GIT 3e14a2867d8ccf555fe6e318eac0f8200399fe1c git+ssh://master.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git#drm-mm

commit 
Author: Michel Daenzer <michel@tungstengraphics.com>
Date:   Fri Sep 22 04:26:35 2006 +1000

    drm: Use register writes instead of BITBLT_MULTI packets for buffer swap blits
    
    This takes up two more ring buffer entries per rectangle blitted but makes sure
    the blit is performed top to bottom, reducing the likelyhood of tearing.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 54a56ac583ac66f3f4bc2c4cc3ef9b0676770742
Author: Dave Airlie <airlied@linux.ie>
Date:   Fri Sep 22 04:25:09 2006 +1000

    drm: use radeon specific names for radeon flags
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 2f02cc3fb8960754a2a5df6a33f53528e0d830be
Author: Eric Anholt <eric@anholt.net>
Date:   Fri Sep 22 04:19:34 2006 +1000

    drm: add device/vendor id to drm_device_t for compat with FreeBSD drivers
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit e08870c87ab5b0c0c3cb05d0d0041240736493e4
Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Date:   Fri Sep 22 04:18:37 2006 +1000

    drm: allow multiple addMaps with the same 32-bit map offsset.
    
    Reported on -mm kernels.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 214ff13d9ebbba7940f29bc89669f85f12533083
Author: Michel Daenzer <michel@tungstengraphics.com>
Date:   Fri Sep 22 04:12:11 2006 +1000

    drm: fd.o Bug #7595: Avoid u32 overflows in radeon_check_and_fixup_offset().
    
    The overflows could cause valid offsets to get rejected under some
    circumstances, e.g. when the framebuffer resides at the very end of the card's
    address space.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 47cc140931cc03076014fdbfdd512d6dd9d74d34
Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Date:   Fri Sep 22 04:04:18 2006 +1000

    drm: Fix hashtab implementation leaking illegal error codes to user space.
    
    reported by Dave Airlie
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 9b1a51b69c89028f18277e235533c160e7506ebb
Author: Dave Airlie <airlied@linux.ie>
Date:   Fri Sep 22 03:37:19 2006 +1000

    drm: domain changes broke ppc r200
    
    Freedesktop.org bug #8246
    
    The domain changes regressed on PPC, go back to just using 0,
    as X.org's domain support is crap
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 1f27ce6ab7ad7abf014ef7f181d494cf1107f9db
Author: Dave Airlie <airlied@linux.ie>
Date:   Sun Aug 27 11:11:14 2006 +1000

    drm: fixup setversion return codes..
    
    Frederik Deweerdt <deweerdt@free.fr> noticed some badness in setversion
    returns, however just making it work, breaks things... this code is hairy
    with backwards compat...
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 46acbf13fb280e69c5cafe7c837d5a27c6e380c3
Author: Dave Airlie <airlied@linux.ie>
Date:   Sun Aug 27 11:09:46 2006 +1000

    drm: fixup i915 error codes
    
    Frederik Deweerdt <deweerdt@free.fr> pointed this out, I fixed a missing
    DRM error wrapper also.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit b15ec36806ce3b89a2fddce958de9370efb249da
Author: Dave Airlie <airlied@linux.ie>
Date:   Sat Aug 19 17:43:52 2006 +1000

    drm: realign sosme radeon code with drm git tree
    
    this applies some minor cleanups for the radeon driver, to use the
    3D flush and reset the AGP flags on X recycle
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit d40c8533a5b8ca1887f81ae1c81136f3c40a8488
Author: Dave Airlie <airlied@linux.ie>
Date:   Sat Aug 19 17:40:50 2006 +1000

    drm: realign via driver with drm git tree
    
    This just realigns some code/whitespace between the kernel and main tree
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 1f4eccfdb2a5f8b2751aea8cf2d6b00401c156e0
Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Date:   Fri Aug 18 16:37:10 2006 +1000

    drm: remove hash tables on drm exit
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit fb41e54be4bad6f64d343d051d699efde3c92e2c
Author: Adrian Bunk <bunk@stusta.de>
Date:   Wed Aug 16 11:55:18 2006 +1000

    drm: cleanups
    
    This patch contains the following cleanups:
    - make 3 needlessly global functions static
    - sis_mm.c: fix compile warnings with CONFIG_FB_SIS=y
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit c7aed1790254aed286b7bfb51167c2676df86f4b
Author: Denis Vlasenko <vda.linux@googlemail.com>
Date:   Wed Aug 16 11:54:07 2006 +1000

    drm: i810_dma.c: fix pointer arithmetic for 64-bit target
    
    First warning result from open-coded PTR_ERR,
    the rest is caused by code like this:
    
    *(u32 *) ((u32) buf_priv->kernel_virtual + used)
    
    I've also fixed a missing PTR_ERR in i830_dma.c
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 0a0c721dc5d0de011e5d363cd454c60c66ca00ec
Author: Thomas Hellstrom <thomas@tungstengraphics.com>
Date:   Wed Aug 16 09:21:56 2006 +1000

    drm: avoid kernel oops in some error paths calling drm_lastclose
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit bd5af0781aed12b9707d238c17cf55d46f9bf98d
Author: Chuck Short <zulcss@gmail.com>
Date:   Wed Aug 16 09:17:53 2006 +1000

    drm: allow detection of new VIA chipsets
    
    Update pci ids.
    
    patch location:
    http://www.kernel.org/git/?p=linux/kernel/git/bcollins/ubuntu-dapper.git;a=c
    ommitdiff;h=5195a64a27550a279b2ecaf400066a3823f2d053
    
    Signed-off-by: Chuck Short <zulcss@gmail.com>
    Signed-off-by: Ben Collins <bcollins@ubuntu.com>
    Signed-off-by: Andrew Morton <akpm@osdl.org>
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 78eca43d0391f59c3b1505bb7bd38ff45b650aab
Author: Andrew Morton <akpm@osdl.org>
Date:   Wed Aug 16 09:15:51 2006 +1000

    drm: fix i965 build bug
    
    Signed-off-by: Andrew Morton <akpm@osdl.org>
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit a1d0fcf5a1cf56ae4711c7e0f857832724a67e8b
Author: Andrew Morton <akpm@osdl.org>
Date:   Mon Aug 14 11:35:15 2006 +1000

    drm: remove FALSE/TRUE that snuck in with simple memory manager changes.
    
    Thanks to Andrew Morton for pointing these out, I've fixed a few his patch
    missed.
    
    Signed-off-by: Andrew Morton <akpm@osdl.org>
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit c29b669caae4ed1630ef479e54bdde126a0378ec
Author: Alan Hourihane <alanh@tungstengraphics.com>
Date:   Sat Aug 12 16:29:24 2006 +1000

    drm: Add support for Intel i965G chipsets.
    
    This is a patch prepared by Guangdeng Liao based off of Tungsten Graphics's
    final code drop.
    
    From: Alan Hourihane <alanh@tungstengraphics.com>
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit d000b486ea1633380e6224c03e94227db46567ad
Author: Dave Airlie <airlied@linux.ie>
Date:   Sat Aug 12 16:03:52 2006 +1000

    drm: add better explanation for i830/i915
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit c2604ce05853939cf712ebc5acc0da4011289346
Author: Dave Airlie <airlied@linux.ie>
Date:   Sat Aug 12 16:03:26 2006 +1000

    drm: remove a tab that snuck in
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 572225bedf8e39b5dd7cc687a51015edbb738401
Author: Dave Airlie <airlied@linux.ie>
Date:   Tue Aug 8 22:17:02 2006 +1000

    drm: fix return value in auth function
    
    This just fixes up the return value in the drm_auth:remove_magic
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 7981bf7d494a6c4d45e22c54b0da887e5a67e705
Author: Thomas Hellstrom <thomas@tungstengraphics.com>
Date:   Tue Aug 8 21:34:46 2006 +1000

    drm: SiS 315 Awareness.
    
    Add support for the SiS 315 to the DRM.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 8d153f7107ff2c5d6e32053ae377c961187ab6b9
Author: Thomas Hellstrom <thomas@tungstengraphics.com>
Date:   Mon Aug 7 22:36:47 2006 +1000

    drm: update user token hashing and map handles
    
    Keep hashed user tokens, with the following changes:
    32-bit physical device addresses are mapped directly to user-tokens. No
        duplicate maps are allowed, and the addresses are assumed to be outside
        of the range 0x10000000 through 0x30000000. The user-token is identical
        to the 32-bit physical start-address of the map.
    64-bit physical device addressed are mapped to user-tokens in the range
    0x10000000 to 0x30000000 with page-size increments. The user_token should
        not be interpreted as an address.
    Other map types, like upcoming TTM maps are mapped to user-tokens in the
        range
    0x10000000 to 0x30000000 with page-size increments. The user_token should
        not be interpreted as an address.
    
    Implement hashed map lookups.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 8669cbc5e651bf4effa20e8c244a5a7d67da6fe9
Author: Thomas Hellstrom <thomas@tungstengraphics.com>
Date:   Mon Aug 7 22:22:10 2006 +1000

    drm: move drm authentication to new generic hash table.
    
    Fix drm_remove_magic potential memory leak / corruption. Move drm
    authentication token hashing to new generic hash table implementation.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 3d45dbd611d1441d667b06acced9fbad3c8fcb1b
Author: Dave Airlie <airlied@linux.ie>
Date:   Mon Aug 7 22:06:04 2006 +1000

    drm: Add the P4VM800PRO (?) PCI ID.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit ce65a44de07f73ceda1749812b75086b7add408d
Author: Thomas Hellstrom <thomas@tungstengraphics.com>
Date:   Mon Aug 7 22:03:22 2006 +1000

    drm: add drm simple memory manager support for SiS and VIA drivers
    
    This add support to the SiS and VIA drivers for the simple memory manager.
    This fixes a lot of problems with the current simple code these drivers used,
    including locking and SMP issues.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 3a1bd924f36da202e480a0e0174b2878c0924a05
Author: Thomas Hellstrom <thomas@tungstengraphics.com>
Date:   Mon Aug 7 21:30:28 2006 +1000

    drm: add simple DRM memory manager, and hash table
    
    This adds the DRM hashtable and simple memory manager implementations from
    Tungsten Graphics, this is NOT the new memory manager, this is a replacement
    for the SIS and VIA memory managers.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit b9b603dd1c99a68e65ad51cda25379441df2e17b
Author: Michel DÃ¤nzer <michel@tungstengraphics.com>
Date:   Mon Aug 7 20:41:53 2006 +1000

    drm: radeon: Use RADEON_RB3D_DSTCACHE_CTLSTAT instead of RADEON_RB2D_DSTCACHE_CTLSTAT.
    
    The latter seems to be a read-only mirror of the former.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit ae1b1a4816ac11075d338af79a239f4c326d675c
Author: Michel DÃ¤nzer <michel@tungstengraphics.com>
Date:   Mon Aug 7 20:37:46 2006 +1000

    drm: radeon: fix up bus mastering when writeback is disabled
    
    When writeback isn't used, actually disable it in the hardware.
    
    Not doing this might waste bus bandwidth or even cause memory corruption or
    system crashes on systems that check bus transfers. No such incident has been
    reported though.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 8624ecbf68e90e5a8124514a0b7f92767fb80a62
Author: Michel DÃ¤nzer <michel@tungstengraphics.com>
Date:   Mon Aug 7 20:33:57 2006 +1000

    drm: radeon: implement RADEON_PARAM_SCRATCH_OFFSET getparam
    
    When this succeeds, userspace can read the scratch register contents from th    mapped writeback page directly.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 9ca941615ee6418cd38c13602960f29c7ac7d973
Author: Michel DÃ¤nzer <michel@tungstengraphics.com>
Date:   Mon Aug 7 20:31:30 2006 +1000

    drm: radeon: add some debug output when getparam is called with unknown
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 7a3f1f216b92724ff822fe3122272b7fd6a58f8c
Author: Thomas Hellstrom <thomas@tungstengraphics.com>
Date:   Mon Aug 7 20:28:29 2006 +1000

    drm: missing mutex unlock
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 332296016ee2e808b362de66bf6bec49c396e5bf
Author: Dave Airlie <airlied@linux.ie>
Date:   Mon Aug 7 20:23:42 2006 +1000

    drm: remove the DRM pci domain
    
    This patch removes the pci_domain from the DRM device structure, and
    gets it via a macro that either asks the platform or does the alpha special
    case. jgarzik asked for this to just use the platform magic, but I've no
    alpha experience and I'd rather not just break it and wait for someone to
    give out.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 242ef0e1e7e5bb7e80c3620c1aa55168819d6fb8
Author: Dave <airlied@linux.ie>
Date:   Tue Jul 18 04:01:01 2006 +1000

    drm: remove local copies of pci bus/slot/func
    
    The drm keeps a local copy of these for little use.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 3d77461ecd7fb92bb888f69478e3518b3c947ce3
Author: Dave Airlie <airlied@linux.ie>
Date:   Mon Aug 7 20:07:43 2006 +1000

    drm: cleanup old compat code and DRM fns from Linux only code
    
    This patch removes some of the old compatibility macros from the DRM,
    and removes use of DRM wrappers from Linux specific code.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>
 drivers/char/drm/Kconfig        |    9 -
 drivers/char/drm/Makefile       |    6 
 drivers/char/drm/drmP.h         |   68 ++++-
 drivers/char/drm/drm_auth.c     |   64 +----
 drivers/char/drm/drm_bufs.c     |   74 +++---
 drivers/char/drm/drm_drv.c      |   12 +
 drivers/char/drm/drm_fops.c     |   10 -
 drivers/char/drm/drm_hashtab.c  |  190 +++++++++++++++
 drivers/char/drm/drm_hashtab.h  |   67 +++++
 drivers/char/drm/drm_ioc32.c    |    2 
 drivers/char/drm/drm_ioctl.c    |   34 ++-
 drivers/char/drm/drm_irq.c      |   12 +
 drivers/char/drm/drm_mm.c       |  201 ++++++++++++++++
 drivers/char/drm/drm_pciids.h   |  187 ++++++++------
 drivers/char/drm/drm_proc.c     |    2 
 drivers/char/drm/drm_sman.c     |  352 +++++++++++++++++++++++++++
 drivers/char/drm/drm_sman.h     |  176 ++++++++++++++
 drivers/char/drm/drm_stub.c     |   12 -
 drivers/char/drm/drm_vm.c       |   45 +--
 drivers/char/drm/i810_dma.c     |   10 -
 drivers/char/drm/i830_dma.c     |    4 
 drivers/char/drm/i915_dma.c     |   45 +++
 drivers/char/drm/i915_drm.h     |    6 
 drivers/char/drm/i915_drv.h     |   10 -
 drivers/char/drm/i915_irq.c     |   16 +
 drivers/char/drm/radeon_cp.c    |   72 +++---
 drivers/char/drm/radeon_drv.c   |    2 
 drivers/char/drm/radeon_drv.h   |   36 ++-
 drivers/char/drm/radeon_state.c |   48 ++--
 drivers/char/drm/sis_drv.c      |   39 +++
 drivers/char/drm/sis_drv.h      |   34 ++-
 drivers/char/drm/sis_ds.c       |  299 -----------------------
 drivers/char/drm/sis_ds.h       |  146 -----------
 drivers/char/drm/sis_mm.c       |  504 +++++++++++++++++----------------------
 drivers/char/drm/via_dmablit.c  |   68 +++--
 drivers/char/drm/via_drm.h      |    8 +
 drivers/char/drm/via_drv.c      |    3 
 drivers/char/drm/via_drv.h      |   16 +
 drivers/char/drm/via_ds.c       |  273 ---------------------
 drivers/char/drm/via_ds.h       |  104 --------
 drivers/char/drm/via_map.c      |    9 +
 drivers/char/drm/via_mm.c       |  375 +++++++++--------------------
 42 files changed, 1878 insertions(+), 1772 deletions(-)

diff --git a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig
index 5278c38..ef833a1 100644
--- a/drivers/char/drm/Kconfig
+++ b/drivers/char/drm/Kconfig
@@ -60,7 +60,9 @@ config DRM_I830
 	  Choose this option if you have a system that has Intel 830M, 845G,
 	  852GM, 855GM or 865G integrated graphics.  If M is selected, the
 	  module will be called i830.  AGP support is required for this driver
-	  to work. This driver will eventually be replaced by the i915 one.
+	  to work. This driver is used by the older X releases X.org 6.7 and
+	  XFree86 4.3. If unsure, build this and i915 as modules and the X server
+	  will load the correct one.
 
 config DRM_I915
 	tristate "i915 driver"
@@ -68,8 +70,9 @@ config DRM_I915
 	  Choose this option if you have a system that has Intel 830M, 845G,
 	  852GM, 855GM 865G or 915G integrated graphics.  If M is selected, the
 	  module will be called i915.  AGP support is required for this driver
-	  to work. This driver will eventually replace the I830 driver, when
-	  later release of X start to use the new DDX and DRI.
+	  to work. This driver is used by the Intel driver in X.org 6.8 and
+	  XFree86 4.4 and above. If unsure, build this and i830 as modules and 
+	  the X server will load the correct one.
 	
 endchoice
 
diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile
index 9d180c4..3ad0f64 100644
--- a/drivers/char/drm/Makefile
+++ b/drivers/char/drm/Makefile
@@ -6,7 +6,7 @@ drm-objs    :=	drm_auth.o drm_bufs.o drm
 		drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \
 		drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
 		drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
-		drm_sysfs.o
+		drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o
 
 tdfx-objs   := tdfx_drv.o
 r128-objs   := r128_drv.o r128_cce.o r128_state.o r128_irq.o
@@ -16,9 +16,9 @@ i830-objs   := i830_drv.o i830_dma.o i83
 i915-objs   := i915_drv.o i915_dma.o i915_irq.o i915_mem.o
 radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o
 ffb-objs    := ffb_drv.o ffb_context.o
-sis-objs    := sis_drv.o sis_ds.o sis_mm.o
+sis-objs    := sis_drv.o sis_mm.o
 savage-objs := savage_drv.o savage_bci.o savage_state.o
-via-objs    := via_irq.o via_drv.o via_ds.o via_map.o via_mm.o via_dma.o via_verifier.o via_video.o via_dmablit.o
+via-objs    := via_irq.o via_drv.o via_map.o via_mm.o via_dma.o via_verifier.o via_video.o via_dmablit.o
 
 ifeq ($(CONFIG_COMPAT),y)
 drm-objs    += drm_ioc32.o
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index d2a5618..7690a59 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -79,6 +79,7 @@ #define __OS_HAS_AGP (defined(CONFIG_AGP
 #define __OS_HAS_MTRR (defined(CONFIG_MTRR))
 
 #include "drm_os_linux.h"
+#include "drm_hashtab.h"
 
 /***********************************************************************/
 /** \name DRM template customization defaults */
@@ -104,7 +105,7 @@ #define DRIVER_FB_DMA      0x400
 #define DRM_DEBUG_CODE 2	  /**< Include debugging code if > 1, then
 				     also include looping detection. */
 
-#define DRM_HASH_SIZE	      16 /**< Size of key hash table. Must be power of 2. */
+#define DRM_MAGIC_HASH_ORDER  4  /**< Size of key hash table. Must be power of 2. */
 #define DRM_KERNEL_CONTEXT    0	 /**< Change drm_resctx if changed */
 #define DRM_RESERVED_CONTEXTS 1	 /**< Change drm_resctx if changed */
 #define DRM_LOOPING_LIMIT     5000000
@@ -134,19 +135,12 @@ #define DRM_MEM_BOUNDAGP  17
 #define DRM_MEM_CTXBITMAP 18
 #define DRM_MEM_STUB      19
 #define DRM_MEM_SGLISTS   20
-#define DRM_MEM_CTXLIST  21
+#define DRM_MEM_CTXLIST   21
+#define DRM_MEM_MM        22
+#define DRM_MEM_HASHTAB   23
 
 #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)
-
-/*@}*/
-
-/***********************************************************************/
-/** \name Backward compatibility section */
-/*@{*/
-
-#define DRM_RPR_ARG(vma) vma,
-
-#define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT)
+#define DRM_MAP_HASH_OFFSET 0x10000000
 
 /*@}*/
 
@@ -211,8 +205,6 @@ #define DRM_PROC_PRINT_RET(ret, fmt, arg
 /*@{*/
 
 #define DRM_ARRAY_SIZE(x) ARRAY_SIZE(x)
-#define DRM_MIN(a,b) min(a,b)
-#define DRM_MAX(a,b) max(a,b)
 
 #define DRM_LEFTCOUNT(x) (((x)->rp + (x)->count - (x)->wp) % ((x)->count + 1))
 #define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x))
@@ -286,7 +278,8 @@ typedef struct drm_devstate {
 } drm_devstate_t;
 
 typedef struct drm_magic_entry {
-	drm_magic_t magic;
+	drm_hash_item_t hash_item;
+	struct list_head head;
 	struct drm_file *priv;
 	struct drm_magic_entry *next;
 } drm_magic_entry_t;
@@ -493,6 +486,7 @@ typedef struct drm_sigdata {
  */
 typedef struct drm_map_list {
 	struct list_head head;		/**< list head */
+	drm_hash_item_t hash;
 	drm_map_t *map;			/**< mapping */
 	unsigned int user_token;
 } drm_map_list_t;
@@ -527,6 +521,22 @@ typedef struct ati_pcigart_info {
 	drm_local_map_t mapping;
 } drm_ati_pcigart_info;
 
+/*
+ * Generic memory manager structs
+ */
+typedef struct drm_mm_node {
+	struct list_head fl_entry;
+	struct list_head ml_entry;
+	int free;
+	unsigned long start;
+	unsigned long size;
+	void *private;
+} drm_mm_node_t;
+
+typedef struct drm_mm {
+	drm_mm_node_t root_node;
+} drm_mm_t;
+
 /**
  * DRM driver structure. This structure represent the common code for
  * a family of cards. There will one drm_device for each card present
@@ -646,13 +656,15 @@ typedef struct drm_device {
 	/*@{ */
 	drm_file_t *file_first;		/**< file list head */
 	drm_file_t *file_last;		/**< file list tail */
-	drm_magic_head_t magiclist[DRM_HASH_SIZE];	/**< magic hash table */
+	drm_open_hash_t magiclist;	/**< magic hash table */
+	struct list_head magicfree;
 	/*@} */
 
 	/** \name Memory management */
 	/*@{ */
 	drm_map_list_t *maplist;	/**< Linked list of regions */
 	int map_count;			/**< Number of mappable regions */
+	drm_open_hash_t map_hash;	/**< User token hash table for maps */
 
 	/** \name Context handle management */
 	/*@{ */
@@ -711,10 +723,8 @@ typedef struct drm_device {
 	drm_agp_head_t *agp;	/**< AGP data */
 
 	struct pci_dev *pdev;		/**< PCI device structure */
-	int pci_domain;			/**< PCI bus domain number */
-	int pci_bus;			/**< PCI bus number */
-	int pci_slot;			/**< PCI slot number */
-	int pci_func;			/**< PCI function number */
+	int pci_vendor;			/**< PCI vendor id */
+	int pci_device;			/**< PCI device id */
 #ifdef __alpha__
 	struct pci_controller *hose;
 #endif
@@ -736,6 +746,12 @@ static __inline__ int drm_core_check_fea
 	return ((dev->driver->driver_features & feature) ? 1 : 0);
 }
 
+#ifdef __alpha__
+#define drm_get_pci_domain(dev) dev->hose->bus->number
+#else
+#define drm_get_pci_domain(dev) 0
+#endif
+
 #if __OS_HAS_AGP
 static inline int drm_core_has_AGP(struct drm_device *dev)
 {
@@ -1011,6 +1027,18 @@ extern struct class_device *drm_sysfs_de
 						 drm_head_t *head);
 extern void drm_sysfs_device_remove(struct class_device *class_dev);
 
+/*
+ * Basic memory manager support (drm_mm.c)
+ */
+extern drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
+				       unsigned long size,
+				       unsigned alignment);
+extern void drm_mm_put_block(drm_mm_t *mm, drm_mm_node_t *cur);
+extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size,
+					 unsigned alignment, int best_match);
+extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size);
+extern void drm_mm_takedown(drm_mm_t *mm);
+
 /* Inline replacements for DRM_IOREMAP macros */
 static __inline__ void drm_core_ioremap(struct drm_map *map,
 					struct drm_device *dev)
diff --git a/drivers/char/drm/drm_auth.c b/drivers/char/drm/drm_auth.c
index 2a37586..c7b19d3 100644
--- a/drivers/char/drm/drm_auth.c
+++ b/drivers/char/drm/drm_auth.c
@@ -36,20 +36,6 @@
 #include "drmP.h"
 
 /**
- * Generate a hash key from a magic.
- *
- * \param magic magic.
- * \return hash key.
- *
- * The key is the modulus of the hash table size, #DRM_HASH_SIZE, which must be
- * a power of 2.
- */
-static int drm_hash_magic(drm_magic_t magic)
-{
-	return magic & (DRM_HASH_SIZE - 1);
-}
-
-/**
  * Find the file with the given magic number.
  *
  * \param dev DRM device.
@@ -63,14 +49,12 @@ static drm_file_t *drm_find_file(drm_dev
 {
 	drm_file_t *retval = NULL;
 	drm_magic_entry_t *pt;
-	int hash = drm_hash_magic(magic);
+	drm_hash_item_t *hash;
 
 	mutex_lock(&dev->struct_mutex);
-	for (pt = dev->magiclist[hash].head; pt; pt = pt->next) {
-		if (pt->magic == magic) {
-			retval = pt->priv;
-			break;
-		}
+	if (!drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) {
+		pt = drm_hash_entry(hash, drm_magic_entry_t, hash_item);
+		retval = pt->priv;
 	}
 	mutex_unlock(&dev->struct_mutex);
 	return retval;
@@ -90,28 +74,20 @@ static drm_file_t *drm_find_file(drm_dev
 static int drm_add_magic(drm_device_t * dev, drm_file_t * priv,
 			 drm_magic_t magic)
 {
-	int hash;
 	drm_magic_entry_t *entry;
 
 	DRM_DEBUG("%d\n", magic);
 
-	hash = drm_hash_magic(magic);
 	entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC);
 	if (!entry)
 		return -ENOMEM;
 	memset(entry, 0, sizeof(*entry));
-	entry->magic = magic;
 	entry->priv = priv;
-	entry->next = NULL;
 
+	entry->hash_item.key = (unsigned long)magic;
 	mutex_lock(&dev->struct_mutex);
-	if (dev->magiclist[hash].tail) {
-		dev->magiclist[hash].tail->next = entry;
-		dev->magiclist[hash].tail = entry;
-	} else {
-		dev->magiclist[hash].head = entry;
-		dev->magiclist[hash].tail = entry;
-	}
+	drm_ht_insert_item(&dev->magiclist, &entry->hash_item);
+	list_add_tail(&entry->head, &dev->magicfree);
 	mutex_unlock(&dev->struct_mutex);
 
 	return 0;
@@ -128,34 +104,24 @@ static int drm_add_magic(drm_device_t * 
  */
 static int drm_remove_magic(drm_device_t * dev, drm_magic_t magic)
 {
-	drm_magic_entry_t *prev = NULL;
 	drm_magic_entry_t *pt;
-	int hash;
+	drm_hash_item_t *hash;
 
 	DRM_DEBUG("%d\n", magic);
-	hash = drm_hash_magic(magic);
 
 	mutex_lock(&dev->struct_mutex);
-	for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) {
-		if (pt->magic == magic) {
-			if (dev->magiclist[hash].head == pt) {
-				dev->magiclist[hash].head = pt->next;
-			}
-			if (dev->magiclist[hash].tail == pt) {
-				dev->magiclist[hash].tail = prev;
-			}
-			if (prev) {
-				prev->next = pt->next;
-			}
-			mutex_unlock(&dev->struct_mutex);
-			return 0;
-		}
+	if (drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) {
+		mutex_unlock(&dev->struct_mutex);
+		return -EINVAL;
 	}
+	pt = drm_hash_entry(hash, drm_magic_entry_t, hash_item);
+	drm_ht_remove_item(&dev->magiclist, hash);
+	list_del(&pt->head);
 	mutex_unlock(&dev->struct_mutex);
 
 	drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
 
-	return -EINVAL;
+	return 0;
 }
 
 /**
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index 006b06d..029baea 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -65,43 +65,29 @@ static drm_map_list_t *drm_find_matching
 	return NULL;
 }
 
-/*
- * Used to allocate 32-bit handles for mappings.
- */
-#define START_RANGE 0x10000000
-#define END_RANGE 0x40000000
-
-#ifdef _LP64
-static __inline__ unsigned int HandleID(unsigned long lhandle,
-					drm_device_t *dev)
+static int drm_map_handle(drm_device_t *dev, drm_hash_item_t *hash,
+			  unsigned long user_token, int hashed_handle)
 {
-	static unsigned int map32_handle = START_RANGE;
-	unsigned int hash;
-
-	if (lhandle & 0xffffffff00000000) {
-		hash = map32_handle;
-		map32_handle += PAGE_SIZE;
-		if (map32_handle > END_RANGE)
-			map32_handle = START_RANGE;
-	} else
-		hash = lhandle;
-
-	while (1) {
-		drm_map_list_t *_entry;
-		list_for_each_entry(_entry, &dev->maplist->head, head) {
-			if (_entry->user_token == hash)
-				break;
-		}
-		if (&_entry->head == &dev->maplist->head)
-			return hash;
+	int use_hashed_handle;
+#if (BITS_PER_LONG == 64)
+	use_hashed_handle = ((user_token & 0xFFFFFFFF00000000UL) || hashed_handle);
+#elif (BITS_PER_LONG == 32)
+	use_hashed_handle = hashed_handle;
+#else
+#error Unsupported long size. Neither 64 nor 32 bits.
+#endif
 
-		hash += PAGE_SIZE;
-		map32_handle += PAGE_SIZE;
+	if (!use_hashed_handle) {
+		int ret;
+		hash->key = user_token;
+		ret = drm_ht_insert_item(&dev->map_hash, hash);
+		if (ret != -EINVAL)
+			return ret;
 	}
+	return drm_ht_just_insert_please(&dev->map_hash, hash,
+					 user_token, 32 - PAGE_SHIFT - 3,
+					 PAGE_SHIFT, DRM_MAP_HASH_OFFSET);
 }
-#else
-# define HandleID(x,dev) (unsigned int)(x)
-#endif
 
 /**
  * Ioctl to specify a range of memory that is available for mapping by a non-root process.
@@ -123,6 +109,8 @@ static int drm_addmap_core(drm_device_t 
 	drm_map_t *map;
 	drm_map_list_t *list;
 	drm_dma_handle_t *dmah;
+	unsigned long user_token;
+	int ret;
 
 	map = drm_alloc(sizeof(*map), DRM_MEM_MAPS);
 	if (!map)
@@ -257,11 +245,20 @@ #endif
 
 	mutex_lock(&dev->struct_mutex);
 	list_add(&list->head, &dev->maplist->head);
+
 	/* Assign a 32-bit handle */
 	/* We do it here so that dev->struct_mutex protects the increment */
-	list->user_token = HandleID(map->type == _DRM_SHM
-				    ? (unsigned long)map->handle
-				    : map->offset, dev);
+	user_token = (map->type == _DRM_SHM) ? (unsigned long)map->handle :
+		map->offset;
+	ret = drm_map_handle(dev, &list->hash, user_token, 0);
+	if (ret) {
+		drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+		drm_free(list, sizeof(*list), DRM_MEM_MAPS);
+		mutex_unlock(&dev->struct_mutex);
+		return ret;
+	}
+
+	list->user_token = list->hash.key;
 	mutex_unlock(&dev->struct_mutex);
 
 	*maplist = list;
@@ -346,6 +343,7 @@ int drm_rmmap_locked(drm_device_t *dev, 
 
 		if (r_list->map == map) {
 			list_del(list);
+			drm_ht_remove_key(&dev->map_hash, r_list->user_token);
 			drm_free(list, sizeof(*list), DRM_MEM_MAPS);
 			break;
 		}
@@ -441,8 +439,10 @@ int drm_rmmap_ioctl(struct inode *inode,
 		return -EINVAL;
 	}
 
-	if (!map)
+	if (!map) {
+		mutex_unlock(&dev->struct_mutex);
 		return -EINVAL;
+	}
 
 	/* Register and framebuffer maps are permanent */
 	if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) {
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c
index 3c0b882..b366c5b 100644
--- a/drivers/char/drm/drm_drv.c
+++ b/drivers/char/drm/drm_drv.c
@@ -118,7 +118,7 @@ #endif
 	[DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0},
 };
 
-#define DRIVER_IOCTL_COUNT	DRM_ARRAY_SIZE( drm_ioctls )
+#define DRIVER_IOCTL_COUNT	ARRAY_SIZE( drm_ioctls )
 
 /**
  * Take down the DRM device.
@@ -155,12 +155,13 @@ int drm_lastclose(drm_device_t * dev)
 	del_timer(&dev->timer);
 
 	/* Clear pid list */
-	for (i = 0; i < DRM_HASH_SIZE; i++) {
-		for (pt = dev->magiclist[i].head; pt; pt = next) {
-			next = pt->next;
+	if (dev->magicfree.next) {
+		list_for_each_entry_safe(pt, next, &dev->magicfree, head) {
+			list_del(&pt->head);
+			drm_ht_remove_item(&dev->magiclist, &pt->hash_item);
 			drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
 		}
-		dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
+		drm_ht_remove(&dev->magiclist);
 	}
 
 	/* Clear AGP information */
@@ -299,6 +300,7 @@ static void drm_cleanup(drm_device_t * d
 	if (dev->maplist) {
 		drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
 		dev->maplist = NULL;
+		drm_ht_remove(&dev->map_hash);
 	}
 
 	drm_ctxbitmap_cleanup(dev);
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c
index b7f7951..898f47d 100644
--- a/drivers/char/drm/drm_fops.c
+++ b/drivers/char/drm/drm_fops.c
@@ -53,6 +53,8 @@ static int drm_setup(drm_device_t * dev)
 			return ret;
 	}
 
+	dev->magicfree.next = NULL;
+
 	/* prebuild the SAREA */
 	i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM, _DRM_CONTAINS_LOCK, &map);
 	if (i != 0)
@@ -69,13 +71,11 @@ static int drm_setup(drm_device_t * dev)
 			return i;
 	}
 
-	for (i = 0; i < DRM_ARRAY_SIZE(dev->counts); i++)
+	for (i = 0; i < ARRAY_SIZE(dev->counts); i++)
 		atomic_set(&dev->counts[i], 0);
 
-	for (i = 0; i < DRM_HASH_SIZE; i++) {
-		dev->magiclist[i].head = NULL;
-		dev->magiclist[i].tail = NULL;
-	}
+	drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER);
+	INIT_LIST_HEAD(&dev->magicfree);
 
 	dev->ctxlist = drm_alloc(sizeof(*dev->ctxlist), DRM_MEM_CTXLIST);
 	if (dev->ctxlist == NULL)
diff --git a/drivers/char/drm/drm_hashtab.c b/drivers/char/drm/drm_hashtab.c
new file mode 100644
index 0000000..a0b2d68
--- /dev/null
+++ b/drivers/char/drm/drm_hashtab.c
@@ -0,0 +1,190 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ **************************************************************************/
+/*
+ * Simple open hash tab implementation.
+ *
+ * Authors:
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#include "drmP.h"
+#include "drm_hashtab.h"
+#include <linux/hash.h>
+
+int drm_ht_create(drm_open_hash_t *ht, unsigned int order)
+{
+	unsigned int i;
+
+	ht->size = 1 << order;
+	ht->order = order;
+	ht->fill = 0;
+	ht->table = vmalloc(ht->size*sizeof(*ht->table));
+	if (!ht->table) {
+		DRM_ERROR("Out of memory for hash table\n");
+		return -ENOMEM;
+	}
+	for (i=0; i< ht->size; ++i) {
+		INIT_HLIST_HEAD(&ht->table[i]);
+	}
+	return 0;
+}
+
+void drm_ht_verbose_list(drm_open_hash_t *ht, unsigned long key)
+{
+	drm_hash_item_t *entry;
+	struct hlist_head *h_list;
+	struct hlist_node *list;
+	unsigned int hashed_key;
+	int count = 0;
+
+	hashed_key = hash_long(key, ht->order);
+	DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key);
+	h_list = &ht->table[hashed_key];
+	hlist_for_each(list, h_list) {
+		entry = hlist_entry(list, drm_hash_item_t, head);
+		DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key);
+	}
+}
+
+static struct hlist_node *drm_ht_find_key(drm_open_hash_t *ht, 
+					  unsigned long key)
+{
+	drm_hash_item_t *entry;
+	struct hlist_head *h_list;
+	struct hlist_node *list;
+	unsigned int hashed_key;
+
+	hashed_key = hash_long(key, ht->order);
+	h_list = &ht->table[hashed_key];
+	hlist_for_each(list, h_list) {
+		entry = hlist_entry(list, drm_hash_item_t, head);
+		if (entry->key == key)
+			return list;
+		if (entry->key > key)
+			break;
+	}
+	return NULL;
+}
+
+
+int drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item)
+{
+	drm_hash_item_t *entry;
+	struct hlist_head *h_list;
+	struct hlist_node *list, *parent;
+	unsigned int hashed_key;
+	unsigned long key = item->key;
+
+	hashed_key = hash_long(key, ht->order);
+	h_list = &ht->table[hashed_key];
+	parent = NULL;
+	hlist_for_each(list, h_list) {
+		entry = hlist_entry(list, drm_hash_item_t, head);
+		if (entry->key == key)
+			return -EINVAL;
+		if (entry->key > key)
+			break;
+		parent = list;
+	}
+	if (parent) {
+		hlist_add_after(parent, &item->head);
+	} else {
+		hlist_add_head(&item->head, h_list);
+	}
+	return 0;
+}
+
+/*
+ * Just insert an item and return any "bits" bit key that hasn't been 
+ * used before.
+ */
+int drm_ht_just_insert_please(drm_open_hash_t *ht, drm_hash_item_t *item,
+			      unsigned long seed, int bits, int shift,
+			      unsigned long add)
+{
+	int ret;
+	unsigned long mask = (1 << bits) - 1;
+	unsigned long first, unshifted_key;
+
+	unshifted_key = hash_long(seed, bits);
+	first = unshifted_key;
+	do {
+		item->key = (unshifted_key << shift) + add;
+		ret = drm_ht_insert_item(ht, item);
+		if (ret)
+			unshifted_key = (unshifted_key + 1) & mask;
+	} while(ret && (unshifted_key != first));
+
+	if (ret) {
+		DRM_ERROR("Available key bit space exhausted\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int drm_ht_find_item(drm_open_hash_t *ht, unsigned long key,
+		     drm_hash_item_t **item)
+{
+	struct hlist_node *list;
+
+	list = drm_ht_find_key(ht, key);
+	if (!list)
+		return -EINVAL;
+
+	*item = hlist_entry(list, drm_hash_item_t, head);
+	return 0;
+}
+
+int drm_ht_remove_key(drm_open_hash_t *ht, unsigned long key)
+{
+	struct hlist_node *list;
+
+	list = drm_ht_find_key(ht, key);
+	if (list) {
+		hlist_del_init(list);
+		ht->fill--;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+int drm_ht_remove_item(drm_open_hash_t *ht, drm_hash_item_t *item)
+{
+	hlist_del_init(&item->head);
+	ht->fill--;
+	return 0;
+}
+
+void drm_ht_remove(drm_open_hash_t *ht)
+{
+	if (ht->table) {
+		vfree(ht->table);
+		ht->table = NULL;
+	}
+}
+
diff --git a/drivers/char/drm/drm_hashtab.h b/drivers/char/drm/drm_hashtab.h
new file mode 100644
index 0000000..40afec0
--- /dev/null
+++ b/drivers/char/drm/drm_hashtab.h
@@ -0,0 +1,67 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Bismack, ND. USA.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ **************************************************************************/
+/*
+ * Simple open hash tab implementation.
+ *
+ * Authors:
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#ifndef DRM_HASHTAB_H
+#define DRM_HASHTAB_H
+
+#define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member)
+
+typedef struct drm_hash_item{
+	struct hlist_node head;
+	unsigned long key;
+} drm_hash_item_t;
+
+typedef struct drm_open_hash{
+	unsigned int size;
+	unsigned int order;
+	unsigned int fill;
+	struct hlist_head *table;
+} drm_open_hash_t;
+
+
+extern int drm_ht_create(drm_open_hash_t *ht, unsigned int order);
+extern int drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item);
+extern int drm_ht_just_insert_please(drm_open_hash_t *ht, drm_hash_item_t *item,
+				     unsigned long seed, int bits, int shift,
+				     unsigned long add);
+extern int drm_ht_find_item(drm_open_hash_t *ht, unsigned long key, drm_hash_item_t **item);
+
+extern void drm_ht_verbose_list(drm_open_hash_t *ht, unsigned long key);
+extern int drm_ht_remove_key(drm_open_hash_t *ht, unsigned long key);
+extern int drm_ht_remove_item(drm_open_hash_t *ht, drm_hash_item_t *item);
+extern void drm_ht_remove(drm_open_hash_t *ht);
+
+
+#endif
+
diff --git a/drivers/char/drm/drm_ioc32.c b/drivers/char/drm/drm_ioc32.c
index e9e2db1..d4f8745 100644
--- a/drivers/char/drm/drm_ioc32.c
+++ b/drivers/char/drm/drm_ioc32.c
@@ -1051,7 +1051,7 @@ long drm_compat_ioctl(struct file *filp,
 	drm_ioctl_compat_t *fn;
 	int ret;
 
-	if (nr >= DRM_ARRAY_SIZE(drm_compat_ioctls))
+	if (nr >= ARRAY_SIZE(drm_compat_ioctls))
 		return -ENOTTY;
 
 	fn = drm_compat_ioctls[nr];
diff --git a/drivers/char/drm/drm_ioctl.c b/drivers/char/drm/drm_ioctl.c
index 555f323..5658955 100644
--- a/drivers/char/drm/drm_ioctl.c
+++ b/drivers/char/drm/drm_ioctl.c
@@ -127,9 +127,10 @@ int drm_setunique(struct inode *inode, s
 	domain = bus >> 8;
 	bus &= 0xff;
 
-	if ((domain != dev->pci_domain) ||
-	    (bus != dev->pci_bus) ||
-	    (slot != dev->pci_slot) || (func != dev->pci_func))
+	if ((domain != drm_get_pci_domain(dev)) ||
+	    (bus != dev->pdev->bus->number) ||
+	    (slot != PCI_SLOT(dev->pdev->devfn)) ||
+	    (func != PCI_FUNC(dev->pdev->devfn)))
 		return -EINVAL;
 
 	return 0;
@@ -140,15 +141,17 @@ static int drm_set_busid(drm_device_t * 
 	int len;
 
 	if (dev->unique != NULL)
-		return EBUSY;
+		return 0;
 
 	dev->unique_len = 40;
 	dev->unique = drm_alloc(dev->unique_len + 1, DRM_MEM_DRIVER);
 	if (dev->unique == NULL)
-		return ENOMEM;
+		return -ENOMEM;
 
 	len = snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d",
-		 dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func);
+		       drm_get_pci_domain(dev), dev->pdev->bus->number,
+		       PCI_SLOT(dev->pdev->devfn),
+		       PCI_FUNC(dev->pdev->devfn));
 
 	if (len > dev->unique_len)
 		DRM_ERROR("Unique buffer overflowed\n");
@@ -157,7 +160,7 @@ static int drm_set_busid(drm_device_t * 
 	    drm_alloc(strlen(dev->driver->pci_driver.name) + dev->unique_len +
 		      2, DRM_MEM_DRIVER);
 	if (dev->devname == NULL)
-		return ENOMEM;
+		return -ENOMEM;
 
 	sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
 		dev->unique);
@@ -330,27 +333,32 @@ int drm_setversion(DRM_IOCTL_ARGS)
 	drm_set_version_t retv;
 	int if_version;
 	drm_set_version_t __user *argp = (void __user *)data;
+	int ret;
 
-	DRM_COPY_FROM_USER_IOCTL(sv, argp, sizeof(sv));
+	if (copy_from_user(&sv, argp, sizeof(sv)))
+		return -EFAULT;
 
 	retv.drm_di_major = DRM_IF_MAJOR;
 	retv.drm_di_minor = DRM_IF_MINOR;
 	retv.drm_dd_major = dev->driver->major;
 	retv.drm_dd_minor = dev->driver->minor;
 
-	DRM_COPY_TO_USER_IOCTL(argp, retv, sizeof(sv));
+	if (copy_to_user(argp, &retv, sizeof(retv)))
+		return -EFAULT;
 
 	if (sv.drm_di_major != -1) {
 		if (sv.drm_di_major != DRM_IF_MAJOR ||
 		    sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR)
-			return EINVAL;
+			return -EINVAL;
 		if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_di_minor);
-		dev->if_version = DRM_MAX(if_version, dev->if_version);
+		dev->if_version = max(if_version, dev->if_version);
 		if (sv.drm_di_minor >= 1) {
 			/*
 			 * Version 1.1 includes tying of DRM to specific device
 			 */
-			drm_set_busid(dev);
+			ret = drm_set_busid(dev);
+			if (ret)
+				return ret;
 		}
 	}
 
@@ -358,7 +366,7 @@ int drm_setversion(DRM_IOCTL_ARGS)
 		if (sv.drm_dd_major != dev->driver->major ||
 		    sv.drm_dd_minor < 0
 		    || sv.drm_dd_minor > dev->driver->minor)
-			return EINVAL;
+			return -EINVAL;
 
 		if (dev->driver->set_version)
 			dev->driver->set_version(dev, &sv);
diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c
index ebdb718..4553a3a 100644
--- a/drivers/char/drm/drm_irq.c
+++ b/drivers/char/drm/drm_irq.c
@@ -64,9 +64,9 @@ int drm_irq_by_busid(struct inode *inode
 	if (copy_from_user(&p, argp, sizeof(p)))
 		return -EFAULT;
 
-	if ((p.busnum >> 8) != dev->pci_domain ||
-	    (p.busnum & 0xff) != dev->pci_bus ||
-	    p.devnum != dev->pci_slot || p.funcnum != dev->pci_func)
+	if ((p.busnum >> 8) != drm_get_pci_domain(dev) ||
+	    (p.busnum & 0xff) != dev->pdev->bus->number ||
+	    p.devnum != PCI_SLOT(dev->pdev->devfn) || p.funcnum != PCI_FUNC(dev->pdev->devfn))
 		return -EINVAL;
 
 	p.irq = dev->irq;
@@ -255,7 +255,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 	if (!dev->irq)
 		return -EINVAL;
 
-	DRM_COPY_FROM_USER_IOCTL(vblwait, argp, sizeof(vblwait));
+	if (copy_from_user(&vblwait, argp, sizeof(vblwait)))
+		return -EFAULT;
 
 	switch (vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK) {
 	case _DRM_VBLANK_RELATIVE:
@@ -329,7 +330,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 	}
 
       done:
-	DRM_COPY_TO_USER_IOCTL(argp, vblwait, sizeof(vblwait));
+	if (copy_to_user(argp, &vblwait, sizeof(vblwait)))
+		return -EFAULT;
 
 	return ret;
 }
diff --git a/drivers/char/drm/drm_mm.c b/drivers/char/drm/drm_mm.c
new file mode 100644
index 0000000..617526b
--- /dev/null
+++ b/drivers/char/drm/drm_mm.c
@@ -0,0 +1,201 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ **************************************************************************/
+
+/*
+ * Generic simple memory manager implementation. Intended to be used as a base
+ * class implementation for more advanced memory managers.
+ *
+ * Note that the algorithm used is quite simple and there might be substantial
+ * performance gains if a smarter free list is implemented. Currently it is just an
+ * unordered stack of free regions. This could easily be improved if an RB-tree
+ * is used instead. At least if we expect heavy fragmentation.
+ *
+ * Aligned allocations can also see improvement.
+ *
+ * Authors:
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#include "drmP.h"
+
+drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
+				unsigned long size, unsigned alignment)
+{
+
+	drm_mm_node_t *child;
+
+	if (alignment)
+		size += alignment - 1;
+
+	if (parent->size == size) {
+		list_del_init(&parent->fl_entry);
+		parent->free = 0;
+		return parent;
+	} else {
+		child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM);
+		if (!child)
+			return NULL;
+
+		INIT_LIST_HEAD(&child->ml_entry);
+		INIT_LIST_HEAD(&child->fl_entry);
+
+		child->free = 0;
+		child->size = size;
+		child->start = parent->start;
+
+		list_add_tail(&child->ml_entry, &parent->ml_entry);
+		parent->size -= size;
+		parent->start += size;
+	}
+	return child;
+}
+
+/*
+ * Put a block. Merge with the previous and / or next block if they are free.
+ * Otherwise add to the free stack.
+ */
+
+void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur)
+{
+
+	drm_mm_node_t *list_root = &mm->root_node;
+	struct list_head *cur_head = &cur->ml_entry;
+	struct list_head *root_head = &list_root->ml_entry;
+	drm_mm_node_t *prev_node = NULL;
+	drm_mm_node_t *next_node;
+
+	int merged = 0;
+
+	if (cur_head->prev != root_head) {
+		prev_node = list_entry(cur_head->prev, drm_mm_node_t, ml_entry);
+		if (prev_node->free) {
+			prev_node->size += cur->size;
+			merged = 1;
+		}
+	}
+	if (cur_head->next != root_head) {
+		next_node = list_entry(cur_head->next, drm_mm_node_t, ml_entry);
+		if (next_node->free) {
+			if (merged) {
+				prev_node->size += next_node->size;
+				list_del(&next_node->ml_entry);
+				list_del(&next_node->fl_entry);
+				drm_free(next_node, sizeof(*next_node),
+					 DRM_MEM_MM);
+			} else {
+				next_node->size += cur->size;
+				next_node->start = cur->start;
+				merged = 1;
+			}
+		}
+	}
+	if (!merged) {
+		cur->free = 1;
+		list_add(&cur->fl_entry, &list_root->fl_entry);
+	} else {
+		list_del(&cur->ml_entry);
+		drm_free(cur, sizeof(*cur), DRM_MEM_MM);
+	}
+}
+
+drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm,
+				  unsigned long size,
+				  unsigned alignment, int best_match)
+{
+	struct list_head *list;
+	const struct list_head *free_stack = &mm->root_node.fl_entry;
+	drm_mm_node_t *entry;
+	drm_mm_node_t *best;
+	unsigned long best_size;
+
+	best = NULL;
+	best_size = ~0UL;
+
+	if (alignment)
+		size += alignment - 1;
+
+	list_for_each(list, free_stack) {
+		entry = list_entry(list, drm_mm_node_t, fl_entry);
+		if (entry->size >= size) {
+			if (!best_match)
+				return entry;
+			if (size < best_size) {
+				best = entry;
+				best_size = entry->size;
+			}
+		}
+	}
+
+	return best;
+}
+
+int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
+{
+	drm_mm_node_t *child;
+
+	INIT_LIST_HEAD(&mm->root_node.ml_entry);
+	INIT_LIST_HEAD(&mm->root_node.fl_entry);
+	child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM);
+	if (!child)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&child->ml_entry);
+	INIT_LIST_HEAD(&child->fl_entry);
+
+	child->start = start;
+	child->size = size;
+	child->free = 1;
+
+	list_add(&child->fl_entry, &mm->root_node.fl_entry);
+	list_add(&child->ml_entry, &mm->root_node.ml_entry);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(drm_mm_init);
+
+void drm_mm_takedown(drm_mm_t * mm)
+{
+	struct list_head *bnode = mm->root_node.fl_entry.next;
+	drm_mm_node_t *entry;
+
+	entry = list_entry(bnode, drm_mm_node_t, fl_entry);
+
+	if (entry->ml_entry.next != &mm->root_node.ml_entry ||
+	    entry->fl_entry.next != &mm->root_node.fl_entry) {
+		DRM_ERROR("Memory manager not clean. Delaying takedown\n");
+		return;
+	}
+
+	list_del(&entry->fl_entry);
+	list_del(&entry->ml_entry);
+
+	drm_free(entry, sizeof(*entry), DRM_MEM_MM);
+}
+
+EXPORT_SYMBOL(drm_mm_takedown);
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
index b1bb3c7..09398d5 100644
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -3,13 +3,13 @@
    Please contact dri-devel@lists.sf.net to add new cards to this list
 */
 #define radeon_PCI_IDS \
-	{0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x3154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x3E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x3E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP}, \
-	{0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \
+	{0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x3154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x3E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x3E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|RADEON_IS_IGP}, \
+	{0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP}, \
 	{0x1002, 0x4144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
@@ -25,35 +25,35 @@ #define radeon_PCI_IDS \
 	{0x1002, 0x4154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4156, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
-	{0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \
+	{0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP}, \
 	{0x1002, 0x4242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x4243, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
 	{0x1002, 0x4966, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \
 	{0x1002, 0x4967, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \
-	{0x1002, 0x4A48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4A4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4A4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4A4D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4A4E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4A4F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4A50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4A54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4B49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4B4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4B4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4B4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C5A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x4A48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4A4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4A4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4A4D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4A4E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4A4F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4A50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4A54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4B49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4B4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4B4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4B4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4C5A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
 	{0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
@@ -62,16 +62,16 @@ #define radeon_PCI_IDS \
 	{0x1002, 0x4E49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
 	{0x1002, 0x4E4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
 	{0x1002, 0x4E4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
-	{0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4E52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4E53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4E56, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
-	{0x1002, 0x5145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
-	{0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
-	{0x1002, 0x5147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
+	{0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4E52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4E53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4E56, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
+	{0x1002, 0x5145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
+	{0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
+	{0x1002, 0x5147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
 	{0x1002, 0x5148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x514C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x514D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
@@ -80,59 +80,59 @@ #define radeon_PCI_IDS \
 	{0x1002, 0x5159, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
 	{0x1002, 0x515A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
 	{0x1002, 0x515E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
-	{0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x554B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x554C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x554D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x554E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5551, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5554, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x564A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x564B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \
-	{0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x554B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x554C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x554D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x554E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5551, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5554, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x564A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x564B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP}, \
+	{0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
 	{0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
-	{0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5b64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5b65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x5d48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5d49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5d4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5d4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5d4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5d50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5d52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5d57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5e48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5e4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5e4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5e4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5e4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5b64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5b65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x5d48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5d49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5d4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5d4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5d4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5d50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5d52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5d57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5e48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5e4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5e4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5e4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5e4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0, 0, 0}
 
 #define r128_PCI_IDS \
@@ -209,6 +209,7 @@ #define sisdrv_PCI_IDS \
 	{0x1039, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x1039, 0x5300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x1039, 0x6300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x1039, 0x6330, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_CHIP_315}, \
 	{0x1039, 0x7300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0, 0, 0}
 
@@ -227,6 +228,10 @@ #define viadrv_PCI_IDS \
 	{0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x1106, 0x3304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0, 0, 0}
 
 #define i810_PCI_IDS \
@@ -285,5 +290,9 @@ #define i915_PCI_IDS \
 	{0x8086, 0x2592, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x8086, 0x27a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x8086, 0x2972, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x8086, 0x2982, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x8086, 0x2992, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x8086, 0x29a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0, 0, 0}
 
diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c
index 362a270..62d5fe1 100644
--- a/drivers/char/drm/drm_proc.c
+++ b/drivers/char/drm/drm_proc.c
@@ -510,7 +510,7 @@ #endif
 			       vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
 			       vma->vm_flags & VM_LOCKED ? 'l' : '-',
 			       vma->vm_flags & VM_IO ? 'i' : '-',
-			       VM_OFFSET(vma));
+			       vma->vm_pgoff << PAGE_SHIFT);
 
 #if defined(__i386__)
 		pgprot = pgprot_val(vma->vm_page_prot);
diff --git a/drivers/char/drm/drm_sman.c b/drivers/char/drm/drm_sman.c
new file mode 100644
index 0000000..425c823
--- /dev/null
+++ b/drivers/char/drm/drm_sman.c
@@ -0,0 +1,352 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck., ND., USA.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ *
+ **************************************************************************/
+/*
+ * Simple memory manager interface that keeps track on allocate regions on a
+ * per "owner" basis. All regions associated with an "owner" can be released
+ * with a simple call. Typically if the "owner" exists. The owner is any
+ * "unsigned long" identifier. Can typically be a pointer to a file private
+ * struct or a context identifier.
+ *
+ * Authors:
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#include "drm_sman.h"
+
+typedef struct drm_owner_item {
+	drm_hash_item_t owner_hash;
+	struct list_head sman_list;
+	struct list_head mem_blocks;
+} drm_owner_item_t;
+
+void drm_sman_takedown(drm_sman_t * sman)
+{
+	drm_ht_remove(&sman->user_hash_tab);
+	drm_ht_remove(&sman->owner_hash_tab);
+	if (sman->mm)
+		drm_free(sman->mm, sman->num_managers * sizeof(*sman->mm),
+			 DRM_MEM_MM);
+}
+
+EXPORT_SYMBOL(drm_sman_takedown);
+
+int
+drm_sman_init(drm_sman_t * sman, unsigned int num_managers,
+	      unsigned int user_order, unsigned int owner_order)
+{
+	int ret = 0;
+
+	sman->mm = (drm_sman_mm_t *) drm_calloc(num_managers, sizeof(*sman->mm),
+						DRM_MEM_MM);
+	if (!sman->mm) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	sman->num_managers = num_managers;
+	INIT_LIST_HEAD(&sman->owner_items);
+	ret = drm_ht_create(&sman->owner_hash_tab, owner_order);
+	if (ret)
+		goto out1;
+	ret = drm_ht_create(&sman->user_hash_tab, user_order);
+	if (!ret)
+		goto out;
+
+	drm_ht_remove(&sman->owner_hash_tab);
+out1:
+	drm_free(sman->mm, num_managers * sizeof(*sman->mm), DRM_MEM_MM);
+out:
+	return ret;
+}
+
+EXPORT_SYMBOL(drm_sman_init);
+
+static void *drm_sman_mm_allocate(void *private, unsigned long size,
+				  unsigned alignment)
+{
+	drm_mm_t *mm = (drm_mm_t *) private;
+	drm_mm_node_t *tmp;
+
+	tmp = drm_mm_search_free(mm, size, alignment, 1);
+	if (!tmp) {
+		return NULL;
+	}
+	tmp = drm_mm_get_block(tmp, size, alignment);
+	return tmp;
+}
+
+static void drm_sman_mm_free(void *private, void *ref)
+{
+	drm_mm_t *mm = (drm_mm_t *) private;
+	drm_mm_node_t *node = (drm_mm_node_t *) ref;
+
+	drm_mm_put_block(mm, node);
+}
+
+static void drm_sman_mm_destroy(void *private)
+{
+	drm_mm_t *mm = (drm_mm_t *) private;
+	drm_mm_takedown(mm);
+	drm_free(mm, sizeof(*mm), DRM_MEM_MM);
+}
+
+static unsigned long drm_sman_mm_offset(void *private, void *ref)
+{
+	drm_mm_node_t *node = (drm_mm_node_t *) ref;
+	return node->start;
+}
+
+int
+drm_sman_set_range(drm_sman_t * sman, unsigned int manager,
+		   unsigned long start, unsigned long size)
+{
+	drm_sman_mm_t *sman_mm;
+	drm_mm_t *mm;
+	int ret;
+
+	BUG_ON(manager >= sman->num_managers);
+
+	sman_mm = &sman->mm[manager];
+	mm = drm_calloc(1, sizeof(*mm), DRM_MEM_MM);
+	if (!mm) {
+		return -ENOMEM;
+	}
+	sman_mm->private = mm;
+	ret = drm_mm_init(mm, start, size);
+
+	if (ret) {
+		drm_free(mm, sizeof(*mm), DRM_MEM_MM);
+		return ret;
+	}
+
+	sman_mm->allocate = drm_sman_mm_allocate;
+	sman_mm->free = drm_sman_mm_free;
+	sman_mm->destroy = drm_sman_mm_destroy;
+	sman_mm->offset = drm_sman_mm_offset;
+
+	return 0;
+}
+
+EXPORT_SYMBOL(drm_sman_set_range);
+
+int
+drm_sman_set_manager(drm_sman_t * sman, unsigned int manager,
+		     drm_sman_mm_t * allocator)
+{
+	BUG_ON(manager >= sman->num_managers);
+	sman->mm[manager] = *allocator;
+
+	return 0;
+}
+
+static drm_owner_item_t *drm_sman_get_owner_item(drm_sman_t * sman,
+						 unsigned long owner)
+{
+	int ret;
+	drm_hash_item_t *owner_hash_item;
+	drm_owner_item_t *owner_item;
+
+	ret = drm_ht_find_item(&sman->owner_hash_tab, owner, &owner_hash_item);
+	if (!ret) {
+		return drm_hash_entry(owner_hash_item, drm_owner_item_t,
+				      owner_hash);
+	}
+
+	owner_item = drm_calloc(1, sizeof(*owner_item), DRM_MEM_MM);
+	if (!owner_item)
+		goto out;
+
+	INIT_LIST_HEAD(&owner_item->mem_blocks);
+	owner_item->owner_hash.key = owner;
+	if (drm_ht_insert_item(&sman->owner_hash_tab, &owner_item->owner_hash))
+		goto out1;
+
+	list_add_tail(&owner_item->sman_list, &sman->owner_items);
+	return owner_item;
+
+out1:
+	drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM);
+out:
+	return NULL;
+}
+
+drm_memblock_item_t *drm_sman_alloc(drm_sman_t *sman, unsigned int manager,
+				    unsigned long size, unsigned alignment,
+				    unsigned long owner)
+{
+	void *tmp;
+	drm_sman_mm_t *sman_mm;
+	drm_owner_item_t *owner_item;
+	drm_memblock_item_t *memblock;
+
+	BUG_ON(manager >= sman->num_managers);
+
+	sman_mm = &sman->mm[manager];
+	tmp = sman_mm->allocate(sman_mm->private, size, alignment);
+
+	if (!tmp) {
+		return NULL;
+	}
+
+	memblock = drm_calloc(1, sizeof(*memblock), DRM_MEM_MM);
+
+	if (!memblock)
+		goto out;
+
+	memblock->mm_info = tmp;
+	memblock->mm = sman_mm;
+	memblock->sman = sman;
+
+	if (drm_ht_just_insert_please
+	    (&sman->user_hash_tab, &memblock->user_hash,
+	     (unsigned long)memblock, 32, 0, 0))
+		goto out1;
+
+	owner_item = drm_sman_get_owner_item(sman, owner);
+	if (!owner_item)
+		goto out2;
+
+	list_add_tail(&memblock->owner_list, &owner_item->mem_blocks);
+
+	return memblock;
+
+out2:
+	drm_ht_remove_item(&sman->user_hash_tab, &memblock->user_hash);
+out1:
+	drm_free(memblock, sizeof(*memblock), DRM_MEM_MM);
+out:
+	sman_mm->free(sman_mm->private, tmp);
+
+	return NULL;
+}
+
+EXPORT_SYMBOL(drm_sman_alloc);
+
+static void drm_sman_free(drm_memblock_item_t *item)
+{
+	drm_sman_t *sman = item->sman;
+
+	list_del(&item->owner_list);
+	drm_ht_remove_item(&sman->user_hash_tab, &item->user_hash);
+	item->mm->free(item->mm->private, item->mm_info);
+	drm_free(item, sizeof(*item), DRM_MEM_MM);
+}
+
+int drm_sman_free_key(drm_sman_t *sman, unsigned int key)
+{
+	drm_hash_item_t *hash_item;
+	drm_memblock_item_t *memblock_item;
+
+	if (drm_ht_find_item(&sman->user_hash_tab, key, &hash_item))
+		return -EINVAL;
+
+	memblock_item = drm_hash_entry(hash_item, drm_memblock_item_t, user_hash);
+	drm_sman_free(memblock_item);
+	return 0;
+}
+
+EXPORT_SYMBOL(drm_sman_free_key);
+
+static void drm_sman_remove_owner(drm_sman_t *sman,
+				  drm_owner_item_t *owner_item)
+{
+	list_del(&owner_item->sman_list);
+	drm_ht_remove_item(&sman->owner_hash_tab, &owner_item->owner_hash);
+	drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM);
+}
+
+int drm_sman_owner_clean(drm_sman_t *sman, unsigned long owner)
+{
+
+	drm_hash_item_t *hash_item;
+	drm_owner_item_t *owner_item;
+
+	if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) {
+		return -1;
+	}
+
+	owner_item = drm_hash_entry(hash_item, drm_owner_item_t, owner_hash);
+	if (owner_item->mem_blocks.next == &owner_item->mem_blocks) {
+		drm_sman_remove_owner(sman, owner_item);
+		return -1;
+	}
+
+	return 0;
+}
+
+EXPORT_SYMBOL(drm_sman_owner_clean);
+
+static void drm_sman_do_owner_cleanup(drm_sman_t *sman,
+				      drm_owner_item_t *owner_item)
+{
+	drm_memblock_item_t *entry, *next;
+
+	list_for_each_entry_safe(entry, next, &owner_item->mem_blocks,
+				 owner_list) {
+		drm_sman_free(entry);
+	}
+	drm_sman_remove_owner(sman, owner_item);
+}
+
+void drm_sman_owner_cleanup(drm_sman_t *sman, unsigned long owner)
+{
+
+	drm_hash_item_t *hash_item;
+	drm_owner_item_t *owner_item;
+
+	if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) {
+
+		return;
+	}
+
+	owner_item = drm_hash_entry(hash_item, drm_owner_item_t, owner_hash);
+	drm_sman_do_owner_cleanup(sman, owner_item);
+}
+
+EXPORT_SYMBOL(drm_sman_owner_cleanup);
+
+void drm_sman_cleanup(drm_sman_t *sman)
+{
+	drm_owner_item_t *entry, *next;
+	unsigned int i;
+	drm_sman_mm_t *sman_mm;
+
+	list_for_each_entry_safe(entry, next, &sman->owner_items, sman_list) {
+		drm_sman_do_owner_cleanup(sman, entry);
+	}
+	if (sman->mm) {
+		for (i = 0; i < sman->num_managers; ++i) {
+			sman_mm = &sman->mm[i];
+			if (sman_mm->private) {
+				sman_mm->destroy(sman_mm->private);
+				sman_mm->private = NULL;
+			}
+		}
+	}
+}
+
+EXPORT_SYMBOL(drm_sman_cleanup);
diff --git a/drivers/char/drm/drm_sman.h b/drivers/char/drm/drm_sman.h
new file mode 100644
index 0000000..ddc732a
--- /dev/null
+++ b/drivers/char/drm/drm_sman.h
@@ -0,0 +1,176 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ **************************************************************************/
+/*
+ * Simple memory MANager interface that keeps track on allocate regions on a
+ * per "owner" basis. All regions associated with an "owner" can be released
+ * with a simple call. Typically if the "owner" exists. The owner is any
+ * "unsigned long" identifier. Can typically be a pointer to a file private
+ * struct or a context identifier.
+ *
+ * Authors:
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#ifndef DRM_SMAN_H
+#define DRM_SMAN_H
+
+#include "drmP.h"
+#include "drm_hashtab.h"
+
+/*
+ * A class that is an abstration of a simple memory allocator.
+ * The sman implementation provides a default such allocator
+ * using the drm_mm.c implementation. But the user can replace it.
+ * See the SiS implementation, which may use the SiS FB kernel module
+ * for memory management.
+ */
+
+typedef struct drm_sman_mm {
+	/* private info. If allocated, needs to be destroyed by the destroy
+	   function */
+	void *private;
+
+	/* Allocate a memory block with given size and alignment.
+	   Return an opaque reference to the memory block */
+
+	void *(*allocate) (void *private, unsigned long size,
+			   unsigned alignment);
+
+	/* Free a memory block. "ref" is the opaque reference that we got from
+	   the "alloc" function */
+
+	void (*free) (void *private, void *ref);
+
+	/* Free all resources associated with this allocator */
+
+	void (*destroy) (void *private);
+
+	/* Return a memory offset from the opaque reference returned from the
+	   "alloc" function */
+
+	unsigned long (*offset) (void *private, void *ref);
+} drm_sman_mm_t;
+
+typedef struct drm_memblock_item {
+	struct list_head owner_list;
+	drm_hash_item_t user_hash;
+	void *mm_info;
+	drm_sman_mm_t *mm;
+	struct drm_sman *sman;
+} drm_memblock_item_t;
+
+typedef struct drm_sman {
+	drm_sman_mm_t *mm;
+	int num_managers;
+	drm_open_hash_t owner_hash_tab;
+	drm_open_hash_t user_hash_tab;
+	struct list_head owner_items;
+} drm_sman_t;
+
+/*
+ * Take down a memory manager. This function should only be called after a
+ * successful init and after a call to drm_sman_cleanup.
+ */
+
+extern void drm_sman_takedown(drm_sman_t * sman);
+
+/*
+ * Allocate structures for a manager.
+ * num_managers are the number of memory pools to manage. (VRAM, AGP, ....)
+ * user_order is the log2 of the number of buckets in the user hash table.
+ *	    set this to approximately log2 of the max number of memory regions
+ *	    that will be allocated for _all_ pools together.
+ * owner_order is the log2 of the number of buckets in the owner hash table.
+ *	    set this to approximately log2 of
+ *	    the number of client file connections that will
+ *	    be using the manager.
+ *
+ */
+
+extern int drm_sman_init(drm_sman_t * sman, unsigned int num_managers,
+			 unsigned int user_order, unsigned int owner_order);
+
+/*
+ * Initialize a drm_mm.c allocator. Should be called only once for each
+ * manager unless a customized allogator is used.
+ */
+
+extern int drm_sman_set_range(drm_sman_t * sman, unsigned int manager,
+			      unsigned long start, unsigned long size);
+
+/*
+ * Initialize a customized allocator for one of the managers.
+ * (See the SiS module). The object pointed to by "allocator" is copied,
+ * so it can be destroyed after this call.
+ */
+
+extern int drm_sman_set_manager(drm_sman_t * sman, unsigned int mananger,
+				drm_sman_mm_t * allocator);
+
+/*
+ * Allocate a memory block. Aligment is not implemented yet.
+ */
+
+extern drm_memblock_item_t *drm_sman_alloc(drm_sman_t * sman,
+					   unsigned int manager,
+					   unsigned long size,
+					   unsigned alignment,
+					   unsigned long owner);
+/*
+ * Free a memory block identified by its user hash key.
+ */
+
+extern int drm_sman_free_key(drm_sman_t * sman, unsigned int key);
+
+/*
+ * returns 1 iff there are no stale memory blocks associated with this owner.
+ * Typically called to determine if we need to idle the hardware and call
+ * drm_sman_owner_cleanup. If there are no stale memory blocks, it removes all
+ * resources associated with owner.
+ */
+
+extern int drm_sman_owner_clean(drm_sman_t * sman, unsigned long owner);
+
+/*
+ * Frees all stale memory blocks associated with this owner. Note that this
+ * requires that the hardware is finished with all blocks, so the graphics engine
+ * should be idled before this call is made. This function also frees
+ * any resources associated with "owner" and should be called when owner
+ * is not going to be referenced anymore.
+ */
+
+extern void drm_sman_owner_cleanup(drm_sman_t * sman, unsigned long owner);
+
+/*
+ * Frees all stale memory blocks associated with the memory manager.
+ * See idling above.
+ */
+
+extern void drm_sman_cleanup(drm_sman_t * sman);
+
+#endif
diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c
index 9a842a3..7b1d4e8 100644
--- a/drivers/char/drm/drm_stub.c
+++ b/drivers/char/drm/drm_stub.c
@@ -65,22 +65,22 @@ static int drm_fill_in_dev(drm_device_t 
 	mutex_init(&dev->ctxlist_mutex);
 
 	dev->pdev = pdev;
+	dev->pci_device = pdev->device;
+	dev->pci_vendor = pdev->vendor;
 
 #ifdef __alpha__
 	dev->hose = pdev->sysdata;
-	dev->pci_domain = dev->hose->bus->number;
-#else
-	dev->pci_domain = 0;
 #endif
-	dev->pci_bus = pdev->bus->number;
-	dev->pci_slot = PCI_SLOT(pdev->devfn);
-	dev->pci_func = PCI_FUNC(pdev->devfn);
 	dev->irq = pdev->irq;
 
 	dev->maplist = drm_calloc(1, sizeof(*dev->maplist), DRM_MEM_MAPS);
 	if (dev->maplist == NULL)
 		return -ENOMEM;
 	INIT_LIST_HEAD(&dev->maplist->head);
+	if (drm_ht_create(&dev->map_hash, 12)) {
+		drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
+		return -ENOMEM;
+	}
 
 	/* the DRM has 6 basic counters */
 	dev->counters = 6;
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index ffd0800..b40ae43 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -59,7 +59,7 @@ static __inline__ struct page *drm_do_vm
 	drm_device_t *dev = priv->head->dev;
 	drm_map_t *map = NULL;
 	drm_map_list_t *r_list;
-	struct list_head *list;
+	drm_hash_item_t *hash;
 
 	/*
 	 * Find the right map
@@ -70,14 +70,11 @@ static __inline__ struct page *drm_do_vm
 	if (!dev->agp || !dev->agp->cant_use_aperture)
 		goto vm_nopage_error;
 
-	list_for_each(list, &dev->maplist->head) {
-		r_list = list_entry(list, drm_map_list_t, head);
-		map = r_list->map;
-		if (!map)
-			continue;
-		if (r_list->user_token == VM_OFFSET(vma))
-			break;
-	}
+	if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash))
+		goto vm_nopage_error;
+
+	r_list = drm_hash_entry(hash, drm_map_list_t, hash);
+	map = r_list->map;
 
 	if (map && map->type == _DRM_AGP) {
 		unsigned long offset = address - vma->vm_start;
@@ -467,7 +464,7 @@ static int drm_mmap_dma(struct file *fil
 	dev = priv->head->dev;
 	dma = dev->dma;
 	DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
-		  vma->vm_start, vma->vm_end, VM_OFFSET(vma));
+		  vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT);
 
 	/* Length must match exact page count */
 	if (!dma || (length >> PAGE_SHIFT) != dma->page_count) {
@@ -521,12 +518,11 @@ int drm_mmap(struct file *filp, struct v
 	drm_file_t *priv = filp->private_data;
 	drm_device_t *dev = priv->head->dev;
 	drm_map_t *map = NULL;
-	drm_map_list_t *r_list;
 	unsigned long offset = 0;
-	struct list_head *list;
+	drm_hash_item_t *hash;
 
 	DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
-		  vma->vm_start, vma->vm_end, VM_OFFSET(vma));
+		  vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT);
 
 	if (!priv->authenticated)
 		return -EACCES;
@@ -535,7 +531,7 @@ int drm_mmap(struct file *filp, struct v
 	 * the AGP mapped at physical address 0
 	 * --BenH.
 	 */
-	if (!VM_OFFSET(vma)
+	if (!(vma->vm_pgoff << PAGE_SHIFT)
 #if __OS_HAS_AGP
 	    && (!dev->agp
 		|| dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE)
@@ -543,23 +539,12 @@ #endif
 	    )
 		return drm_mmap_dma(filp, vma);
 
-	/* A sequential search of a linked list is
-	   fine here because: 1) there will only be
-	   about 5-10 entries in the list and, 2) a
-	   DRI client only has to do this mapping
-	   once, so it doesn't have to be optimized
-	   for performance, even if the list was a
-	   bit longer. */
-	list_for_each(list, &dev->maplist->head) {
-
-		r_list = list_entry(list, drm_map_list_t, head);
-		map = r_list->map;
-		if (!map)
-			continue;
-		if (r_list->user_token == VM_OFFSET(vma))
-			break;
+	if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) {
+		DRM_ERROR("Could not find map\n");
+		return -EINVAL;
 	}
 
+	map = drm_hash_entry(hash, drm_map_list_t, hash)->map;
 	if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN)))
 		return -EPERM;
 
@@ -620,7 +605,7 @@ #endif
 		offset = dev->driver->get_reg_ofs(dev);
 #ifdef __sparc__
 		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-		if (io_remap_pfn_range(DRM_RPR_ARG(vma) vma->vm_start,
+		if (io_remap_pfn_range(vma, vma->vm_start,
 				       (map->offset + offset) >> PAGE_SHIFT,
 				       vma->vm_end - vma->vm_start,
 				       vma->vm_page_prot))
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
index c658dde..fa2de70 100644
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -106,7 +106,7 @@ static int i810_mmap_buffers(struct file
 	unlock_kernel();
 
 	if (io_remap_pfn_range(vma, vma->vm_start,
-			       VM_OFFSET(vma) >> PAGE_SHIFT,
+			       vma->vm_pgoff,
 			       vma->vm_end - vma->vm_start, vma->vm_page_prot))
 		return -EAGAIN;
 	return 0;
@@ -141,10 +141,10 @@ static int i810_map_buffer(drm_buf_t * b
 					    MAP_SHARED, buf->bus_address);
 	dev_priv->mmap_buffer = NULL;
 	filp->f_op = old_fops;
-	if ((unsigned long)buf_priv->virtual > -1024UL) {
+	if (IS_ERR(buf_priv->virtual)) {
 		/* Real error */
 		DRM_ERROR("mmap error\n");
-		retcode = (signed int)buf_priv->virtual;
+		retcode = PTR_ERR(buf_priv->virtual);
 		buf_priv->virtual = NULL;
 	}
 	up_write(&current->mm->mmap_sem);
@@ -808,7 +808,7 @@ static void i810_dma_dispatch_vertex(drm
 		    ((GFX_OP_PRIMITIVE | prim | ((used / 4) - 2)));
 
 		if (used & 4) {
-			*(u32 *) ((u32) buf_priv->kernel_virtual + used) = 0;
+			*(u32 *) ((char *) buf_priv->kernel_virtual + used) = 0;
 			used += 4;
 		}
 
@@ -1166,7 +1166,7 @@ static void i810_dma_dispatch_mc(drm_dev
 
 	if (buf_priv->currently_mapped == I810_BUF_MAPPED) {
 		if (used & 4) {
-			*(u32 *) ((u32) buf_priv->virtual + used) = 0;
+			*(u32 *) ((char *) buf_priv->virtual + used) = 0;
 			used += 4;
 		}
 
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
index b0f815d..4f0e574 100644
--- a/drivers/char/drm/i830_dma.c
+++ b/drivers/char/drm/i830_dma.c
@@ -108,7 +108,7 @@ static int i830_mmap_buffers(struct file
 	unlock_kernel();
 
 	if (io_remap_pfn_range(vma, vma->vm_start,
-			       VM_OFFSET(vma) >> PAGE_SHIFT,
+			       vma->vm_pgoff,
 			       vma->vm_end - vma->vm_start, vma->vm_page_prot))
 		return -EAGAIN;
 	return 0;
@@ -146,7 +146,7 @@ static int i830_map_buffer(drm_buf_t * b
 	if (IS_ERR((void *)virtual)) {	/* ugh */
 		/* Real error */
 		DRM_ERROR("mmap error\n");
-		retcode = virtual;
+		retcode = PTR_ERR((void *)virtual);
 		buf_priv->virtual = NULL;
 	} else {
 		buf_priv->virtual = (void __user *)virtual;
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index a94233b..fb7913f 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -31,6 +31,11 @@ #include "drm.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
 
+#define IS_I965G(dev) (dev->pci_device == 0x2972 || \
+		       dev->pci_device == 0x2982 || \
+		       dev->pci_device == 0x2992 || \
+		       dev->pci_device == 0x29A2)
+
 /* Really want an OS-independent resettable timer.  Would like to have
  * this loop run for (eg) 3 sec, but have the timer reset every time
  * the head pointer changes, so that EBUSY only happens if the ring
@@ -255,7 +260,7 @@ static int i915_dma_init(DRM_IOCTL_ARGS)
 		retcode = i915_dma_resume(dev);
 		break;
 	default:
-		retcode = -EINVAL;
+		retcode = DRM_ERR(EINVAL);
 		break;
 	}
 
@@ -347,7 +352,7 @@ static int i915_emit_cmds(drm_device_t *
 	if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8)
 		return DRM_ERR(EINVAL);
 
-	BEGIN_LP_RING(((dwords+1)&~1));
+	BEGIN_LP_RING((dwords+1)&~1);
 
 	for (i = 0; i < dwords;) {
 		int cmd, sz;
@@ -386,7 +391,7 @@ static int i915_emit_box(drm_device_t * 
 	RING_LOCALS;
 
 	if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) {
-		return EFAULT;
+		return DRM_ERR(EFAULT);
 	}
 
 	if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) {
@@ -395,24 +400,40 @@ static int i915_emit_box(drm_device_t * 
 		return DRM_ERR(EINVAL);
 	}
 
-	BEGIN_LP_RING(6);
-	OUT_RING(GFX_OP_DRAWRECT_INFO);
-	OUT_RING(DR1);
-	OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
-	OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
-	OUT_RING(DR4);
-	OUT_RING(0);
-	ADVANCE_LP_RING();
+	if (IS_I965G(dev)) {
+		BEGIN_LP_RING(4);
+		OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
+		OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
+		OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
+		OUT_RING(DR4);
+		ADVANCE_LP_RING();
+	} else {
+		BEGIN_LP_RING(6);
+		OUT_RING(GFX_OP_DRAWRECT_INFO);
+		OUT_RING(DR1);
+		OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
+		OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
+		OUT_RING(DR4);
+		OUT_RING(0);
+		ADVANCE_LP_RING();
+	}
 
 	return 0;
 }
 
+/* XXX: Emitting the counter should really be moved to part of the IRQ
+ * emit. For now, do it in both places:
+ */
+
 static void i915_emit_breadcrumb(drm_device_t *dev)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	RING_LOCALS;
 
-	dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
+	dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
+
+	if (dev_priv->counter > 0x7FFFFFFFUL)
+		dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
 
 	BEGIN_LP_RING(4);
 	OUT_RING(CMD_STORE_DWORD_IDX);
diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h
index 5aa3e0e..6af83e6 100644
--- a/drivers/char/drm/i915_drm.h
+++ b/drivers/char/drm/i915_drm.h
@@ -98,6 +98,12 @@ typedef struct _drm_i915_sarea {
 	int rotated_size;
 	int rotated_pitch;
 	int virtualX, virtualY;
+
+	unsigned int front_tiled;
+	unsigned int back_tiled;
+	unsigned int depth_tiled;
+	unsigned int rotated_tiled;
+	unsigned int rotated2_tiled;
 } drm_i915_sarea_t;
 
 /* Flags for perf_boxes
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
index 2d56503..fdc2bf1 100644
--- a/drivers/char/drm/i915_drv.h
+++ b/drivers/char/drm/i915_drv.h
@@ -146,9 +146,9 @@ #define RING_LOCALS	unsigned int outring
 #define BEGIN_LP_RING(n) do {				\
 	if (I915_VERBOSE)				\
 		DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n",	\
-			  n, __FUNCTION__);		\
-	if (dev_priv->ring.space < n*4)			\
-		i915_wait_ring(dev, n*4, __FUNCTION__);		\
+			  (n), __FUNCTION__);		\
+	if (dev_priv->ring.space < (n)*4)			\
+		i915_wait_ring(dev, (n)*4, __FUNCTION__);		\
 	outcount = 0;					\
 	outring = dev_priv->ring.tail;			\
 	ringmask = dev_priv->ring.tail_mask;		\
@@ -157,7 +157,7 @@ #define BEGIN_LP_RING(n) do {				\
 
 #define OUT_RING(n) do {					\
 	if (I915_VERBOSE) DRM_DEBUG("   OUT_RING %x\n", (int)(n));	\
-	*(volatile unsigned int *)(virt + outring) = n;		\
+	*(volatile unsigned int *)(virt + outring) = (n);	\
         outcount++;						\
 	outring += 4;						\
 	outring &= ringmask;					\
@@ -254,6 +254,8 @@ #define GFX_OP_MAP_INFO          ((0x3<<
 #define GFX_OP_DESTBUFFER_VARS   ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0)
 #define GFX_OP_DRAWRECT_INFO     ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3))
 
+#define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2)
+
 #define MI_BATCH_BUFFER 	((0x30<<23)|1)
 #define MI_BATCH_BUFFER_START 	(0x31<<23)
 #define MI_BATCH_BUFFER_END 	(0xA<<23)
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c
index cd96cfa..0d4a162 100644
--- a/drivers/char/drm/i915_irq.c
+++ b/drivers/char/drm/i915_irq.c
@@ -71,21 +71,27 @@ irqreturn_t i915_driver_irq_handler(DRM_
 static int i915_emit_irq(drm_device_t * dev)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	u32 ret;
 	RING_LOCALS;
 
 	i915_kernel_lost_context(dev);
 
 	DRM_DEBUG("%s\n", __FUNCTION__);
 
-	ret = dev_priv->counter;
+	dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
 
-	BEGIN_LP_RING(2);
+	if (dev_priv->counter > 0x7FFFFFFFUL)
+		dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
+
+	BEGIN_LP_RING(6);
+	OUT_RING(CMD_STORE_DWORD_IDX);
+	OUT_RING(20);
+	OUT_RING(dev_priv->counter);
+	OUT_RING(0);
 	OUT_RING(0);
 	OUT_RING(GFX_OP_USER_INTERRUPT);
 	ADVANCE_LP_RING();
-
-	return ret;
+	
+	return dev_priv->counter;
 }
 
 static int i915_wait_irq(drm_device_t * dev, int irq_nr)
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
index 5ad43ba..5ed9656 100644
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -864,13 +864,13 @@ static int radeon_do_pixcache_flush(drm_
 
 	dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
 
-	tmp = RADEON_READ(RADEON_RB2D_DSTCACHE_CTLSTAT);
-	tmp |= RADEON_RB2D_DC_FLUSH_ALL;
-	RADEON_WRITE(RADEON_RB2D_DSTCACHE_CTLSTAT, tmp);
+	tmp = RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT);
+	tmp |= RADEON_RB3D_DC_FLUSH_ALL;
+	RADEON_WRITE(RADEON_RB3D_DSTCACHE_CTLSTAT, tmp);
 
 	for (i = 0; i < dev_priv->usec_timeout; i++) {
-		if (!(RADEON_READ(RADEON_RB2D_DSTCACHE_CTLSTAT)
-		      & RADEON_RB2D_DC_BUSY)) {
+		if (!(RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT)
+		      & RADEON_RB3D_DC_BUSY)) {
 			return 0;
 		}
 		DRM_UDELAY(1);
@@ -1130,7 +1130,7 @@ static void radeon_cp_init_ring_buffer(d
 			     | (dev_priv->fb_location >> 16));
 
 #if __OS_HAS_AGP
-	if (dev_priv->flags & CHIP_IS_AGP) {
+	if (dev_priv->flags & RADEON_IS_AGP) {
 		RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base);
 		RADEON_WRITE(RADEON_MC_AGP_LOCATION,
 			     (((dev_priv->gart_vm_start - 1 +
@@ -1158,7 +1158,7 @@ #endif
 	dev_priv->ring.tail = cur_read_ptr;
 
 #if __OS_HAS_AGP
-	if (dev_priv->flags & CHIP_IS_AGP) {
+	if (dev_priv->flags & RADEON_IS_AGP) {
 		RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR,
 			     dev_priv->ring_rptr->offset
 			     - dev->agp->base + dev_priv->gart_vm_start);
@@ -1258,6 +1258,13 @@ static void radeon_test_writeback(drm_ra
 		dev_priv->writeback_works = 0;
 		DRM_INFO("writeback forced off\n");
 	}
+
+	if (!dev_priv->writeback_works) {
+		/* Disable writeback to avoid unnecessary bus master transfer */
+		RADEON_WRITE(RADEON_CP_RB_CNTL, RADEON_READ(RADEON_CP_RB_CNTL) |
+			     RADEON_RB_NO_UPDATE);
+		RADEON_WRITE(RADEON_SCRATCH_UMSK, 0);
+	}
 }
 
 /* Enable or disable PCI-E GART on the chip */
@@ -1295,7 +1302,7 @@ static void radeon_set_pcigart(drm_radeo
 {
 	u32 tmp;
 
-	if (dev_priv->flags & CHIP_IS_PCIE) {
+	if (dev_priv->flags & RADEON_IS_PCIE) {
 		radeon_set_pciegart(dev_priv, on);
 		return;
 	}
@@ -1333,20 +1340,22 @@ static int radeon_do_init_cp(drm_device_
 	DRM_DEBUG("\n");
 
 	/* if we require new memory map but we don't have it fail */
-	if ((dev_priv->flags & CHIP_NEW_MEMMAP) && !dev_priv->new_memmap)
-	{
-		DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX\n");
+	if ((dev_priv->flags & RADEON_NEW_MEMMAP) && !dev_priv->new_memmap) {
+		DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX for 3D\n");
 		radeon_do_cleanup_cp(dev);
 		return DRM_ERR(EINVAL);
 	}
 
-	if (init->is_pci && (dev_priv->flags & CHIP_IS_AGP))
-	{
+	if (init->is_pci && (dev_priv->flags & RADEON_IS_AGP)) {
 		DRM_DEBUG("Forcing AGP card to PCI mode\n");
-		dev_priv->flags &= ~CHIP_IS_AGP;
+		dev_priv->flags &= ~RADEON_IS_AGP;
+	} else if (!(dev_priv->flags & (RADEON_IS_AGP | RADEON_IS_PCI | RADEON_IS_PCIE))
+		   && !init->is_pci) {
+		DRM_DEBUG("Restoring AGP flag\n");
+		dev_priv->flags |= RADEON_IS_AGP;
 	}
 
-	if ((!(dev_priv->flags & CHIP_IS_AGP)) && !dev->sg) {
+	if ((!(dev_priv->flags & RADEON_IS_AGP)) && !dev->sg) {
 		DRM_ERROR("PCI GART memory not allocated!\n");
 		radeon_do_cleanup_cp(dev);
 		return DRM_ERR(EINVAL);
@@ -1489,7 +1498,7 @@ static int radeon_do_init_cp(drm_device_
 				    init->sarea_priv_offset);
 
 #if __OS_HAS_AGP
-	if (dev_priv->flags & CHIP_IS_AGP) {
+	if (dev_priv->flags & RADEON_IS_AGP) {
 		drm_core_ioremap(dev_priv->cp_ring, dev);
 		drm_core_ioremap(dev_priv->ring_rptr, dev);
 		drm_core_ioremap(dev->agp_buffer_map, dev);
@@ -1548,7 +1557,7 @@ #endif
 		 * align it down.
 		 */
 #if __OS_HAS_AGP
-		if (dev_priv->flags & CHIP_IS_AGP) {
+		if (dev_priv->flags & RADEON_IS_AGP) {
 			base = dev->agp->base;
 			/* Check if valid */
 			if ((base + dev_priv->gart_size) > dev_priv->fb_location &&
@@ -1578,7 +1587,7 @@ #endif
 	}
 
 #if __OS_HAS_AGP
-	if (dev_priv->flags & CHIP_IS_AGP)
+	if (dev_priv->flags & RADEON_IS_AGP)
 		dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset
 						 - dev->agp->base
 						 + dev_priv->gart_vm_start);
@@ -1604,7 +1613,7 @@ #endif
 	dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK;
 
 #if __OS_HAS_AGP
-	if (dev_priv->flags & CHIP_IS_AGP) {
+	if (dev_priv->flags & RADEON_IS_AGP) {
 		/* Turn off PCI GART */
 		radeon_set_pcigart(dev_priv, 0);
 	} else
@@ -1624,7 +1633,7 @@ #endif
 			    dev_priv->gart_info.mapping.handle;
 
 			dev_priv->gart_info.is_pcie =
-			    !!(dev_priv->flags & CHIP_IS_PCIE);
+			    !!(dev_priv->flags & RADEON_IS_PCIE);
 			dev_priv->gart_info.gart_table_location =
 			    DRM_ATI_GART_FB;
 
@@ -1636,7 +1645,7 @@ #endif
 			    DRM_ATI_GART_MAIN;
 			dev_priv->gart_info.addr = NULL;
 			dev_priv->gart_info.bus_addr = 0;
-			if (dev_priv->flags & CHIP_IS_PCIE) {
+			if (dev_priv->flags & RADEON_IS_PCIE) {
 				DRM_ERROR
 				    ("Cannot use PCI Express without GART in FB memory\n");
 				radeon_do_cleanup_cp(dev);
@@ -1678,7 +1687,7 @@ static int radeon_do_cleanup_cp(drm_devi
 		drm_irq_uninstall(dev);
 
 #if __OS_HAS_AGP
-	if (dev_priv->flags & CHIP_IS_AGP) {
+	if (dev_priv->flags & RADEON_IS_AGP) {
 		if (dev_priv->cp_ring != NULL) {
 			drm_core_ioremapfree(dev_priv->cp_ring, dev);
 			dev_priv->cp_ring = NULL;
@@ -1733,7 +1742,7 @@ static int radeon_do_resume_cp(drm_devic
 	DRM_DEBUG("Starting radeon_do_resume_cp()\n");
 
 #if __OS_HAS_AGP
-	if (dev_priv->flags & CHIP_IS_AGP) {
+	if (dev_priv->flags & RADEON_IS_AGP) {
 		/* Turn off PCI GART */
 		radeon_set_pcigart(dev_priv, 0);
 	} else
@@ -2177,13 +2186,15 @@ int radeon_driver_load(struct drm_device
 	dev->dev_private = (void *)dev_priv;
 	dev_priv->flags = flags;
 
-	switch (flags & CHIP_FAMILY_MASK) {
+	switch (flags & RADEON_FAMILY_MASK) {
 	case CHIP_R100:
 	case CHIP_RV200:
 	case CHIP_R200:
 	case CHIP_R300:
+	case CHIP_R350:
 	case CHIP_R420:
-		dev_priv->flags |= CHIP_HAS_HIERZ;
+	case CHIP_RV410:
+		dev_priv->flags |= RADEON_HAS_HIERZ;
 		break;
 	default:
 		/* all other chips have no hierarchical z buffer */
@@ -2191,13 +2202,14 @@ int radeon_driver_load(struct drm_device
 	}
 
 	if (drm_device_is_agp(dev))
-		dev_priv->flags |= CHIP_IS_AGP;
-
-	if (drm_device_is_pcie(dev))
-		dev_priv->flags |= CHIP_IS_PCIE;
+		dev_priv->flags |= RADEON_IS_AGP;
+	else if (drm_device_is_pcie(dev))
+		dev_priv->flags |= RADEON_IS_PCIE;
+	else
+		dev_priv->flags |= RADEON_IS_PCI;
 
 	DRM_DEBUG("%s card detected\n",
-		  ((dev_priv->flags & CHIP_IS_AGP) ? "AGP" : (((dev_priv->flags & CHIP_IS_PCIE) ? "PCIE" : "PCI"))));
+		  ((dev_priv->flags & RADEON_IS_AGP) ? "AGP" : (((dev_priv->flags & RADEON_IS_PCIE) ? "PCIE" : "PCI"))));
 	return ret;
 }
 
diff --git a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c
index eb985c2..2eb652e 100644
--- a/drivers/char/drm/radeon_drv.c
+++ b/drivers/char/drm/radeon_drv.c
@@ -44,7 +44,7 @@ module_param_named(no_wb, radeon_no_wb, 
 static int dri_library_name(struct drm_device *dev, char *buf)
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
-	int family = dev_priv->flags & CHIP_FAMILY_MASK;
+	int family = dev_priv->flags & RADEON_FAMILY_MASK;
 
 	return snprintf(buf, PAGE_SIZE, "%s\n",
 		        (family < CHIP_R200) ? "radeon" :
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
index e5a256f..f45cd7f 100644
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -133,15 +133,16 @@ enum radeon_cp_microcode_version {
  * Chip flags
  */
 enum radeon_chip_flags {
-	CHIP_FAMILY_MASK = 0x0000ffffUL,
-	CHIP_FLAGS_MASK = 0xffff0000UL,
-	CHIP_IS_MOBILITY = 0x00010000UL,
-	CHIP_IS_IGP = 0x00020000UL,
-	CHIP_SINGLE_CRTC = 0x00040000UL,
-	CHIP_IS_AGP = 0x00080000UL,
-	CHIP_HAS_HIERZ = 0x00100000UL,
-	CHIP_IS_PCIE = 0x00200000UL,
-	CHIP_NEW_MEMMAP = 0x00400000UL,
+	RADEON_FAMILY_MASK = 0x0000ffffUL,
+	RADEON_FLAGS_MASK = 0xffff0000UL,
+	RADEON_IS_MOBILITY = 0x00010000UL,
+	RADEON_IS_IGP = 0x00020000UL,
+	RADEON_SINGLE_CRTC = 0x00040000UL,
+	RADEON_IS_AGP = 0x00080000UL,
+	RADEON_HAS_HIERZ = 0x00100000UL,
+	RADEON_IS_PCIE = 0x00200000UL,
+	RADEON_NEW_MEMMAP = 0x00400000UL,
+	RADEON_IS_PCI = 0x00800000UL,
 };
 
 #define GET_RING_HEAD(dev_priv)	(dev_priv->writeback_works ? \
@@ -424,6 +425,8 @@ #define RADEON_AGP_BASE			0x0170
 #define RADEON_RB3D_COLOROFFSET		0x1c40
 #define RADEON_RB3D_COLORPITCH		0x1c48
 
+#define	RADEON_SRC_X_Y			0x1590
+
 #define RADEON_DP_GUI_MASTER_CNTL	0x146c
 #	define RADEON_GMC_SRC_PITCH_OFFSET_CNTL	(1 << 0)
 #	define RADEON_GMC_DST_PITCH_OFFSET_CNTL	(1 << 1)
@@ -441,6 +444,7 @@ #	define RADEON_GMC_WR_MSK_DIS		(1 << 30
 #	define RADEON_ROP3_S			0x00cc0000
 #	define RADEON_ROP3_P			0x00f00000
 #define RADEON_DP_WRITE_MASK		0x16cc
+#define RADEON_SRC_PITCH_OFFSET		0x1428
 #define RADEON_DST_PITCH_OFFSET		0x142c
 #define RADEON_DST_PITCH_OFFSET_C	0x1c80
 #	define RADEON_DST_TILE_LINEAR		(0 << 30)
@@ -545,6 +549,11 @@ #	define RADEON_RB3D_ZC_FLUSH		(1 << 0)
 #	define RADEON_RB3D_ZC_FREE		(1 << 2)
 #	define RADEON_RB3D_ZC_FLUSH_ALL		0x5
 #	define RADEON_RB3D_ZC_BUSY		(1 << 31)
+#define RADEON_RB3D_DSTCACHE_CTLSTAT	0x325c
+#	define RADEON_RB3D_DC_FLUSH		(3 << 0)
+#	define RADEON_RB3D_DC_FREE		(3 << 2)
+#	define RADEON_RB3D_DC_FLUSH_ALL		0xf
+#	define RADEON_RB3D_DC_BUSY		(1 << 31)
 #define RADEON_RB3D_ZSTENCILCNTL	0x1c2c
 #	define RADEON_Z_TEST_MASK		(7 << 4)
 #	define RADEON_Z_TEST_ALWAYS		(7 << 4)
@@ -681,6 +690,7 @@ #define RADEON_CP_ME_RAM_DATAL		0x07e0
 #define RADEON_CP_RB_BASE		0x0700
 #define RADEON_CP_RB_CNTL		0x0704
 #	define RADEON_BUF_SWAP_32BIT		(2 << 16)
+#	define RADEON_RB_NO_UPDATE		(1 << 27)
 #define RADEON_CP_RB_RPTR_ADDR		0x070c
 #define RADEON_CP_RB_RPTR		0x0710
 #define RADEON_CP_RB_WPTR		0x0714
@@ -986,13 +996,13 @@ #define RADEON_WAIT_UNTIL_PAGE_FLIPPED()
 } while (0)
 
 #define RADEON_FLUSH_CACHE() do {					\
-	OUT_RING( CP_PACKET0( RADEON_RB2D_DSTCACHE_CTLSTAT, 0 ) );	\
-	OUT_RING( RADEON_RB2D_DC_FLUSH );				\
+	OUT_RING( CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 0 ) );	\
+	OUT_RING( RADEON_RB3D_DC_FLUSH );				\
 } while (0)
 
 #define RADEON_PURGE_CACHE() do {					\
-	OUT_RING( CP_PACKET0( RADEON_RB2D_DSTCACHE_CTLSTAT, 0 ) );	\
-	OUT_RING( RADEON_RB2D_DC_FLUSH_ALL );				\
+	OUT_RING( CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 0 ) );	\
+	OUT_RING( RADEON_RB3D_DC_FLUSH_ALL );				\
 } while (0)
 
 #define RADEON_FLUSH_ZCACHE() do {					\
diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c
index 39a7f68..feac5f0 100644
--- a/drivers/char/drm/radeon_state.c
+++ b/drivers/char/drm/radeon_state.c
@@ -42,7 +42,11 @@ static __inline__ int radeon_check_and_f
 						    drm_file_t * filp_priv,
 						    u32 *offset)
 {
-	u32 off = *offset;
+	u64 off = *offset;
+	u32 fb_start = dev_priv->fb_location;
+	u32 fb_end = fb_start + dev_priv->fb_size - 1;
+	u32 gart_start = dev_priv->gart_vm_start;
+	u32 gart_end = gart_start + dev_priv->gart_size - 1;
 	struct drm_radeon_driver_file_fields *radeon_priv;
 
 	/* Hrm ... the story of the offset ... So this function converts
@@ -62,10 +66,8 @@ static __inline__ int radeon_check_and_f
 	/* First, the best case, the offset already lands in either the
 	 * framebuffer or the GART mapped space
 	 */
-	if ((off >= dev_priv->fb_location &&
-	     off < (dev_priv->fb_location + dev_priv->fb_size)) ||
-	    (off >= dev_priv->gart_vm_start &&
-	     off < (dev_priv->gart_vm_start + dev_priv->gart_size)))
+	if ((off >= fb_start && off <= fb_end) ||
+	    (off >= gart_start && off <= gart_end))
 		return 0;
 
 	/* Ok, that didn't happen... now check if we have a zero based
@@ -78,16 +80,13 @@ static __inline__ int radeon_check_and_f
 	}
 
 	/* Finally, assume we aimed at a GART offset if beyond the fb */
-	if (off > (dev_priv->fb_location + dev_priv->fb_size))
-		off = off - (dev_priv->fb_location + dev_priv->fb_size) +
-			dev_priv->gart_vm_start;
+	if (off > fb_end)
+		off = off - fb_end - 1 + gart_start;
 
 	/* Now recheck and fail if out of bounds */
-	if ((off >= dev_priv->fb_location &&
-	     off < (dev_priv->fb_location + dev_priv->fb_size)) ||
-	    (off >= dev_priv->gart_vm_start &&
-	     off < (dev_priv->gart_vm_start + dev_priv->gart_size))) {
-		DRM_DEBUG("offset fixed up to 0x%x\n", off);
+	if ((off >= fb_start && off <= fb_end) ||
+	    (off >= gart_start && off <= gart_end)) {
+		DRM_DEBUG("offset fixed up to 0x%x\n", (unsigned int)off);
 		*offset = off;
 		return 0;
 	}
@@ -869,7 +868,7 @@ static void radeon_cp_dispatch_clear(drm
 		 */
 		dev_priv->sarea_priv->ctx_owner = 0;
 
-		if ((dev_priv->flags & CHIP_HAS_HIERZ)
+		if ((dev_priv->flags & RADEON_HAS_HIERZ)
 		    && (flags & RADEON_USE_HIERZ)) {
 			/* FIXME : reverse engineer that for Rx00 cards */
 			/* FIXME : the mask supposedly contains low-res z values. So can't set
@@ -914,7 +913,7 @@ static void radeon_cp_dispatch_clear(drm
 		for (i = 0; i < nbox; i++) {
 			int tileoffset, nrtilesx, nrtilesy, j;
 			/* it looks like r200 needs rv-style clears, at least if hierz is not enabled? */
-			if ((dev_priv->flags & CHIP_HAS_HIERZ)
+			if ((dev_priv->flags & RADEON_HAS_HIERZ)
 			    && !(dev_priv->microcode_version == UCODE_R200)) {
 				/* FIXME : figure this out for r200 (when hierz is enabled). Or
 				   maybe r200 actually doesn't need to put the low-res z value into
@@ -998,7 +997,7 @@ static void radeon_cp_dispatch_clear(drm
 		}
 
 		/* TODO don't always clear all hi-level z tiles */
-		if ((dev_priv->flags & CHIP_HAS_HIERZ)
+		if ((dev_priv->flags & RADEON_HAS_HIERZ)
 		    && (dev_priv->microcode_version == UCODE_R200)
 		    && (flags & RADEON_USE_HIERZ))
 			/* r100 and cards without hierarchical z-buffer have no high-level z-buffer */
@@ -1270,9 +1269,9 @@ static void radeon_cp_dispatch_swap(drm_
 
 		DRM_DEBUG("dispatch swap %d,%d-%d,%d\n", x, y, w, h);
 
-		BEGIN_RING(7);
+		BEGIN_RING(9);
 
-		OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));
+		OUT_RING(CP_PACKET0(RADEON_DP_GUI_MASTER_CNTL, 0));
 		OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
 			 RADEON_GMC_DST_PITCH_OFFSET_CNTL |
 			 RADEON_GMC_BRUSH_NONE |
@@ -1284,6 +1283,7 @@ static void radeon_cp_dispatch_swap(drm_
 
 		/* Make this work even if front & back are flipped:
 		 */
+		OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1));
 		if (dev_priv->current_page == 0) {
 			OUT_RING(dev_priv->back_pitch_offset);
 			OUT_RING(dev_priv->front_pitch_offset);
@@ -1292,6 +1292,7 @@ static void radeon_cp_dispatch_swap(drm_
 			OUT_RING(dev_priv->back_pitch_offset);
 		}
 
+		OUT_RING(CP_PACKET0(RADEON_SRC_X_Y, 2));
 		OUT_RING((x << 16) | y);
 		OUT_RING((x << 16) | y);
 		OUT_RING((w << 16) | h);
@@ -2987,16 +2988,21 @@ #endif
 	case RADEON_PARAM_GART_TEX_HANDLE:
 		value = dev_priv->gart_textures_offset;
 		break;
-	
+	case RADEON_PARAM_SCRATCH_OFFSET:
+		if (!dev_priv->writeback_works)
+			return DRM_ERR(EINVAL);
+		value = RADEON_SCRATCH_REG_OFFSET;
+		break;
 	case RADEON_PARAM_CARD_TYPE:
-		if (dev_priv->flags & CHIP_IS_PCIE)
+		if (dev_priv->flags & RADEON_IS_PCIE)
 			value = RADEON_CARD_PCIE;
-		else if (dev_priv->flags & CHIP_IS_AGP)
+		else if (dev_priv->flags & RADEON_IS_AGP)
 			value = RADEON_CARD_AGP;
 		else
 			value = RADEON_CARD_PCI;
 		break;
 	default:
+		DRM_DEBUG("Invalid parameter %d\n", param.param);
 		return DRM_ERR(EINVAL);
 	}
 
diff --git a/drivers/char/drm/sis_drv.c b/drivers/char/drm/sis_drv.c
index 5e9dc86..3d5b321 100644
--- a/drivers/char/drm/sis_drv.c
+++ b/drivers/char/drm/sis_drv.c
@@ -35,11 +35,44 @@ static struct pci_device_id pciidlist[] 
 	sisdrv_PCI_IDS
 };
 
+static int sis_driver_load(drm_device_t *dev, unsigned long chipset)
+{
+	drm_sis_private_t *dev_priv;
+	int ret;
+
+	dev_priv = drm_calloc(1, sizeof(drm_sis_private_t), DRM_MEM_DRIVER);
+	if (dev_priv == NULL)
+		return DRM_ERR(ENOMEM);
+
+	dev->dev_private = (void *)dev_priv;
+	dev_priv->chipset = chipset;
+	ret = drm_sman_init(&dev_priv->sman, 2, 12, 8);
+	if (ret) {
+		drm_free(dev_priv, sizeof(dev_priv), DRM_MEM_DRIVER);
+	}
+
+	return ret;
+}
+
+static int sis_driver_unload(drm_device_t *dev)
+{
+	drm_sis_private_t *dev_priv = dev->dev_private;
+
+	drm_sman_takedown(&dev_priv->sman);
+	drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
+
+	return 0;
+}
+
 static struct drm_driver driver = {
 	.driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR,
-	.context_ctor = sis_init_context,
-	.context_dtor = sis_final_context,
-	.reclaim_buffers = drm_core_reclaim_buffers,
+	.load = sis_driver_load,
+	.unload = sis_driver_unload,
+	.context_dtor = NULL,
+	.dma_quiescent = sis_idle,
+	.reclaim_buffers = NULL,
+	.reclaim_buffers_locked = sis_reclaim_buffers_locked,
+	.lastclose = sis_lastclose,
 	.get_map_ofs = drm_core_get_map_ofs,
 	.get_reg_ofs = drm_core_get_reg_ofs,
 	.ioctls = sis_ioctls,
diff --git a/drivers/char/drm/sis_drv.h b/drivers/char/drm/sis_drv.h
index e218e52..2b8d6f6 100644
--- a/drivers/char/drm/sis_drv.h
+++ b/drivers/char/drm/sis_drv.h
@@ -31,23 +31,39 @@ #define _SIS_DRV_H_
 /* General customization:
  */
 
-#define DRIVER_AUTHOR		"SIS"
+#define DRIVER_AUTHOR		"SIS, Tungsten Graphics"
 #define DRIVER_NAME		"sis"
 #define DRIVER_DESC		"SIS 300/630/540"
-#define DRIVER_DATE		"20030826"
+#define DRIVER_DATE		"20060704"
 #define DRIVER_MAJOR		1
-#define DRIVER_MINOR		1
-#define DRIVER_PATCHLEVEL	0
+#define DRIVER_MINOR		2
+#define DRIVER_PATCHLEVEL	1
 
-#include "sis_ds.h"
+enum sis_family {
+	SIS_OTHER = 0,
+	SIS_CHIP_315 = 1,
+};
+
+#include "drm_sman.h"
+
+#define SIS_BASE (dev_priv->mmio)
+#define SIS_READ(reg)         DRM_READ32(SIS_BASE, reg);
+#define SIS_WRITE(reg, val)   DRM_WRITE32(SIS_BASE, reg, val);
 
 typedef struct drm_sis_private {
-	memHeap_t *AGPHeap;
-	memHeap_t *FBHeap;
+	drm_local_map_t *mmio;
+	unsigned int idle_fault;
+	drm_sman_t sman;
+	unsigned int chipset;
+	int vram_initialized;
+	int agp_initialized;
+	unsigned long vram_offset;
+	unsigned long agp_offset;
 } drm_sis_private_t;
 
-extern int sis_init_context(drm_device_t * dev, int context);
-extern int sis_final_context(drm_device_t * dev, int context);
+extern int sis_idle(drm_device_t *dev);
+extern void sis_reclaim_buffers_locked(drm_device_t *dev, struct file *filp);
+extern void sis_lastclose(drm_device_t *dev);
 
 extern drm_ioctl_desc_t sis_ioctls[];
 extern int sis_max_ioctl;
diff --git a/drivers/char/drm/sis_ds.c b/drivers/char/drm/sis_ds.c
deleted file mode 100644
index 2e485d4..0000000
--- a/drivers/char/drm/sis_ds.c
+++ /dev/null
@@ -1,299 +0,0 @@
-/* sis_ds.c -- Private header for Direct Rendering Manager -*- linux-c -*-
- * Created: Mon Jan  4 10:05:05 1999 by sclin@sis.com.tw
- *
- * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
- * All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Sung-Ching Lin <sclin@sis.com.tw>
- *
- */
-
-#include "drmP.h"
-#include "drm.h"
-#include "sis_ds.h"
-
-/* Set Data Structure, not check repeated value
- * temporarily used
- */
-
-set_t *setInit(void)
-{
-	int i;
-	set_t *set;
-
-	set = (set_t *) drm_alloc(sizeof(set_t), DRM_MEM_DRIVER);
-	if (set != NULL) {
-		for (i = 0; i < SET_SIZE; i++) {
-			set->list[i].free_next = i + 1;
-			set->list[i].alloc_next = -1;
-		}
-		set->list[SET_SIZE - 1].free_next = -1;
-		set->free = 0;
-		set->alloc = -1;
-		set->trace = -1;
-	}
-	return set;
-}
-
-int setAdd(set_t * set, ITEM_TYPE item)
-{
-	int free = set->free;
-
-	if (free != -1) {
-		set->list[free].val = item;
-		set->free = set->list[free].free_next;
-	} else {
-		return 0;
-	}
-
-	set->list[free].alloc_next = set->alloc;
-	set->alloc = free;
-	set->list[free].free_next = -1;
-
-	return 1;
-}
-
-int setDel(set_t * set, ITEM_TYPE item)
-{
-	int alloc = set->alloc;
-	int prev = -1;
-
-	while (alloc != -1) {
-		if (set->list[alloc].val == item) {
-			if (prev != -1)
-				set->list[prev].alloc_next =
-				    set->list[alloc].alloc_next;
-			else
-				set->alloc = set->list[alloc].alloc_next;
-			break;
-		}
-		prev = alloc;
-		alloc = set->list[alloc].alloc_next;
-	}
-
-	if (alloc == -1)
-		return 0;
-
-	set->list[alloc].free_next = set->free;
-	set->free = alloc;
-	set->list[alloc].alloc_next = -1;
-
-	return 1;
-}
-
-/* setFirst -> setAdd -> setNext is wrong */
-
-int setFirst(set_t * set, ITEM_TYPE * item)
-{
-	if (set->alloc == -1)
-		return 0;
-
-	*item = set->list[set->alloc].val;
-	set->trace = set->list[set->alloc].alloc_next;
-
-	return 1;
-}
-
-int setNext(set_t * set, ITEM_TYPE * item)
-{
-	if (set->trace == -1)
-		return 0;
-
-	*item = set->list[set->trace].val;
-	set->trace = set->list[set->trace].alloc_next;
-
-	return 1;
-}
-
-int setDestroy(set_t * set)
-{
-	drm_free(set, sizeof(set_t), DRM_MEM_DRIVER);
-
-	return 1;
-}
-
-/*
- * GLX Hardware Device Driver common code
- * Copyright (C) 1999 Wittawat Yamwong
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * WITTAWAT YAMWONG, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
- * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#define ISFREE(bptr) ((bptr)->free)
-
-memHeap_t *mmInit(int ofs, int size)
-{
-	PMemBlock blocks;
-
-	if (size <= 0)
-		return NULL;
-
-	blocks = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock), DRM_MEM_DRIVER);
-	if (blocks != NULL) {
-		blocks->ofs = ofs;
-		blocks->size = size;
-		blocks->free = 1;
-		return (memHeap_t *) blocks;
-	} else
-		return NULL;
-}
-
-/* Checks if a pointer 'b' is part of the heap 'heap' */
-int mmBlockInHeap(memHeap_t * heap, PMemBlock b)
-{
-	TMemBlock *p;
-
-	if (heap == NULL || b == NULL)
-		return 0;
-
-	p = heap;
-	while (p != NULL && p != b) {
-		p = p->next;
-	}
-	if (p == b)
-		return 1;
-	else
-		return 0;
-}
-
-static TMemBlock *SliceBlock(TMemBlock * p,
-			     int startofs, int size,
-			     int reserved, int alignment)
-{
-	TMemBlock *newblock;
-
-	/* break left */
-	if (startofs > p->ofs) {
-		newblock = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock),
-						    DRM_MEM_DRIVER);
-		newblock->ofs = startofs;
-		newblock->size = p->size - (startofs - p->ofs);
-		newblock->free = 1;
-		newblock->next = p->next;
-		p->size -= newblock->size;
-		p->next = newblock;
-		p = newblock;
-	}
-
-	/* break right */
-	if (size < p->size) {
-		newblock = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock),
-						    DRM_MEM_DRIVER);
-		newblock->ofs = startofs + size;
-		newblock->size = p->size - size;
-		newblock->free = 1;
-		newblock->next = p->next;
-		p->size = size;
-		p->next = newblock;
-	}
-
-	/* p = middle block */
-	p->align = alignment;
-	p->free = 0;
-	p->reserved = reserved;
-	return p;
-}
-
-PMemBlock mmAllocMem(memHeap_t * heap, int size, int align2, int startSearch)
-{
-	int mask, startofs, endofs;
-	TMemBlock *p;
-
-	if (heap == NULL || align2 < 0 || size <= 0)
-		return NULL;
-
-	mask = (1 << align2) - 1;
-	startofs = 0;
-	p = (TMemBlock *) heap;
-	while (p != NULL) {
-		if (ISFREE(p)) {
-			startofs = (p->ofs + mask) & ~mask;
-			if (startofs < startSearch) {
-				startofs = startSearch;
-			}
-			endofs = startofs + size;
-			if (endofs <= (p->ofs + p->size))
-				break;
-		}
-		p = p->next;
-	}
-	if (p == NULL)
-		return NULL;
-	p = SliceBlock(p, startofs, size, 0, mask + 1);
-	p->heap = heap;
-	return p;
-}
-
-static __inline__ int Join2Blocks(TMemBlock * p)
-{
-	if (p->free && p->next && p->next->free) {
-		TMemBlock *q = p->next;
-		p->size += q->size;
-		p->next = q->next;
-		drm_free(q, sizeof(TMemBlock), DRM_MEM_DRIVER);
-		return 1;
-	}
-	return 0;
-}
-
-int mmFreeMem(PMemBlock b)
-{
-	TMemBlock *p, *prev;
-
-	if (b == NULL)
-		return 0;
-	if (b->heap == NULL)
-		return -1;
-
-	p = b->heap;
-	prev = NULL;
-	while (p != NULL && p != b) {
-		prev = p;
-		p = p->next;
-	}
-	if (p == NULL || p->free || p->reserved)
-		return -1;
-
-	p->free = 1;
-	Join2Blocks(p);
-	if (prev)
-		Join2Blocks(prev);
-	return 0;
-}
diff --git a/drivers/char/drm/sis_ds.h b/drivers/char/drm/sis_ds.h
deleted file mode 100644
index 94f2b47..0000000
--- a/drivers/char/drm/sis_ds.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/* sis_ds.h -- Private header for Direct Rendering Manager -*- linux-c -*- 
- * Created: Mon Jan  4 10:05:05 1999 by sclin@sis.com.tw
- */
-/*
- * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
- * All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Sung-Ching Lin <sclin@sis.com.tw>
- *
- */
-
-#ifndef __SIS_DS_H__
-#define __SIS_DS_H__
-
-/* Set Data Structure */
-
-#define SET_SIZE 5000
-
-typedef unsigned long ITEM_TYPE;
-
-typedef struct {
-	ITEM_TYPE val;
-	int alloc_next, free_next;
-} list_item_t;
-
-typedef struct {
-	int alloc;
-	int free;
-	int trace;
-	list_item_t list[SET_SIZE];
-} set_t;
-
-set_t *setInit(void);
-int setAdd(set_t * set, ITEM_TYPE item);
-int setDel(set_t * set, ITEM_TYPE item);
-int setFirst(set_t * set, ITEM_TYPE * item);
-int setNext(set_t * set, ITEM_TYPE * item);
-int setDestroy(set_t * set);
-
-/*
- * GLX Hardware Device Driver common code
- * Copyright (C) 1999 Wittawat Yamwong
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * WITTAWAT YAMWONG, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
- * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-struct mem_block_t {
-	struct mem_block_t *next;
-	struct mem_block_t *heap;
-	int ofs, size;
-	int align;
-	unsigned int free:1;
-	unsigned int reserved:1;
-};
-typedef struct mem_block_t TMemBlock;
-typedef struct mem_block_t *PMemBlock;
-
-/* a heap is just the first block in a chain */
-typedef struct mem_block_t memHeap_t;
-
-static __inline__ int mmBlockSize(PMemBlock b)
-{
-	return b->size;
-}
-
-static __inline__ int mmOffset(PMemBlock b)
-{
-	return b->ofs;
-}
-
-static __inline__ void mmMarkReserved(PMemBlock b)
-{
-	b->reserved = 1;
-}
-
-/*
- * input: total size in bytes
- * return: a heap pointer if OK, NULL if error
- */
-memHeap_t *mmInit(int ofs, int size);
-
-/*
- * Allocate 'size' bytes with 2^align2 bytes alignment,
- * restrict the search to free memory after 'startSearch'
- * depth and back buffers should be in different 4mb banks
- * to get better page hits if possible
- * input:	size = size of block
- *       	align2 = 2^align2 bytes alignment
- *		startSearch = linear offset from start of heap to begin search
- * return: pointer to the allocated block, 0 if error
- */
-PMemBlock mmAllocMem(memHeap_t * heap, int size, int align2, int startSearch);
-
-/*
- * Returns 1 if the block 'b' is part of the heap 'heap'
- */
-int mmBlockInHeap(PMemBlock heap, PMemBlock b);
-
-/*
- * Free block starts at offset
- * input: pointer to a block
- * return: 0 if OK, -1 if error
- */
-int mmFreeMem(PMemBlock b);
-
-/* For debuging purpose. */
-void mmDumpMemInfo(memHeap_t * mmInit);
-
-#endif				/* __SIS_DS_H__ */
diff --git a/drivers/char/drm/sis_mm.c b/drivers/char/drm/sis_mm.c
index 5e9936b..d26f5db 100644
--- a/drivers/char/drm/sis_mm.c
+++ b/drivers/char/drm/sis_mm.c
@@ -1,414 +1,348 @@
-/* sis_mm.c -- Private header for Direct Rendering Manager -*- linux-c -*-
- * Created: Mon Jan  4 10:05:05 1999 by sclin@sis.com.tw
+/**************************************************************************
  *
- * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
- * All rights reserved.
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
+ * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
  *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
  *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
  *
- * Authors:
- *    Sung-Ching Lin <sclin@sis.com.tw>
  *
+ **************************************************************************/
+
+/*
+ * Authors:
+ *    Thomas Hellström <thomas-at-tungstengraphics-dot-com>
  */
 
 #include "drmP.h"
 #include "sis_drm.h"
 #include "sis_drv.h"
-#include "sis_ds.h"
-#if defined(__linux__) && defined(CONFIG_FB_SIS)
+
 #include <video/sisfb.h>
-#endif
 
-#define MAX_CONTEXT 100
 #define VIDEO_TYPE 0
 #define AGP_TYPE 1
 
-typedef struct {
-	int used;
-	int context;
-	set_t *sets[2];		/* 0 for video, 1 for AGP */
-} sis_context_t;
 
-static sis_context_t global_ppriv[MAX_CONTEXT];
+#if defined(CONFIG_FB_SIS)
+/* fb management via fb device */
 
-static int add_alloc_set(int context, int type, unsigned int val)
-{
-	int i, retval = 0;
+#define SIS_MM_ALIGN_SHIFT 0
+#define SIS_MM_ALIGN_MASK 0
 
-	for (i = 0; i < MAX_CONTEXT; i++) {
-		if (global_ppriv[i].used && global_ppriv[i].context == context) {
-			retval = setAdd(global_ppriv[i].sets[type], val);
-			break;
-		}
-	}
-	return retval;
-}
-
-static int del_alloc_set(int context, int type, unsigned int val)
+static void *sis_sman_mm_allocate(void *private, unsigned long size,
+				  unsigned alignment)
 {
-	int i, retval = 0;
+	struct sis_memreq req;
 
-	for (i = 0; i < MAX_CONTEXT; i++) {
-		if (global_ppriv[i].used && global_ppriv[i].context == context) {
-			retval = setDel(global_ppriv[i].sets[type], val);
-			break;
-		}
-	}
-	return retval;
+	req.size = size;
+	sis_malloc(&req);
+	if (req.size == 0)
+		return NULL;
+	else
+		return (void *)~req.offset;
 }
 
-/* fb management via fb device */
-#if defined(__linux__) && defined(CONFIG_FB_SIS)
-
-static int sis_fb_init(DRM_IOCTL_ARGS)
+static void sis_sman_mm_free(void *private, void *ref)
 {
-	return 0;
+	sis_free(~((unsigned long)ref));
 }
 
-static int sis_fb_alloc(DRM_IOCTL_ARGS)
+static void sis_sman_mm_destroy(void *private)
 {
-	drm_sis_mem_t fb;
-	struct sis_memreq req;
-	drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *)data;
-	int retval = 0;
-
-	DRM_COPY_FROM_USER_IOCTL(fb, argp, sizeof(fb));
-
-	req.size = fb.size;
-	sis_malloc(&req);
-	if (req.offset) {
-		/* TODO */
-		fb.offset = req.offset;
-		fb.free = req.offset;
-		if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) {
-			DRM_DEBUG("adding to allocation set fails\n");
-			sis_free(req.offset);
-			retval = DRM_ERR(EINVAL);
-		}
-	} else {
-		fb.offset = 0;
-		fb.size = 0;
-		fb.free = 0;
-	}
-
-	DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb));
-
-	DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, req.offset);
-
-	return retval;
+	;
 }
 
-static int sis_fb_free(DRM_IOCTL_ARGS)
+static unsigned long sis_sman_mm_offset(void *private, void *ref)
 {
-	drm_sis_mem_t fb;
-	int retval = 0;
-
-	DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t __user *) data, sizeof(fb));
-
-	if (!fb.free)
-		return DRM_ERR(EINVAL);
+	return ~((unsigned long)ref);
+}
 
-	if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
-		retval = DRM_ERR(EINVAL);
-	sis_free(fb.free);
+#else /* CONFIG_FB_SIS */
 
-	DRM_DEBUG("free fb, offset = 0x%lx\n", fb.free);
+#define SIS_MM_ALIGN_SHIFT 4
+#define SIS_MM_ALIGN_MASK ( (1 << SIS_MM_ALIGN_SHIFT) - 1)
 
-	return retval;
-}
+#endif /* CONFIG_FB_SIS */
 
-#else
-
-/* Called by the X Server to initialize the FB heap.  Allocations will fail
- * unless this is called.  Offset is the beginning of the heap from the
- * framebuffer offset (MaxXFBMem in XFree86).
- *
- * Memory layout according to Thomas Winischofer:
- * |------------------|DDDDDDDDDDDDDDDDDDDDDDDDDDDDD|HHHH|CCCCCCCCCCC|
- *
- *    X driver/sisfb                                  HW-   Command-
- *  framebuffer memory           DRI heap           Cursor   queue
- */
 static int sis_fb_init(DRM_IOCTL_ARGS)
 {
 	DRM_DEVICE;
 	drm_sis_private_t *dev_priv = dev->dev_private;
 	drm_sis_fb_t fb;
+	int ret;
 
 	DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_fb_t __user *) data, sizeof(fb));
 
-	if (dev_priv == NULL) {
-		dev->dev_private = drm_calloc(1, sizeof(drm_sis_private_t),
-					      DRM_MEM_DRIVER);
-		dev_priv = dev->dev_private;
-		if (dev_priv == NULL)
-			return ENOMEM;
+	mutex_lock(&dev->struct_mutex);
+#if defined(CONFIG_FB_SIS)
+	{
+		drm_sman_mm_t sman_mm;
+		sman_mm.private = (void *)0xFFFFFFFF;
+		sman_mm.allocate = sis_sman_mm_allocate;
+		sman_mm.free = sis_sman_mm_free;
+		sman_mm.destroy = sis_sman_mm_destroy;
+		sman_mm.offset = sis_sman_mm_offset;
+		ret =
+		    drm_sman_set_manager(&dev_priv->sman, VIDEO_TYPE, &sman_mm);
 	}
+#else
+	ret = drm_sman_set_range(&dev_priv->sman, VIDEO_TYPE, 0,
+				 fb.size >> SIS_MM_ALIGN_SHIFT);
+#endif
 
-	if (dev_priv->FBHeap != NULL)
-		return DRM_ERR(EINVAL);
+	if (ret) {
+		DRM_ERROR("VRAM memory manager initialisation error\n");
+		mutex_unlock(&dev->struct_mutex);
+		return ret;
+	}
 
-	dev_priv->FBHeap = mmInit(fb.offset, fb.size);
+	dev_priv->vram_initialized = 1;
+	dev_priv->vram_offset = fb.offset;
 
+	mutex_unlock(&dev->struct_mutex);
 	DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
 
 	return 0;
 }
 
-static int sis_fb_alloc(DRM_IOCTL_ARGS)
+static int sis_drm_alloc(drm_device_t * dev, drm_file_t * priv,
+			 unsigned long data, int pool)
 {
-	DRM_DEVICE;
 	drm_sis_private_t *dev_priv = dev->dev_private;
-	drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *)data;
-	drm_sis_mem_t fb;
-	PMemBlock block;
+	drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *) data;
+	drm_sis_mem_t mem;
 	int retval = 0;
+	drm_memblock_item_t *item;
+
+	DRM_COPY_FROM_USER_IOCTL(mem, argp, sizeof(mem));
 
-	if (dev_priv == NULL || dev_priv->FBHeap == NULL)
+	mutex_lock(&dev->struct_mutex);
+
+	if (0 == ((pool == 0) ? dev_priv->vram_initialized :
+		      dev_priv->agp_initialized)) {
+		DRM_ERROR
+		    ("Attempt to allocate from uninitialized memory manager.\n");
 		return DRM_ERR(EINVAL);
+	}
 
-	DRM_COPY_FROM_USER_IOCTL(fb, argp, sizeof(fb));
-
-	block = mmAllocMem(dev_priv->FBHeap, fb.size, 0, 0);
-	if (block) {
-		/* TODO */
-		fb.offset = block->ofs;
-		fb.free = (unsigned long)block;
-		if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) {
-			DRM_DEBUG("adding to allocation set fails\n");
-			mmFreeMem((PMemBlock) fb.free);
-			retval = DRM_ERR(EINVAL);
-		}
+	mem.size = (mem.size + SIS_MM_ALIGN_MASK) >> SIS_MM_ALIGN_SHIFT;
+	item = drm_sman_alloc(&dev_priv->sman, pool, mem.size, 0,
+			      (unsigned long)priv);
+
+	mutex_unlock(&dev->struct_mutex);
+	if (item) {
+		mem.offset = ((pool == 0) ?
+			      dev_priv->vram_offset : dev_priv->agp_offset) +
+		    (item->mm->
+		     offset(item->mm, item->mm_info) << SIS_MM_ALIGN_SHIFT);
+		mem.free = item->user_hash.key;
+		mem.size = mem.size << SIS_MM_ALIGN_SHIFT;
 	} else {
-		fb.offset = 0;
-		fb.size = 0;
-		fb.free = 0;
+		mem.offset = 0;
+		mem.size = 0;
+		mem.free = 0;
+		retval = DRM_ERR(ENOMEM);
 	}
 
-	DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb));
+	DRM_COPY_TO_USER_IOCTL(argp, mem, sizeof(mem));
 
-	DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, fb.offset);
+	DRM_DEBUG("alloc %d, size = %d, offset = %d\n", pool, mem.size,
+		  mem.offset);
 
 	return retval;
 }
 
-static int sis_fb_free(DRM_IOCTL_ARGS)
+static int sis_drm_free(DRM_IOCTL_ARGS)
 {
 	DRM_DEVICE;
 	drm_sis_private_t *dev_priv = dev->dev_private;
-	drm_sis_mem_t fb;
+	drm_sis_mem_t mem;
+	int ret;
 
-	if (dev_priv == NULL || dev_priv->FBHeap == NULL)
-		return DRM_ERR(EINVAL);
+	DRM_COPY_FROM_USER_IOCTL(mem, (drm_sis_mem_t __user *) data,
+				 sizeof(mem));
 
-	DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t __user *) data, sizeof(fb));
+	mutex_lock(&dev->struct_mutex);
+	ret = drm_sman_free_key(&dev_priv->sman, mem.free);
+	mutex_unlock(&dev->struct_mutex);
+	DRM_DEBUG("free = 0x%lx\n", mem.free);
 
-	if (!mmBlockInHeap(dev_priv->FBHeap, (PMemBlock) fb.free))
-		return DRM_ERR(EINVAL);
-
-	if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
-		return DRM_ERR(EINVAL);
-	mmFreeMem((PMemBlock) fb.free);
-
-	DRM_DEBUG("free fb, free = 0x%lx\n", fb.free);
-
-	return 0;
+	return ret;
 }
 
-#endif
-
-/* agp memory management */
+static int sis_fb_alloc(DRM_IOCTL_ARGS)
+{
+	DRM_DEVICE;
+	return sis_drm_alloc(dev, priv, data, VIDEO_TYPE);
+}
 
 static int sis_ioctl_agp_init(DRM_IOCTL_ARGS)
 {
 	DRM_DEVICE;
 	drm_sis_private_t *dev_priv = dev->dev_private;
 	drm_sis_agp_t agp;
-
-	if (dev_priv == NULL) {
-		dev->dev_private = drm_calloc(1, sizeof(drm_sis_private_t),
-					      DRM_MEM_DRIVER);
-		dev_priv = dev->dev_private;
-		if (dev_priv == NULL)
-			return ENOMEM;
-	}
-
-	if (dev_priv->AGPHeap != NULL)
-		return DRM_ERR(EINVAL);
+	int ret;
+	dev_priv = dev->dev_private;
 
 	DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_agp_t __user *) data,
 				 sizeof(agp));
+	mutex_lock(&dev->struct_mutex);
+	ret = drm_sman_set_range(&dev_priv->sman, AGP_TYPE, 0,
+				 agp.size >> SIS_MM_ALIGN_SHIFT);
+
+	if (ret) {
+		DRM_ERROR("AGP memory manager initialisation error\n");
+		mutex_unlock(&dev->struct_mutex);
+		return ret;
+	}
 
-	dev_priv->AGPHeap = mmInit(agp.offset, agp.size);
+	dev_priv->agp_initialized = 1;
+	dev_priv->agp_offset = agp.offset;
+	mutex_unlock(&dev->struct_mutex);
 
 	DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
-
 	return 0;
 }
 
 static int sis_ioctl_agp_alloc(DRM_IOCTL_ARGS)
 {
 	DRM_DEVICE;
-	drm_sis_private_t *dev_priv = dev->dev_private;
-	drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *)data;
-	drm_sis_mem_t agp;
-	PMemBlock block;
-	int retval = 0;
 
-	if (dev_priv == NULL || dev_priv->AGPHeap == NULL)
-		return DRM_ERR(EINVAL);
+	return sis_drm_alloc(dev, priv, data, AGP_TYPE);
+}
 
-	DRM_COPY_FROM_USER_IOCTL(agp, argp, sizeof(agp));
-
-	block = mmAllocMem(dev_priv->AGPHeap, agp.size, 0, 0);
-	if (block) {
-		/* TODO */
-		agp.offset = block->ofs;
-		agp.free = (unsigned long)block;
-		if (!add_alloc_set(agp.context, AGP_TYPE, agp.free)) {
-			DRM_DEBUG("adding to allocation set fails\n");
-			mmFreeMem((PMemBlock) agp.free);
-			retval = -1;
+static drm_local_map_t *sis_reg_init(drm_device_t *dev)
+{
+	drm_map_list_t *entry;
+	drm_local_map_t *map;
+
+	list_for_each_entry(entry, &dev->maplist->head, head) {
+		map = entry->map;
+		if (!map)
+			continue;
+		if (map->type == _DRM_REGISTERS) {
+			return map;
 		}
-	} else {
-		agp.offset = 0;
-		agp.size = 0;
-		agp.free = 0;
 	}
-
-	DRM_COPY_TO_USER_IOCTL(argp, agp, sizeof(agp));
-
-	DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, agp.offset);
-
-	return retval;
+	return NULL;
 }
 
-static int sis_ioctl_agp_free(DRM_IOCTL_ARGS)
+int sis_idle(drm_device_t *dev)
 {
-	DRM_DEVICE;
 	drm_sis_private_t *dev_priv = dev->dev_private;
-	drm_sis_mem_t agp;
-
-	if (dev_priv == NULL || dev_priv->AGPHeap == NULL)
-		return DRM_ERR(EINVAL);
+	uint32_t idle_reg;
+	unsigned long end;
+	int i;
 
-	DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_mem_t __user *) data,
-				 sizeof(agp));
+	if (dev_priv->idle_fault)
+		return 0;
 
-	if (!mmBlockInHeap(dev_priv->AGPHeap, (PMemBlock) agp.free))
-		return DRM_ERR(EINVAL);
+	if (dev_priv->mmio == NULL) {
+		dev_priv->mmio = sis_reg_init(dev);
+		if (dev_priv->mmio == NULL) {
+			DRM_ERROR("Could not find register map.\n");
+			return 0;
+		}
+	}
+	
+	/*
+	 * Implement a device switch here if needed
+	 */
+
+	if (dev_priv->chipset != SIS_CHIP_315)
+		return 0;
+
+	/*
+	 * Timeout after 3 seconds. We cannot use DRM_WAIT_ON here
+	 * because its polling frequency is too low.
+	 */
+
+	end = jiffies + (DRM_HZ * 3);
+
+	for (i=0; i<4; ++i) {
+		do {
+			idle_reg = SIS_READ(0x85cc);
+		} while ( !time_after_eq(jiffies, end) &&
+			  ((idle_reg & 0x80000000) != 0x80000000));
+	}
 
-	mmFreeMem((PMemBlock) agp.free);
-	if (!del_alloc_set(agp.context, AGP_TYPE, agp.free))
-		return DRM_ERR(EINVAL);
+	if (time_after_eq(jiffies, end)) {
+		DRM_ERROR("Graphics engine idle timeout. "
+			  "Disabling idle check\n");
+		dev_priv->idle_fault = 1;
+	}
 
-	DRM_DEBUG("free agp, free = 0x%lx\n", agp.free);
+	/*
+	 * The caller never sees an error code. It gets trapped
+	 * in libdrm.
+	 */
 
 	return 0;
 }
 
-int sis_init_context(struct drm_device *dev, int context)
-{
-	int i;
 
-	for (i = 0; i < MAX_CONTEXT; i++) {
-		if (global_ppriv[i].used &&
-		    (global_ppriv[i].context == context))
-			break;
-	}
+void sis_lastclose(struct drm_device *dev)
+{
+	drm_sis_private_t *dev_priv = dev->dev_private;
 
-	if (i >= MAX_CONTEXT) {
-		for (i = 0; i < MAX_CONTEXT; i++) {
-			if (!global_ppriv[i].used) {
-				global_ppriv[i].context = context;
-				global_ppriv[i].used = 1;
-				global_ppriv[i].sets[0] = setInit();
-				global_ppriv[i].sets[1] = setInit();
-				DRM_DEBUG("init allocation set, socket=%d, "
-					  "context = %d\n", i, context);
-				break;
-			}
-		}
-		if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) ||
-		    (global_ppriv[i].sets[1] == NULL)) {
-			return 0;
-		}
-	}
+	if (!dev_priv)
+		return;
 
-	return 1;
+	mutex_lock(&dev->struct_mutex);
+	drm_sman_cleanup(&dev_priv->sman);
+	dev_priv->vram_initialized = 0;
+	dev_priv->agp_initialized = 0;
+	dev_priv->mmio = NULL;
+	mutex_unlock(&dev->struct_mutex);
 }
 
-int sis_final_context(struct drm_device *dev, int context)
+void sis_reclaim_buffers_locked(drm_device_t * dev, struct file *filp)
 {
-	int i;
+	drm_sis_private_t *dev_priv = dev->dev_private;
+	drm_file_t *priv = filp->private_data;
 
-	for (i = 0; i < MAX_CONTEXT; i++) {
-		if (global_ppriv[i].used &&
-		    (global_ppriv[i].context == context))
-			break;
+	mutex_lock(&dev->struct_mutex);
+	if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
+		mutex_unlock(&dev->struct_mutex);
+		return;
 	}
 
-	if (i < MAX_CONTEXT) {
-		set_t *set;
-		ITEM_TYPE item;
-		int retval;
-
-		DRM_DEBUG("find socket %d, context = %d\n", i, context);
-
-		/* Video Memory */
-		set = global_ppriv[i].sets[0];
-		retval = setFirst(set, &item);
-		while (retval) {
-			DRM_DEBUG("free video memory 0x%lx\n", item);
-#if defined(__linux__) && defined(CONFIG_FB_SIS)
-			sis_free(item);
-#else
-			mmFreeMem((PMemBlock) item);
-#endif
-			retval = setNext(set, &item);
-		}
-		setDestroy(set);
-
-		/* AGP Memory */
-		set = global_ppriv[i].sets[1];
-		retval = setFirst(set, &item);
-		while (retval) {
-			DRM_DEBUG("free agp memory 0x%lx\n", item);
-			mmFreeMem((PMemBlock) item);
-			retval = setNext(set, &item);
-		}
-		setDestroy(set);
-
-		global_ppriv[i].used = 0;
+	if (dev->driver->dma_quiescent) {
+		dev->driver->dma_quiescent(dev);
 	}
 
-	return 1;
+	drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv);
+	mutex_unlock(&dev->struct_mutex);
+	return;
 }
 
 drm_ioctl_desc_t sis_ioctls[] = {
 	[DRM_IOCTL_NR(DRM_SIS_FB_ALLOC)] = {sis_fb_alloc, DRM_AUTH},
-	[DRM_IOCTL_NR(DRM_SIS_FB_FREE)] = {sis_fb_free, DRM_AUTH},
-	[DRM_IOCTL_NR(DRM_SIS_AGP_INIT)] = {sis_ioctl_agp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
+	[DRM_IOCTL_NR(DRM_SIS_FB_FREE)] = {sis_drm_free, DRM_AUTH},
+	[DRM_IOCTL_NR(DRM_SIS_AGP_INIT)] =
+	    {sis_ioctl_agp_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY},
 	[DRM_IOCTL_NR(DRM_SIS_AGP_ALLOC)] = {sis_ioctl_agp_alloc, DRM_AUTH},
-	[DRM_IOCTL_NR(DRM_SIS_AGP_FREE)] = {sis_ioctl_agp_free, DRM_AUTH},
-	[DRM_IOCTL_NR(DRM_SIS_FB_INIT)] = {sis_fb_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}
+	[DRM_IOCTL_NR(DRM_SIS_AGP_FREE)] = {sis_drm_free, DRM_AUTH},
+	[DRM_IOCTL_NR(DRM_SIS_FB_INIT)] =
+	    {sis_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY}
 };
 
 int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls);
diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c
index 78a81a4..60c1695 100644
--- a/drivers/char/drm/via_dmablit.c
+++ b/drivers/char/drm/via_dmablit.c
@@ -41,9 +41,9 @@ #include "via_dmablit.h"
 
 #include <linux/pagemap.h>
 
-#define VIA_PGDN(x)             (((unsigned long)(x)) & PAGE_MASK)
-#define VIA_PGOFF(x)            (((unsigned long)(x)) & ~PAGE_MASK)
-#define VIA_PFN(x)              ((unsigned long)(x) >> PAGE_SHIFT)
+#define VIA_PGDN(x)	     (((unsigned long)(x)) & PAGE_MASK)
+#define VIA_PGOFF(x)	    (((unsigned long)(x)) & ~PAGE_MASK)
+#define VIA_PFN(x)	      ((unsigned long)(x) >> PAGE_SHIFT)
 
 typedef struct _drm_via_descriptor {
 	uint32_t mem_addr;
@@ -121,19 +121,19 @@ via_map_blit_for_device(struct pci_dev *
 		
 		while (line_len > 0) {
 
-                        remaining_len = min(PAGE_SIZE-VIA_PGOFF(cur_mem), line_len);
+			remaining_len = min(PAGE_SIZE-VIA_PGOFF(cur_mem), line_len);
 			line_len -= remaining_len;
 
 			if (mode == 1) {
-                                desc_ptr->mem_addr = 
+				desc_ptr->mem_addr = 
 					dma_map_page(&pdev->dev, 
 						     vsg->pages[VIA_PFN(cur_mem) - 
 								VIA_PFN(first_addr)],
 						     VIA_PGOFF(cur_mem), remaining_len, 
 						     vsg->direction);
-                                desc_ptr->dev_addr = cur_fb;
+				desc_ptr->dev_addr = cur_fb;
 				
-                                desc_ptr->size = remaining_len;
+				desc_ptr->size = remaining_len;
 				desc_ptr->next = (uint32_t) next;
 				next = dma_map_single(&pdev->dev, desc_ptr, sizeof(*desc_ptr), 
 						      DMA_TO_DEVICE);
@@ -162,7 +162,7 @@ via_map_blit_for_device(struct pci_dev *
 
 /*
  * Function that frees up all resources for a blit. It is usable even if the 
- * blit info has only be partially built as long as the status enum is consistent
+ * blit info has only been partially built as long as the status enum is consistent
  * with the actual status of the used resources.
  */
 
@@ -238,8 +238,11 @@ via_lock_all_dma_pages(drm_via_sg_info_t
 		return DRM_ERR(ENOMEM);
 	memset(vsg->pages, 0, sizeof(struct page *) * vsg->num_pages);
 	down_read(&current->mm->mmap_sem);
-	ret = get_user_pages(current, current->mm, (unsigned long) xfer->mem_addr,
-			     vsg->num_pages, vsg->direction, 0, vsg->pages, NULL);
+	ret = get_user_pages(current, current->mm,
+			     (unsigned long)xfer->mem_addr,
+			     vsg->num_pages,
+			     (vsg->direction == DMA_FROM_DEVICE),
+			     0, vsg->pages, NULL);
 
 	up_read(&current->mm->mmap_sem);
 	if (ret != vsg->num_pages) {
@@ -475,9 +478,15 @@ via_dmablit_timer(unsigned long data)
 	if (!timer_pending(&blitq->poll_timer)) {
 		blitq->poll_timer.expires = jiffies+1;
 		add_timer(&blitq->poll_timer);
-	}
-	via_dmablit_handler(dev, engine, 0);
 
+	       /*
+		* Rerun handler to delete timer if engines are off, and
+		* to shorten abort latency. This is a little nasty.
+		*/
+
+	       via_dmablit_handler(dev, engine, 0);
+
+	}
 }
 
 
@@ -597,15 +606,27 @@ via_build_sg_info(drm_device_t *dev, drm
 	 * (Not a big limitation anyway.)
 	 */
 
-	if (((xfer->mem_stride - xfer->line_length) >= PAGE_SIZE) ||
-	    (xfer->mem_stride > 2048*4)) {
+	if ((xfer->mem_stride - xfer->line_length) >= PAGE_SIZE) {
 		DRM_ERROR("Too large system memory stride. Stride: %d, "
 			  "Length: %d\n", xfer->mem_stride, xfer->line_length);
 		return DRM_ERR(EINVAL);
 	}
 
-	if (xfer->num_lines > 2048) {
-		DRM_ERROR("Too many PCI DMA bitblt lines.\n");
+	if ((xfer->mem_stride == xfer->line_length) &&
+	   (xfer->fb_stride == xfer->line_length)) {
+		xfer->mem_stride *= xfer->num_lines;
+		xfer->line_length = xfer->mem_stride;
+		xfer->fb_stride = xfer->mem_stride;
+		xfer->num_lines = 1;
+	}
+
+	/*
+	 * Don't lock an arbitrary large number of pages, since that causes a
+	 * DOS security hole.
+	 */
+
+	if (xfer->num_lines > 2048 || (xfer->num_lines*xfer->mem_stride > (2048*2048*4))) {
+		DRM_ERROR("Too large PCI DMA bitblt.\n");
 		return DRM_ERR(EINVAL);
 	}		
 
@@ -628,16 +649,17 @@ via_build_sg_info(drm_device_t *dev, drm
 
 #ifdef VIA_BUGFREE
 	if ((((unsigned long)xfer->mem_addr & 3) != ((unsigned long)xfer->fb_addr & 3)) ||
-	    ((xfer->mem_stride & 3) != (xfer->fb_stride & 3))) {
+	    ((xfer->num_lines > 1) && ((xfer->mem_stride & 3) != (xfer->fb_stride & 3)))) {
 		DRM_ERROR("Invalid DRM bitblt alignment.\n");
-	        return DRM_ERR(EINVAL);
+		return DRM_ERR(EINVAL);
 	}
 #else
 	if ((((unsigned long)xfer->mem_addr & 15) ||
-	    ((unsigned long)xfer->fb_addr & 3)) || (xfer->mem_stride & 15) ||
-	    (xfer->fb_stride & 3)) {
+	      ((unsigned long)xfer->fb_addr & 3)) ||
+	   ((xfer->num_lines > 1) && 
+	   ((xfer->mem_stride & 15) || (xfer->fb_stride & 3)))) {
 		DRM_ERROR("Invalid DRM bitblt alignment.\n");
-	        return DRM_ERR(EINVAL);
+		return DRM_ERR(EINVAL);
 	}	
 #endif
 
@@ -715,7 +737,7 @@ via_dmablit(drm_device_t *dev, drm_via_d
 	drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
 	drm_via_sg_info_t *vsg;
 	drm_via_blitq_t *blitq;
-        int ret;
+	int ret;
 	int engine;
 	unsigned long irqsave;
 
@@ -756,7 +778,7 @@ via_dmablit(drm_device_t *dev, drm_via_d
 
 /*
  * Sync on a previously submitted blit. Note that the X server use signals extensively, and
- * that there is a very big proability that this IOCTL will be interrupted by a signal. In that
+ * that there is a very big probability that this IOCTL will be interrupted by a signal. In that
  * case it returns with -EAGAIN for the signal to be delivered. 
  * The caller should then reissue the IOCTL. This is similar to what is being done for drmGetLock().
  */
diff --git a/drivers/char/drm/via_drm.h b/drivers/char/drm/via_drm.h
index 47f0b5b..e4ee97d 100644
--- a/drivers/char/drm/via_drm.h
+++ b/drivers/char/drm/via_drm.h
@@ -250,6 +250,12 @@ typedef struct drm_via_blitsync {
 	unsigned engine;
 } drm_via_blitsync_t;
 
+/* - * Below,"flags" is currently unused but will be used for possible future
+ * extensions like kernel space bounce buffers for bad alignments and
+ * blit engine busy-wait polling for better latency in the absence of
+ * interrupts.
+ */
+
 typedef struct drm_via_dmablit {
 	uint32_t num_lines;
 	uint32_t line_length;
@@ -260,7 +266,7 @@ typedef struct drm_via_dmablit {
 	unsigned char *mem_addr;
 	uint32_t mem_stride;
 
-	int bounce_buffer;
+	uint32_t flags;
 	int to_fb;
 
 	drm_via_blitsync_t sync;
diff --git a/drivers/char/drm/via_drv.c b/drivers/char/drm/via_drv.c
index b3d364d..bb9dde8 100644
--- a/drivers/char/drm/via_drv.c
+++ b/drivers/char/drm/via_drv.c
@@ -43,7 +43,6 @@ static struct drm_driver driver = {
 	    DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
 	.load = via_driver_load,
 	.unload = via_driver_unload,
-	.context_ctor = via_init_context,
 	.context_dtor = via_final_context,
 	.vblank_wait = via_driver_vblank_wait,
 	.irq_preinstall = via_driver_irq_preinstall,
@@ -53,6 +52,8 @@ static struct drm_driver driver = {
 	.dma_quiescent = via_driver_dma_quiescent,
 	.dri_library_name = dri_library_name,
 	.reclaim_buffers = drm_core_reclaim_buffers,
+	.reclaim_buffers_locked = via_reclaim_buffers_locked,
+	.lastclose = via_lastclose,
 	.get_map_ofs = drm_core_get_map_ofs,
 	.get_reg_ofs = drm_core_get_reg_ofs,
 	.ioctls = via_ioctls,
diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h
index 52bcc7b..d21b5b7 100644
--- a/drivers/char/drm/via_drv.h
+++ b/drivers/char/drm/via_drv.h
@@ -24,15 +24,16 @@
 #ifndef _VIA_DRV_H_
 #define _VIA_DRV_H_
 
+#include "drm_sman.h"
 #define DRIVER_AUTHOR	"Various"
 
 #define DRIVER_NAME		"via"
 #define DRIVER_DESC		"VIA Unichrome / Pro"
-#define DRIVER_DATE		"20051116"
+#define DRIVER_DATE		"20060529"
 
 #define DRIVER_MAJOR		2
-#define DRIVER_MINOR		7
-#define DRIVER_PATCHLEVEL	4
+#define DRIVER_MINOR		10
+#define DRIVER_PATCHLEVEL	0
 
 #include "via_verifier.h"
 
@@ -85,6 +86,12 @@ typedef struct drm_via_private {
 	uint32_t irq_enable_mask;
 	uint32_t irq_pending_mask;
 	int *irq_map;
+	unsigned int idle_fault;
+	drm_sman_t sman;
+	int vram_initialized;
+	int agp_initialized;
+	unsigned long vram_offset;
+	unsigned long agp_offset;
 	drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES];
 } drm_via_private_t;
 
@@ -135,6 +142,9 @@ extern void via_init_futex(drm_via_priva
 extern void via_cleanup_futex(drm_via_private_t * dev_priv);
 extern void via_release_futex(drm_via_private_t * dev_priv, int context);
 
+extern void via_reclaim_buffers_locked(drm_device_t *dev, struct file *filp);
+extern void via_lastclose(drm_device_t *dev);
+
 extern void via_dmablit_handler(drm_device_t *dev, int engine, int from_irq);
 extern void via_init_dmablit(drm_device_t *dev);
 
diff --git a/drivers/char/drm/via_ds.c b/drivers/char/drm/via_ds.c
deleted file mode 100644
index 9429736..0000000
--- a/drivers/char/drm/via_ds.c
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
- * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
- * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sub license,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-#include "drmP.h"
-
-#include "via_ds.h"
-extern unsigned int VIA_DEBUG;
-
-set_t *via_setInit(void)
-{
-	int i;
-	set_t *set;
-	set = (set_t *) drm_alloc(sizeof(set_t), DRM_MEM_DRIVER);
-	for (i = 0; i < SET_SIZE; i++) {
-		set->list[i].free_next = i + 1;
-		set->list[i].alloc_next = -1;
-	}
-	set->list[SET_SIZE - 1].free_next = -1;
-	set->free = 0;
-	set->alloc = -1;
-	set->trace = -1;
-	return set;
-}
-
-int via_setAdd(set_t * set, ITEM_TYPE item)
-{
-	int free = set->free;
-	if (free != -1) {
-		set->list[free].val = item;
-		set->free = set->list[free].free_next;
-	} else {
-		return 0;
-	}
-	set->list[free].alloc_next = set->alloc;
-	set->alloc = free;
-	set->list[free].free_next = -1;
-	return 1;
-}
-
-int via_setDel(set_t * set, ITEM_TYPE item)
-{
-	int alloc = set->alloc;
-	int prev = -1;
-
-	while (alloc != -1) {
-		if (set->list[alloc].val == item) {
-			if (prev != -1)
-				set->list[prev].alloc_next =
-				    set->list[alloc].alloc_next;
-			else
-				set->alloc = set->list[alloc].alloc_next;
-			break;
-		}
-		prev = alloc;
-		alloc = set->list[alloc].alloc_next;
-	}
-
-	if (alloc == -1)
-		return 0;
-
-	set->list[alloc].free_next = set->free;
-	set->free = alloc;
-	set->list[alloc].alloc_next = -1;
-
-	return 1;
-}
-
-/* setFirst -> setAdd -> setNext is wrong */
-
-int via_setFirst(set_t * set, ITEM_TYPE * item)
-{
-	if (set->alloc == -1)
-		return 0;
-
-	*item = set->list[set->alloc].val;
-	set->trace = set->list[set->alloc].alloc_next;
-
-	return 1;
-}
-
-int via_setNext(set_t * set, ITEM_TYPE * item)
-{
-	if (set->trace == -1)
-		return 0;
-
-	*item = set->list[set->trace].val;
-	set->trace = set->list[set->trace].alloc_next;
-
-	return 1;
-}
-
-int via_setDestroy(set_t * set)
-{
-	drm_free(set, sizeof(set_t), DRM_MEM_DRIVER);
-
-	return 1;
-}
-
-#define ISFREE(bptr) ((bptr)->free)
-
-#define fprintf(fmt, arg...) do{}while(0)
-
-memHeap_t *via_mmInit(int ofs, int size)
-{
-	PMemBlock blocks;
-
-	if (size <= 0)
-		return NULL;
-
-	blocks = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock), DRM_MEM_DRIVER);
-
-	if (blocks) {
-		blocks->ofs = ofs;
-		blocks->size = size;
-		blocks->free = 1;
-		return (memHeap_t *) blocks;
-	} else
-		return NULL;
-}
-
-static TMemBlock *SliceBlock(TMemBlock * p,
-			     int startofs, int size,
-			     int reserved, int alignment)
-{
-	TMemBlock *newblock;
-
-	/* break left */
-	if (startofs > p->ofs) {
-		newblock =
-		    (TMemBlock *) drm_calloc(1, sizeof(TMemBlock),
-					     DRM_MEM_DRIVER);
-		newblock->ofs = startofs;
-		newblock->size = p->size - (startofs - p->ofs);
-		newblock->free = 1;
-		newblock->next = p->next;
-		p->size -= newblock->size;
-		p->next = newblock;
-		p = newblock;
-	}
-
-	/* break right */
-	if (size < p->size) {
-		newblock =
-		    (TMemBlock *) drm_calloc(1, sizeof(TMemBlock),
-					     DRM_MEM_DRIVER);
-		newblock->ofs = startofs + size;
-		newblock->size = p->size - size;
-		newblock->free = 1;
-		newblock->next = p->next;
-		p->size = size;
-		p->next = newblock;
-	}
-
-	/* p = middle block */
-	p->align = alignment;
-	p->free = 0;
-	p->reserved = reserved;
-	return p;
-}
-
-PMemBlock via_mmAllocMem(memHeap_t * heap, int size, int align2,
-			 int startSearch)
-{
-	int mask, startofs, endofs;
-	TMemBlock *p;
-
-	if (!heap || align2 < 0 || size <= 0)
-		return NULL;
-
-	mask = (1 << align2) - 1;
-	startofs = 0;
-	p = (TMemBlock *) heap;
-
-	while (p) {
-		if (ISFREE(p)) {
-			startofs = (p->ofs + mask) & ~mask;
-
-			if (startofs < startSearch)
-				startofs = startSearch;
-
-			endofs = startofs + size;
-
-			if (endofs <= (p->ofs + p->size))
-				break;
-		}
-
-		p = p->next;
-	}
-
-	if (!p)
-		return NULL;
-
-	p = SliceBlock(p, startofs, size, 0, mask + 1);
-	p->heap = heap;
-
-	return p;
-}
-
-static __inline__ int Join2Blocks(TMemBlock * p)
-{
-	if (p->free && p->next && p->next->free) {
-		TMemBlock *q = p->next;
-		p->size += q->size;
-		p->next = q->next;
-		drm_free(q, sizeof(TMemBlock), DRM_MEM_DRIVER);
-
-		return 1;
-	}
-
-	return 0;
-}
-
-int via_mmFreeMem(PMemBlock b)
-{
-	TMemBlock *p, *prev;
-
-	if (!b)
-		return 0;
-
-	if (!b->heap) {
-		fprintf(stderr, "no heap\n");
-
-		return -1;
-	}
-
-	p = b->heap;
-	prev = NULL;
-
-	while (p && p != b) {
-		prev = p;
-		p = p->next;
-	}
-
-	if (!p || p->free || p->reserved) {
-		if (!p)
-			fprintf(stderr, "block not found in heap\n");
-		else if (p->free)
-			fprintf(stderr, "block already free\n");
-		else
-			fprintf(stderr, "block is reserved\n");
-
-		return -1;
-	}
-
-	p->free = 1;
-	Join2Blocks(p);
-
-	if (prev)
-		Join2Blocks(prev);
-
-	return 0;
-}
diff --git a/drivers/char/drm/via_ds.h b/drivers/char/drm/via_ds.h
deleted file mode 100644
index d2bb9f3..0000000
--- a/drivers/char/drm/via_ds.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
- * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
- * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
- * All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sub license,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-#ifndef _via_ds_h_
-#define _via_ds_h_
-
-#include "drmP.h"
-
-/* Set Data Structure */
-#define SET_SIZE 5000
-typedef unsigned long ITEM_TYPE;
-
-typedef struct {
-	ITEM_TYPE val;
-	int alloc_next, free_next;
-} list_item_t;
-
-typedef struct {
-	int alloc;
-	int free;
-	int trace;
-	list_item_t list[SET_SIZE];
-} set_t;
-
-set_t *via_setInit(void);
-int via_setAdd(set_t * set, ITEM_TYPE item);
-int via_setDel(set_t * set, ITEM_TYPE item);
-int via_setFirst(set_t * set, ITEM_TYPE * item);
-int via_setNext(set_t * set, ITEM_TYPE * item);
-int via_setDestroy(set_t * set);
-
-#endif
-
-#ifndef MM_INC
-#define MM_INC
-
-struct mem_block_t {
-	struct mem_block_t *next;
-	struct mem_block_t *heap;
-	int ofs, size;
-	int align;
-	unsigned int free:1;
-	unsigned int reserved:1;
-};
-typedef struct mem_block_t TMemBlock;
-typedef struct mem_block_t *PMemBlock;
-
-/* a heap is just the first block in a chain */
-typedef struct mem_block_t memHeap_t;
-
-static __inline__ int mmBlockSize(PMemBlock b)
-{
-	return b->size;
-}
-
-static __inline__ int mmOffset(PMemBlock b)
-{
-	return b->ofs;
-}
-
-static __inline__ void mmMarkReserved(PMemBlock b)
-{
-	b->reserved = 1;
-}
-
-/*
- * input: total size in bytes
- * return: a heap pointer if OK, NULL if error
- */
-memHeap_t *via_mmInit(int ofs, int size);
-
-PMemBlock via_mmAllocMem(memHeap_t * heap, int size, int align2,
-			 int startSearch);
-
-/*
- * Free block starts at offset
- * input: pointer to a block
- * return: 0 if OK, -1 if error
- */
-int via_mmFreeMem(PMemBlock b);
-
-#endif
diff --git a/drivers/char/drm/via_map.c b/drivers/char/drm/via_map.c
index c6a08e9..782011e 100644
--- a/drivers/char/drm/via_map.c
+++ b/drivers/char/drm/via_map.c
@@ -98,6 +98,7 @@ int via_map_init(DRM_IOCTL_ARGS)
 int via_driver_load(drm_device_t *dev, unsigned long chipset)
 {
 	drm_via_private_t *dev_priv;
+	int ret = 0;
 
 	dev_priv = drm_calloc(1, sizeof(drm_via_private_t), DRM_MEM_DRIVER);
 	if (dev_priv == NULL)
@@ -108,13 +109,19 @@ int via_driver_load(drm_device_t *dev, u
 	if (chipset == VIA_PRO_GROUP_A)
 		dev_priv->pro_group_a = 1;
 
-	return 0;
+	ret = drm_sman_init(&dev_priv->sman, 2, 12, 8);
+	if (ret) {
+		drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
+	}
+	return ret;
 }
 
 int via_driver_unload(drm_device_t *dev)
 {
 	drm_via_private_t *dev_priv = dev->dev_private;
 
+	drm_sman_takedown(&dev_priv->sman);
+
 	drm_free(dev_priv, sizeof(drm_via_private_t), DRM_MEM_DRIVER);
 
 	return 0;
diff --git a/drivers/char/drm/via_mm.c b/drivers/char/drm/via_mm.c
index 33e0cb1..2fcf057 100644
--- a/drivers/char/drm/via_mm.c
+++ b/drivers/char/drm/via_mm.c
@@ -1,6 +1,6 @@
 /*
- * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
- * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
+ * Copyright 2006 Tungsten Graphics Inc., Bismarck, ND., USA.
+ * All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -16,347 +16,194 @@
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * THE AUTHORS OR COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
+/*
+ * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
 #include "drmP.h"
 #include "via_drm.h"
 #include "via_drv.h"
-#include "via_ds.h"
-#include "via_mm.h"
-
-#define MAX_CONTEXT 100
-
-typedef struct {
-	int used;
-	int context;
-	set_t *sets[2];		/* 0 for frame buffer, 1 for AGP , 2 for System */
-} via_context_t;
-
-static via_context_t global_ppriv[MAX_CONTEXT];
+#include "drm_sman.h"
 
-static int via_agp_alloc(drm_via_mem_t * mem);
-static int via_agp_free(drm_via_mem_t * mem);
-static int via_fb_alloc(drm_via_mem_t * mem);
-static int via_fb_free(drm_via_mem_t * mem);
-
-static int add_alloc_set(int context, int type, unsigned long val)
-{
-	int i, retval = 0;
-
-	for (i = 0; i < MAX_CONTEXT; i++) {
-		if (global_ppriv[i].used && global_ppriv[i].context == context) {
-			retval = via_setAdd(global_ppriv[i].sets[type], val);
-			break;
-		}
-	}
-
-	return retval;
-}
-
-static int del_alloc_set(int context, int type, unsigned long val)
-{
-	int i, retval = 0;
-
-	for (i = 0; i < MAX_CONTEXT; i++)
-		if (global_ppriv[i].used && global_ppriv[i].context == context) {
-			retval = via_setDel(global_ppriv[i].sets[type], val);
-			break;
-		}
-
-	return retval;
-}
-
-/* agp memory management */
-static memHeap_t *AgpHeap = NULL;
+#define VIA_MM_ALIGN_SHIFT 4
+#define VIA_MM_ALIGN_MASK ( (1 << VIA_MM_ALIGN_SHIFT) - 1)
 
 int via_agp_init(DRM_IOCTL_ARGS)
 {
+	DRM_DEVICE;
 	drm_via_agp_t agp;
+	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+	int ret;
 
 	DRM_COPY_FROM_USER_IOCTL(agp, (drm_via_agp_t __user *) data,
 				 sizeof(agp));
+	mutex_lock(&dev->struct_mutex);
+	ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_AGP, 0,
+				 agp.size >> VIA_MM_ALIGN_SHIFT);
+
+	if (ret) {
+		DRM_ERROR("AGP memory manager initialisation error\n");
+		mutex_unlock(&dev->struct_mutex);
+		return ret;
+	}
 
-	AgpHeap = via_mmInit(agp.offset, agp.size);
-
-	DRM_DEBUG("offset = %lu, size = %lu", (unsigned long)agp.offset,
-		  (unsigned long)agp.size);
+	dev_priv->agp_initialized = 1;
+	dev_priv->agp_offset = agp.offset;
+	mutex_unlock(&dev->struct_mutex);
 
+	DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
 	return 0;
 }
 
-/* fb memory management */
-static memHeap_t *FBHeap = NULL;
-
 int via_fb_init(DRM_IOCTL_ARGS)
 {
+	DRM_DEVICE;
 	drm_via_fb_t fb;
+	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+	int ret;
 
 	DRM_COPY_FROM_USER_IOCTL(fb, (drm_via_fb_t __user *) data, sizeof(fb));
 
-	FBHeap = via_mmInit(fb.offset, fb.size);
+	mutex_lock(&dev->struct_mutex);
+	ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_VIDEO, 0,
+				 fb.size >> VIA_MM_ALIGN_SHIFT);
 
-	DRM_DEBUG("offset = %lu, size = %lu", (unsigned long)fb.offset,
-		  (unsigned long)fb.size);
+	if (ret) {
+		DRM_ERROR("VRAM memory manager initialisation error\n");
+		mutex_unlock(&dev->struct_mutex);
+		return ret;
+	}
 
-	return 0;
-}
+	dev_priv->vram_initialized = 1;
+	dev_priv->vram_offset = fb.offset;
 
-int via_init_context(struct drm_device *dev, int context)
-{
-	int i;
-
-	for (i = 0; i < MAX_CONTEXT; i++)
-		if (global_ppriv[i].used &&
-		    (global_ppriv[i].context == context))
-			break;
-
-	if (i >= MAX_CONTEXT) {
-		for (i = 0; i < MAX_CONTEXT; i++) {
-			if (!global_ppriv[i].used) {
-				global_ppriv[i].context = context;
-				global_ppriv[i].used = 1;
-				global_ppriv[i].sets[0] = via_setInit();
-				global_ppriv[i].sets[1] = via_setInit();
-				DRM_DEBUG("init allocation set, socket=%d,"
-					  " context = %d\n", i, context);
-				break;
-			}
-		}
-
-		if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) ||
-		    (global_ppriv[i].sets[1] == NULL)) {
-			return 0;
-		}
-	}
+	mutex_unlock(&dev->struct_mutex);
+	DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
+
+	return 0;
 
-	return 1;
 }
 
 int via_final_context(struct drm_device *dev, int context)
 {
-	int i;
 	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
 
-	for (i = 0; i < MAX_CONTEXT; i++)
-		if (global_ppriv[i].used &&
-		    (global_ppriv[i].context == context))
-			break;
-
-	if (i < MAX_CONTEXT) {
-		set_t *set;
-		ITEM_TYPE item;
-		int retval;
-
-		DRM_DEBUG("find socket %d, context = %d\n", i, context);
-
-		/* Video Memory */
-		set = global_ppriv[i].sets[0];
-		retval = via_setFirst(set, &item);
-		while (retval) {
-			DRM_DEBUG("free video memory 0x%lx\n", item);
-			via_mmFreeMem((PMemBlock) item);
-			retval = via_setNext(set, &item);
-		}
-		via_setDestroy(set);
-
-		/* AGP Memory */
-		set = global_ppriv[i].sets[1];
-		retval = via_setFirst(set, &item);
-		while (retval) {
-			DRM_DEBUG("free agp memory 0x%lx\n", item);
-			via_mmFreeMem((PMemBlock) item);
-			retval = via_setNext(set, &item);
-		}
-		via_setDestroy(set);
-		global_ppriv[i].used = 0;
-	}
 	via_release_futex(dev_priv, context);
 
-#if defined(__linux__)
 	/* Linux specific until context tracking code gets ported to BSD */
 	/* Last context, perform cleanup */
 	if (dev->ctx_count == 1 && dev->dev_private) {
 		DRM_DEBUG("Last Context\n");
 		if (dev->irq)
 			drm_irq_uninstall(dev);
-
 		via_cleanup_futex(dev_priv);
 		via_do_cleanup_map(dev);
 	}
-#endif
-
 	return 1;
 }
 
+void via_lastclose(struct drm_device *dev)
+{
+	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+
+	if (!dev_priv)
+		return;
+
+	mutex_lock(&dev->struct_mutex);
+	drm_sman_cleanup(&dev_priv->sman);
+	dev_priv->vram_initialized = 0;
+	dev_priv->agp_initialized = 0;
+	mutex_unlock(&dev->struct_mutex);
+}	
+
 int via_mem_alloc(DRM_IOCTL_ARGS)
 {
+	DRM_DEVICE;
+
 	drm_via_mem_t mem;
+	int retval = 0;
+	drm_memblock_item_t *item;
+	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+	unsigned long tmpSize;
 
 	DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data,
 				 sizeof(mem));
 
-	switch (mem.type) {
-	case VIA_MEM_VIDEO:
-		if (via_fb_alloc(&mem) < 0)
-			return -EFAULT;
-		DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem,
-				       sizeof(mem));
-		return 0;
-	case VIA_MEM_AGP:
-		if (via_agp_alloc(&mem) < 0)
-			return -EFAULT;
-		DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem,
-				       sizeof(mem));
-		return 0;
+	if (mem.type > VIA_MEM_AGP) {
+		DRM_ERROR("Unknown memory type allocation\n");
+		return DRM_ERR(EINVAL);
 	}
-
-	return -EFAULT;
-}
-
-static int via_fb_alloc(drm_via_mem_t * mem)
-{
-	drm_via_mm_t fb;
-	PMemBlock block;
-	int retval = 0;
-
-	if (!FBHeap)
-		return -1;
-
-	fb.size = mem->size;
-	fb.context = mem->context;
-
-	block = via_mmAllocMem(FBHeap, fb.size, 5, 0);
-	if (block) {
-		fb.offset = block->ofs;
-		fb.free = (unsigned long)block;
-		if (!add_alloc_set(fb.context, VIA_MEM_VIDEO, fb.free)) {
-			DRM_DEBUG("adding to allocation set fails\n");
-			via_mmFreeMem((PMemBlock) fb.free);
-			retval = -1;
-		}
-	} else {
-		fb.offset = 0;
-		fb.size = 0;
-		fb.free = 0;
-		retval = -1;
+	mutex_lock(&dev->struct_mutex);
+	if (0 == ((mem.type == VIA_MEM_VIDEO) ? dev_priv->vram_initialized :
+		      dev_priv->agp_initialized)) {
+		DRM_ERROR
+		    ("Attempt to allocate from uninitialized memory manager.\n");
+		mutex_unlock(&dev->struct_mutex);
+		return DRM_ERR(EINVAL);
 	}
 
-	mem->offset = fb.offset;
-	mem->index = fb.free;
-
-	DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size,
-		  (int)fb.offset);
-
-	return retval;
-}
-
-static int via_agp_alloc(drm_via_mem_t * mem)
-{
-	drm_via_mm_t agp;
-	PMemBlock block;
-	int retval = 0;
-
-	if (!AgpHeap)
-		return -1;
-
-	agp.size = mem->size;
-	agp.context = mem->context;
-
-	block = via_mmAllocMem(AgpHeap, agp.size, 5, 0);
-	if (block) {
-		agp.offset = block->ofs;
-		agp.free = (unsigned long)block;
-		if (!add_alloc_set(agp.context, VIA_MEM_AGP, agp.free)) {
-			DRM_DEBUG("adding to allocation set fails\n");
-			via_mmFreeMem((PMemBlock) agp.free);
-			retval = -1;
-		}
+	tmpSize = (mem.size + VIA_MM_ALIGN_MASK) >> VIA_MM_ALIGN_SHIFT;
+	item = drm_sman_alloc(&dev_priv->sman, mem.type, tmpSize, 0,
+			      (unsigned long)priv);
+	mutex_unlock(&dev->struct_mutex);
+	if (item) {
+		mem.offset = ((mem.type == VIA_MEM_VIDEO) ?
+			      dev_priv->vram_offset : dev_priv->agp_offset) +
+		    (item->mm->
+		     offset(item->mm, item->mm_info) << VIA_MM_ALIGN_SHIFT);
+		mem.index = item->user_hash.key;
 	} else {
-		agp.offset = 0;
-		agp.size = 0;
-		agp.free = 0;
+		mem.offset = 0;
+		mem.size = 0;
+		mem.index = 0;
+		DRM_DEBUG("Video memory allocation failed\n");
+		retval = DRM_ERR(ENOMEM);
 	}
+	DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem, sizeof(mem));
 
-	mem->offset = agp.offset;
-	mem->index = agp.free;
-
-	DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size,
-		  (unsigned int)agp.offset);
 	return retval;
 }
 
 int via_mem_free(DRM_IOCTL_ARGS)
 {
+	DRM_DEVICE;
+	drm_via_private_t *dev_priv = dev->dev_private;
 	drm_via_mem_t mem;
+	int ret;
 
 	DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data,
 				 sizeof(mem));
 
-	switch (mem.type) {
+	mutex_lock(&dev->struct_mutex);
+	ret = drm_sman_free_key(&dev_priv->sman, mem.index);
+	mutex_unlock(&dev->struct_mutex);
+	DRM_DEBUG("free = 0x%lx\n", mem.index);
 
-	case VIA_MEM_VIDEO:
-		if (via_fb_free(&mem) == 0)
-			return 0;
-		break;
-	case VIA_MEM_AGP:
-		if (via_agp_free(&mem) == 0)
-			return 0;
-		break;
-	}
-
-	return -EFAULT;
+	return ret;
 }
 
-static int via_fb_free(drm_via_mem_t * mem)
-{
-	drm_via_mm_t fb;
-	int retval = 0;
-
-	if (!FBHeap) {
-		return -1;
-	}
-
-	fb.free = mem->index;
-	fb.context = mem->context;
-
-	if (!fb.free) {
-		return -1;
-
-	}
-
-	via_mmFreeMem((PMemBlock) fb.free);
-
-	if (!del_alloc_set(fb.context, VIA_MEM_VIDEO, fb.free)) {
-		retval = -1;
-	}
-
-	DRM_DEBUG("free fb, free = %ld\n", fb.free);
 
-	return retval;
-}
-
-static int via_agp_free(drm_via_mem_t * mem)
+void via_reclaim_buffers_locked(drm_device_t * dev, struct file *filp)
 {
-	drm_via_mm_t agp;
-
-	int retval = 0;
+	drm_via_private_t *dev_priv = dev->dev_private;
+	drm_file_t *priv = filp->private_data;
 
-	agp.free = mem->index;
-	agp.context = mem->context;
-
-	if (!agp.free)
-		return -1;
-
-	via_mmFreeMem((PMemBlock) agp.free);
-
-	if (!del_alloc_set(agp.context, VIA_MEM_AGP, agp.free)) {
-		retval = -1;
+	mutex_lock(&dev->struct_mutex);
+	if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
+		mutex_unlock(&dev->struct_mutex);
+		return;
 	}
 
-	DRM_DEBUG("free agp, free = %ld\n", agp.free);
+	if (dev->driver->dma_quiescent) {
+		dev->driver->dma_quiescent(dev);
+	}
 
-	return retval;
+	drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv);
+	mutex_unlock(&dev->struct_mutex);
+	return;
 }
