Browse Source

Merge branch 'drm-patches' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6

* 'drm-patches' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6: (36 commits)
  drm: Use register writes instead of BITBLT_MULTI packets for buffer swap blits
  drm: use radeon specific names for radeon flags
  drm: add device/vendor id to drm_device_t for compat with FreeBSD drivers
  drm: allow multiple addMaps with the same 32-bit map offsset.
  drm: fd.o Bug #7595: Avoid u32 overflows in radeon_check_and_fixup_offset().
  drm: Fix hashtab implementation leaking illegal error codes to user space.
  drm: domain changes broke ppc r200
  drm: fixup setversion return codes..
  drm: fixup i915 error codes
  drm: realign sosme radeon code with drm git tree
  drm: realign via driver with drm git tree
  drm: remove hash tables on drm exit
  drm: cleanups
  drm: i810_dma.c: fix pointer arithmetic for 64-bit target
  drm: avoid kernel oops in some error paths calling drm_lastclose
  drm: allow detection of new VIA chipsets
  drm: fix i965 build bug
  drm: remove FALSE/TRUE that snuck in with simple memory manager changes.
  drm: Add support for Intel i965G chipsets.
  drm: add better explanation for i830/i915
  ...
Linus Torvalds 19 years ago
parent
commit
e823aff2d6
42 changed files with 1878 additions and 1772 deletions
  1. 6 3
      drivers/char/drm/Kconfig
  2. 3 3
      drivers/char/drm/Makefile
  3. 48 20
      drivers/char/drm/drmP.h
  4. 15 49
      drivers/char/drm/drm_auth.c
  5. 37 37
      drivers/char/drm/drm_bufs.c
  6. 7 5
      drivers/char/drm/drm_drv.c
  7. 5 5
      drivers/char/drm/drm_fops.c
  8. 190 0
      drivers/char/drm/drm_hashtab.c
  9. 67 0
      drivers/char/drm/drm_hashtab.h
  10. 1 1
      drivers/char/drm/drm_ioc32.c
  11. 21 13
      drivers/char/drm/drm_ioctl.c
  12. 7 5
      drivers/char/drm/drm_irq.c
  13. 201 0
      drivers/char/drm/drm_mm.c
  14. 98 89
      drivers/char/drm/drm_pciids.h
  15. 1 1
      drivers/char/drm/drm_proc.c
  16. 352 0
      drivers/char/drm/drm_sman.c
  17. 176 0
      drivers/char/drm/drm_sman.h
  18. 6 6
      drivers/char/drm/drm_stub.c
  19. 15 30
      drivers/char/drm/drm_vm.c
  20. 5 5
      drivers/char/drm/i810_dma.c
  21. 2 2
      drivers/char/drm/i830_dma.c
  22. 33 12
      drivers/char/drm/i915_dma.c
  23. 6 0
      drivers/char/drm/i915_drm.h
  24. 6 4
      drivers/char/drm/i915_drv.h
  25. 11 5
      drivers/char/drm/i915_irq.c
  26. 42 30
      drivers/char/drm/radeon_cp.c
  27. 1 1
      drivers/char/drm/radeon_drv.c
  28. 23 13
      drivers/char/drm/radeon_drv.h
  29. 27 21
      drivers/char/drm/radeon_state.c
  30. 36 3
      drivers/char/drm/sis_drv.c
  31. 25 9
      drivers/char/drm/sis_drv.h
  32. 0 299
      drivers/char/drm/sis_ds.c
  33. 0 146
      drivers/char/drm/sis_ds.h
  34. 219 285
      drivers/char/drm/sis_mm.c
  35. 45 23
      drivers/char/drm/via_dmablit.c
  36. 7 1
      drivers/char/drm/via_drm.h
  37. 2 1
      drivers/char/drm/via_drv.c
  38. 13 3
      drivers/char/drm/via_drv.h
  39. 0 273
      drivers/char/drm/via_ds.c
  40. 0 104
      drivers/char/drm/via_ds.h
  41. 8 1
      drivers/char/drm/via_map.c
  42. 111 264
      drivers/char/drm/via_mm.c

+ 6 - 3
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
 

+ 3 - 3
drivers/char/drm/Makefile

@@ -6,7 +6,7 @@ drm-objs    :=	drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \
 		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 i830_irq.o
 i915-objs   := i915_drv.o i915_dma.o i915_irq.o i915_mem.o
 radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o 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

+ 48 - 20
drivers/char/drm/drmP.h

@@ -79,6 +79,7 @@
 #define __OS_HAS_MTRR (defined(CONFIG_MTRR))
 
 #include "drm_os_linux.h"
+#include "drm_hashtab.h"
 
 /***********************************************************************/
 /** \name DRM template customization defaults */
@@ -104,7 +105,7 @@
 #define DRM_DEBUG_CODE 2	  /**< Include debugging code if > 1, then
 				     also include looping detection. */
 
-#define DRM_HASH_SIZE	      16 /**< Size of key hash table. Must be power of 2. */
+#define DRM_MAGIC_HASH_ORDER  4  /**< Size of key hash table. Must be power of 2. */
 #define DRM_KERNEL_CONTEXT    0	 /**< Change drm_resctx if changed */
 #define DRM_RESERVED_CONTEXTS 1	 /**< Change drm_resctx if changed */
 #define DRM_LOOPING_LIMIT     5000000
@@ -134,19 +135,12 @@
 #define DRM_MEM_CTXBITMAP 18
 #define DRM_MEM_STUB      19
 #define DRM_MEM_SGLISTS   20
-#define DRM_MEM_CTXLIST  21
+#define DRM_MEM_CTXLIST   21
+#define DRM_MEM_MM        22
+#define DRM_MEM_HASHTAB   23
 
 #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)
-
-/*@}*/
-
-/***********************************************************************/
-/** \name Backward compatibility section */
-/*@{*/
-
-#define DRM_RPR_ARG(vma) vma,
-
-#define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT)
+#define DRM_MAP_HASH_OFFSET 0x10000000
 
 /*@}*/
 
@@ -211,8 +205,6 @@
 /*@{*/
 
 #define DRM_ARRAY_SIZE(x) ARRAY_SIZE(x)
-#define DRM_MIN(a,b) min(a,b)
-#define DRM_MAX(a,b) max(a,b)
 
 #define DRM_LEFTCOUNT(x) (((x)->rp + (x)->count - (x)->wp) % ((x)->count + 1))
 #define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x))
@@ -286,7 +278,8 @@ typedef struct drm_devstate {
 } drm_devstate_t;
 
 typedef struct drm_magic_entry {
-	drm_magic_t magic;
+	drm_hash_item_t hash_item;
+	struct list_head head;
 	struct drm_file *priv;
 	struct drm_magic_entry *next;
 } drm_magic_entry_t;
@@ -493,6 +486,7 @@ typedef struct drm_sigdata {
  */
 typedef struct drm_map_list {
 	struct list_head head;		/**< list head */
+	drm_hash_item_t hash;
 	drm_map_t *map;			/**< mapping */
 	unsigned int user_token;
 } drm_map_list_t;
@@ -527,6 +521,22 @@ typedef struct ati_pcigart_info {
 	drm_local_map_t mapping;
 } drm_ati_pcigart_info;
 
+/*
+ * Generic memory manager structs
+ */
+typedef struct drm_mm_node {
+	struct list_head fl_entry;
+	struct list_head ml_entry;
+	int free;
+	unsigned long start;
+	unsigned long size;
+	void *private;
+} drm_mm_node_t;
+
+typedef struct drm_mm {
+	drm_mm_node_t root_node;
+} drm_mm_t;
+
 /**
  * DRM driver structure. This structure represent the common code for
  * a family of cards. There will one drm_device for each card present
@@ -646,13 +656,15 @@ typedef struct drm_device {
 	/*@{ */
 	drm_file_t *file_first;		/**< file list head */
 	drm_file_t *file_last;		/**< file list tail */
-	drm_magic_head_t magiclist[DRM_HASH_SIZE];	/**< magic hash table */
+	drm_open_hash_t magiclist;	/**< magic hash table */
+	struct list_head magicfree;
 	/*@} */
 
 	/** \name Memory management */
 	/*@{ */
 	drm_map_list_t *maplist;	/**< Linked list of regions */
 	int map_count;			/**< Number of mappable regions */
+	drm_open_hash_t map_hash;	/**< User token hash table for maps */
 
 	/** \name Context handle management */
 	/*@{ */
@@ -711,10 +723,8 @@ typedef struct drm_device {
 	drm_agp_head_t *agp;	/**< AGP data */
 
 	struct pci_dev *pdev;		/**< PCI device structure */
-	int pci_domain;			/**< PCI bus domain number */
-	int pci_bus;			/**< PCI bus number */
-	int pci_slot;			/**< PCI slot number */
-	int pci_func;			/**< PCI function number */
+	int pci_vendor;			/**< PCI vendor id */
+	int pci_device;			/**< PCI device id */
 #ifdef __alpha__
 	struct pci_controller *hose;
 #endif
@@ -736,6 +746,12 @@ static __inline__ int drm_core_check_feature(struct drm_device *dev,
 	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_device_add(struct class *cs,
 						 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)

+ 15 - 49
drivers/char/drm/drm_auth.c

@@ -35,20 +35,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.
  *
@@ -63,14 +49,12 @@ static drm_file_t *drm_find_file(drm_device_t * dev, drm_magic_t magic)
 {
 	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_device_t * dev, drm_magic_t magic)
 static int drm_add_magic(drm_device_t * dev, drm_file_t * priv,
 			 drm_magic_t magic)
 {
-	int hash;
 	drm_magic_entry_t *entry;
 
 	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 * dev, drm_file_t * priv,
  */
 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;
 }
 
 /**

+ 37 - 37
drivers/char/drm/drm_bufs.c

@@ -65,43 +65,29 @@ static drm_map_list_t *drm_find_matching_map(drm_device_t *dev,
 	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 * dev, unsigned int offset,
 	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 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
 
 	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, drm_local_map_t *map)
 
 		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, struct file *filp,
 		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)) {

+ 7 - 5
drivers/char/drm/drm_drv.c

@@ -118,7 +118,7 @@ static drm_ioctl_desc_t drm_ioctls[] = {
 	[DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0},
 };
 
-#define DRIVER_IOCTL_COUNT	DRM_ARRAY_SIZE( drm_ioctls )
+#define DRIVER_IOCTL_COUNT	ARRAY_SIZE( drm_ioctls )
 
 /**
  * Take down the DRM device.
@@ -155,12 +155,13 @@ int drm_lastclose(drm_device_t * dev)
 	del_timer(&dev->timer);
 
 	/* Clear pid list */
-	for (i = 0; i < DRM_HASH_SIZE; i++) {
-		for (pt = dev->magiclist[i].head; pt; pt = next) {
-			next = pt->next;
+	if (dev->magicfree.next) {
+		list_for_each_entry_safe(pt, next, &dev->magicfree, head) {
+			list_del(&pt->head);
+			drm_ht_remove_item(&dev->magiclist, &pt->hash_item);
 			drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
 		}
-		dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
+		drm_ht_remove(&dev->magiclist);
 	}
 
 	/* Clear AGP information */
@@ -299,6 +300,7 @@ static void drm_cleanup(drm_device_t * dev)
 	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);

+ 5 - 5
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)

+ 190 - 0
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;
+	}
+}
+

+ 67 - 0
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
+

+ 1 - 1
drivers/char/drm/drm_ioc32.c

@@ -1051,7 +1051,7 @@ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 	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];

+ 21 - 13
drivers/char/drm/drm_ioctl.c

@@ -127,9 +127,10 @@ int drm_setunique(struct inode *inode, struct file *filp,
 	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 * dev)
 	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 * dev)
 	    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);

+ 7 - 5
drivers/char/drm/drm_irq.c

@@ -64,9 +64,9 @@ int drm_irq_by_busid(struct inode *inode, struct file *filp,
 	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;
 }

+ 201 - 0
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);

+ 98 - 89
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 @@
 	{0x1002, 0x4154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4156, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
-	{0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \
+	{0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP}, \
 	{0x1002, 0x4242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x4243, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
 	{0x1002, 0x4966, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \
 	{0x1002, 0x4967, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \
-	{0x1002, 0x4A48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4A4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4A4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4A4D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4A4E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4A4F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4A50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4A54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4B49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4B4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4B4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4B4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C5A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x4A48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4A4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4A4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4A4D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4A4E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4A4F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4A50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4A54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4B49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4B4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4B4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4B4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4C5A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
 	{0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
@@ -62,16 +62,16 @@
 	{0x1002, 0x4E49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
 	{0x1002, 0x4E4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
 	{0x1002, 0x4E4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
-	{0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4E52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4E53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4E56, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
-	{0x1002, 0x5145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
-	{0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
-	{0x1002, 0x5147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
+	{0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4E52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4E53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x4E56, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
+	{0x1002, 0x5145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
+	{0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
+	{0x1002, 0x5147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
 	{0x1002, 0x5148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x514C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x514D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
@@ -80,59 +80,59 @@
 	{0x1002, 0x5159, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
 	{0x1002, 0x515A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
 	{0x1002, 0x515E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
-	{0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x554B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x554C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x554D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x554E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5551, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5554, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x564A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x564B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \
-	{0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x554B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x554C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x554D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x554E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5551, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5554, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x564A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x564B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP}, \
+	{0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
 	{0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
-	{0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5b64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5b65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x5d48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5d49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5d4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5d4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5d4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5d50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5d52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5d57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5e48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5e4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5e4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5e4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x5e4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_NEW_MEMMAP}, \
-	{0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5b64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5b65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \
+	{0x1002, 0x5d48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5d49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5d4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5d4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5d4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5d50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5d52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5d57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5e48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5e4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5e4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5e4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x5e4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0, 0, 0}
 
 #define r128_PCI_IDS \
@@ -209,6 +209,7 @@
 	{0x1039, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x1039, 0x5300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x1039, 0x6300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x1039, 0x6330, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_CHIP_315}, \
 	{0x1039, 0x7300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0, 0, 0}
 
@@ -227,6 +228,10 @@
 	{0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x1106, 0x3304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0, 0, 0}
 
 #define i810_PCI_IDS \
@@ -285,5 +290,9 @@
 	{0x8086, 0x2592, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x8086, 0x27a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x8086, 0x2972, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x8086, 0x2982, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x8086, 0x2992, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x8086, 0x29a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0, 0, 0}
 

+ 1 - 1
drivers/char/drm/drm_proc.c

@@ -510,7 +510,7 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request,
 			       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);

+ 352 - 0
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);

+ 176 - 0
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

+ 6 - 6
drivers/char/drm/drm_stub.c

@@ -65,22 +65,22 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
 	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;

+ 15 - 30
drivers/char/drm/drm_vm.c

@@ -59,7 +59,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
 	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_nopage(struct vm_area_struct *vma,
 	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 *filp, struct vm_area_struct *vma)
 	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 vm_area_struct *vma)
 	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 vm_area_struct *vma)
 	 * the AGP mapped at physical address 0
 	 * --BenH.
 	 */
-	if (!VM_OFFSET(vma)
+	if (!(vma->vm_pgoff << PAGE_SHIFT)
 #if __OS_HAS_AGP
 	    && (!dev->agp
 		|| dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE)
@@ -543,23 +539,12 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
 	    )
 		return drm_mmap_dma(filp, vma);
 
-	/* A sequential search of a linked list is
-	   fine here because: 1) there will only be
-	   about 5-10 entries in the list and, 2) a
-	   DRI client only has to do this mapping
-	   once, so it doesn't have to be optimized
-	   for performance, even if the list was a
-	   bit longer. */
-	list_for_each(list, &dev->maplist->head) {
-
-		r_list = list_entry(list, drm_map_list_t, head);
-		map = r_list->map;
-		if (!map)
-			continue;
-		if (r_list->user_token == VM_OFFSET(vma))
-			break;
+	if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) {
+		DRM_ERROR("Could not find map\n");
+		return -EINVAL;
 	}
 
+	map = drm_hash_entry(hash, drm_map_list_t, hash)->map;
 	if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN)))
 		return -EPERM;
 
@@ -620,7 +605,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
 		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))

+ 5 - 5
drivers/char/drm/i810_dma.c

@@ -106,7 +106,7 @@ static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
 	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 * buf, struct file *filp)
 					    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_device_t * dev,
 		    ((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_device_t * dev, drm_buf_t * buf, int used,
 
 	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;
 		}
 

+ 2 - 2
drivers/char/drm/i830_dma.c

@@ -108,7 +108,7 @@ static int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
 	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 * buf, struct file *filp)
 	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;

+ 33 - 12
drivers/char/drm/i915_dma.c

@@ -31,6 +31,11 @@
 #include "i915_drm.h"
 #include "i915_drv.h"
 
+#define IS_I965G(dev) (dev->pci_device == 0x2972 || \
+		       dev->pci_device == 0x2982 || \
+		       dev->pci_device == 0x2992 || \
+		       dev->pci_device == 0x29A2)
+
 /* Really want an OS-independent resettable timer.  Would like to have
  * this loop run for (eg) 3 sec, but have the timer reset every time
  * the head pointer changes, so that EBUSY only happens if the ring
@@ -255,7 +260,7 @@ static int i915_dma_init(DRM_IOCTL_ARGS)
 		retcode = i915_dma_resume(dev);
 		break;
 	default:
-		retcode = -EINVAL;
+		retcode = DRM_ERR(EINVAL);
 		break;
 	}
 
@@ -347,7 +352,7 @@ static int i915_emit_cmds(drm_device_t * dev, int __user * buffer, int dwords)
 	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 * dev,
 	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 * dev,
 		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);

+ 6 - 0
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

+ 6 - 4
drivers/char/drm/i915_drv.h

@@ -146,9 +146,9 @@ extern void i915_mem_release(drm_device_t * dev,
 #define BEGIN_LP_RING(n) do {				\
 	if (I915_VERBOSE)				\
 		DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n",	\
-			  n, __FUNCTION__);		\
-	if (dev_priv->ring.space < n*4)			\
-		i915_wait_ring(dev, n*4, __FUNCTION__);		\
+			  (n), __FUNCTION__);		\
+	if (dev_priv->ring.space < (n)*4)			\
+		i915_wait_ring(dev, (n)*4, __FUNCTION__);		\
 	outcount = 0;					\
 	outring = dev_priv->ring.tail;			\
 	ringmask = dev_priv->ring.tail_mask;		\
@@ -157,7 +157,7 @@ extern void i915_mem_release(drm_device_t * dev,
 
 #define OUT_RING(n) do {					\
 	if (I915_VERBOSE) DRM_DEBUG("   OUT_RING %x\n", (int)(n));	\
-	*(volatile unsigned int *)(virt + outring) = n;		\
+	*(volatile unsigned int *)(virt + outring) = (n);	\
         outcount++;						\
 	outring += 4;						\
 	outring &= ringmask;					\
@@ -254,6 +254,8 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
 #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)

+ 11 - 5
drivers/char/drm/i915_irq.c

@@ -71,21 +71,27 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 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)

+ 42 - 30
drivers/char/drm/radeon_cp.c

@@ -864,13 +864,13 @@ static int radeon_do_pixcache_flush(drm_radeon_private_t * dev_priv)
 
 	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(drm_device_t * dev,
 			     | (dev_priv->fb_location >> 16));
 
 #if __OS_HAS_AGP
-	if (dev_priv->flags & CHIP_IS_AGP) {
+	if (dev_priv->flags & RADEON_IS_AGP) {
 		RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base);
 		RADEON_WRITE(RADEON_MC_AGP_LOCATION,
 			     (((dev_priv->gart_vm_start - 1 +
@@ -1158,7 +1158,7 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev,
 	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_radeon_private_t * dev_priv)
 		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_radeon_private_t * dev_priv, int on)
 {
 	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_t * dev, drm_radeon_init_t * init)
 	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_t * dev, drm_radeon_init_t * init)
 				    init->sarea_priv_offset);
 
 #if __OS_HAS_AGP
-	if (dev_priv->flags & CHIP_IS_AGP) {
+	if (dev_priv->flags & RADEON_IS_AGP) {
 		drm_core_ioremap(dev_priv->cp_ring, dev);
 		drm_core_ioremap(dev_priv->ring_rptr, dev);
 		drm_core_ioremap(dev->agp_buffer_map, dev);
@@ -1548,7 +1557,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
 		 * align it down.
 		 */
 #if __OS_HAS_AGP
-		if (dev_priv->flags & CHIP_IS_AGP) {
+		if (dev_priv->flags & RADEON_IS_AGP) {
 			base = dev->agp->base;
 			/* Check if valid */
 			if ((base + dev_priv->gart_size) > dev_priv->fb_location &&
@@ -1578,7 +1587,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
 	}
 
 #if __OS_HAS_AGP
-	if (dev_priv->flags & CHIP_IS_AGP)
+	if (dev_priv->flags & RADEON_IS_AGP)
 		dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset
 						 - dev->agp->base
 						 + dev_priv->gart_vm_start);
@@ -1604,7 +1613,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
 	dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK;
 
 #if __OS_HAS_AGP
-	if (dev_priv->flags & CHIP_IS_AGP) {
+	if (dev_priv->flags & RADEON_IS_AGP) {
 		/* Turn off PCI GART */
 		radeon_set_pcigart(dev_priv, 0);
 	} else
@@ -1624,7 +1633,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
 			    dev_priv->gart_info.mapping.handle;
 
 			dev_priv->gart_info.is_pcie =
-			    !!(dev_priv->flags & CHIP_IS_PCIE);
+			    !!(dev_priv->flags & RADEON_IS_PCIE);
 			dev_priv->gart_info.gart_table_location =
 			    DRM_ATI_GART_FB;
 
@@ -1636,7 +1645,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
 			    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_device_t * dev)
 		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_device_t * dev)
 	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, unsigned long flags)
 	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 *dev, unsigned long flags)
 	}
 
 	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;
 }
 

+ 1 - 1
drivers/char/drm/radeon_drv.c

@@ -44,7 +44,7 @@ module_param_named(no_wb, radeon_no_wb, int, 0444);
 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" :

+ 23 - 13
drivers/char/drm/radeon_drv.h

@@ -133,15 +133,16 @@ enum radeon_cp_microcode_version {
  * Chip flags
  */
 enum radeon_chip_flags {
-	CHIP_FAMILY_MASK = 0x0000ffffUL,
-	CHIP_FLAGS_MASK = 0xffff0000UL,
-	CHIP_IS_MOBILITY = 0x00010000UL,
-	CHIP_IS_IGP = 0x00020000UL,
-	CHIP_SINGLE_CRTC = 0x00040000UL,
-	CHIP_IS_AGP = 0x00080000UL,
-	CHIP_HAS_HIERZ = 0x00100000UL,
-	CHIP_IS_PCIE = 0x00200000UL,
-	CHIP_NEW_MEMMAP = 0x00400000UL,
+	RADEON_FAMILY_MASK = 0x0000ffffUL,
+	RADEON_FLAGS_MASK = 0xffff0000UL,
+	RADEON_IS_MOBILITY = 0x00010000UL,
+	RADEON_IS_IGP = 0x00020000UL,
+	RADEON_SINGLE_CRTC = 0x00040000UL,
+	RADEON_IS_AGP = 0x00080000UL,
+	RADEON_HAS_HIERZ = 0x00100000UL,
+	RADEON_IS_PCIE = 0x00200000UL,
+	RADEON_NEW_MEMMAP = 0x00400000UL,
+	RADEON_IS_PCI = 0x00800000UL,
 };
 
 #define GET_RING_HEAD(dev_priv)	(dev_priv->writeback_works ? \
@@ -424,6 +425,8 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
 #define RADEON_RB3D_COLOROFFSET		0x1c40
 #define RADEON_RB3D_COLORPITCH		0x1c48
 
+#define	RADEON_SRC_X_Y			0x1590
+
 #define RADEON_DP_GUI_MASTER_CNTL	0x146c
 #	define RADEON_GMC_SRC_PITCH_OFFSET_CNTL	(1 << 0)
 #	define RADEON_GMC_DST_PITCH_OFFSET_CNTL	(1 << 1)
@@ -441,6 +444,7 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
 #	define RADEON_ROP3_S			0x00cc0000
 #	define RADEON_ROP3_P			0x00f00000
 #define RADEON_DP_WRITE_MASK		0x16cc
+#define RADEON_SRC_PITCH_OFFSET		0x1428
 #define RADEON_DST_PITCH_OFFSET		0x142c
 #define RADEON_DST_PITCH_OFFSET_C	0x1c80
 #	define RADEON_DST_TILE_LINEAR		(0 << 30)
@@ -545,6 +549,11 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
 #	define RADEON_RB3D_ZC_FREE		(1 << 2)
 #	define RADEON_RB3D_ZC_FLUSH_ALL		0x5
 #	define RADEON_RB3D_ZC_BUSY		(1 << 31)
+#define RADEON_RB3D_DSTCACHE_CTLSTAT	0x325c
+#	define RADEON_RB3D_DC_FLUSH		(3 << 0)
+#	define RADEON_RB3D_DC_FREE		(3 << 2)
+#	define RADEON_RB3D_DC_FLUSH_ALL		0xf
+#	define RADEON_RB3D_DC_BUSY		(1 << 31)
 #define RADEON_RB3D_ZSTENCILCNTL	0x1c2c
 #	define RADEON_Z_TEST_MASK		(7 << 4)
 #	define RADEON_Z_TEST_ALWAYS		(7 << 4)
@@ -681,6 +690,7 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
 #define RADEON_CP_RB_BASE		0x0700
 #define RADEON_CP_RB_CNTL		0x0704
 #	define RADEON_BUF_SWAP_32BIT		(2 << 16)
+#	define RADEON_RB_NO_UPDATE		(1 << 27)
 #define RADEON_CP_RB_RPTR_ADDR		0x070c
 #define RADEON_CP_RB_RPTR		0x0710
 #define RADEON_CP_RB_WPTR		0x0714
@@ -986,13 +996,13 @@ do {									\
 } while (0)
 
 #define RADEON_FLUSH_CACHE() do {					\
-	OUT_RING( CP_PACKET0( RADEON_RB2D_DSTCACHE_CTLSTAT, 0 ) );	\
-	OUT_RING( RADEON_RB2D_DC_FLUSH );				\
+	OUT_RING( CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 0 ) );	\
+	OUT_RING( RADEON_RB3D_DC_FLUSH );				\
 } while (0)
 
 #define RADEON_PURGE_CACHE() do {					\
-	OUT_RING( CP_PACKET0( RADEON_RB2D_DSTCACHE_CTLSTAT, 0 ) );	\
-	OUT_RING( RADEON_RB2D_DC_FLUSH_ALL );				\
+	OUT_RING( CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 0 ) );	\
+	OUT_RING( RADEON_RB3D_DC_FLUSH_ALL );				\
 } while (0)
 
 #define RADEON_FLUSH_ZCACHE() do {					\

+ 27 - 21
drivers/char/drm/radeon_state.c

@@ -42,7 +42,11 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
 						    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_fixup_offset(drm_radeon_private_t *
 	/* 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_fixup_offset(drm_radeon_private_t *
 	}
 
 	/* 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_device_t * dev,
 		 */
 		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_device_t * dev,
 		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_device_t * dev,
 		}
 
 		/* 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_device_t * dev)
 
 		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_device_t * dev)
 
 		/* 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_device_t * dev)
 			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 @@ static int radeon_cp_getparam(DRM_IOCTL_ARGS)
 	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);
 	}
 

+ 36 - 3
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,

+ 25 - 9
drivers/char/drm/sis_drv.h

@@ -31,23 +31,39 @@
 /* General customization:
  */
 
-#define DRIVER_AUTHOR		"SIS"
+#define DRIVER_AUTHOR		"SIS, Tungsten Graphics"
 #define DRIVER_NAME		"sis"
 #define DRIVER_DESC		"SIS 300/630/540"
-#define DRIVER_DATE		"20030826"
+#define DRIVER_DATE		"20060704"
 #define DRIVER_MAJOR		1
-#define DRIVER_MINOR		1
-#define DRIVER_PATCHLEVEL	0
+#define DRIVER_MINOR		2
+#define DRIVER_PATCHLEVEL	1
 
-#include "sis_ds.h"
+enum sis_family {
+	SIS_OTHER = 0,
+	SIS_CHIP_315 = 1,
+};
+
+#include "drm_sman.h"
+
+#define SIS_BASE (dev_priv->mmio)
+#define SIS_READ(reg)         DRM_READ32(SIS_BASE, reg);
+#define SIS_WRITE(reg, val)   DRM_WRITE32(SIS_BASE, reg, val);
 
 typedef struct drm_sis_private {
-	memHeap_t *AGPHeap;
-	memHeap_t *FBHeap;
+	drm_local_map_t *mmio;
+	unsigned int idle_fault;
+	drm_sman_t sman;
+	unsigned int chipset;
+	int vram_initialized;
+	int agp_initialized;
+	unsigned long vram_offset;
+	unsigned long agp_offset;
 } drm_sis_private_t;
 
-extern int sis_init_context(drm_device_t * dev, int context);
-extern int sis_final_context(drm_device_t * dev, int context);
+extern int sis_idle(drm_device_t *dev);
+extern void sis_reclaim_buffers_locked(drm_device_t *dev, struct file *filp);
+extern void sis_lastclose(drm_device_t *dev);
 
 extern drm_ioctl_desc_t sis_ioctls[];
 extern int sis_max_ioctl;

+ 0 - 299
drivers/char/drm/sis_ds.c

@@ -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;
-}

+ 0 - 146
drivers/char/drm/sis_ds.h

@@ -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__ */

+ 219 - 285
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);

+ 45 - 23
drivers/char/drm/via_dmablit.c

@@ -41,9 +41,9 @@
 
 #include <linux/pagemap.h>
 
-#define VIA_PGDN(x)             (((unsigned long)(x)) & PAGE_MASK)
-#define VIA_PGOFF(x)            (((unsigned long)(x)) & ~PAGE_MASK)
-#define VIA_PFN(x)              ((unsigned long)(x) >> PAGE_SHIFT)
+#define VIA_PGDN(x)	     (((unsigned long)(x)) & PAGE_MASK)
+#define VIA_PGOFF(x)	    (((unsigned long)(x)) & ~PAGE_MASK)
+#define VIA_PFN(x)	      ((unsigned long)(x) >> PAGE_SHIFT)
 
 typedef struct _drm_via_descriptor {
 	uint32_t mem_addr;
@@ -121,19 +121,19 @@ via_map_blit_for_device(struct pci_dev *pdev,
 		
 		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 *pdev,
 
 /*
  * 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 *vsg,  drm_via_dmablit_t *xfer)
 		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_via_sg_info_t *vsg, drm_via_dmablit_t *
 	 * (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_via_sg_info_t *vsg, drm_via_dmablit_t *
 
 #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_dmablit_t *xfer)
 	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_dmablit_t *xfer)
 
 /*
  * 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().
  */

+ 7 - 1
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;

+ 2 - 1
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,

+ 13 - 3
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_private_t * dev_priv);
 extern void via_cleanup_futex(drm_via_private_t * dev_priv);
 extern void via_release_futex(drm_via_private_t * dev_priv, int context);
 
+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);
 

+ 0 - 273
drivers/char/drm/via_ds.c

@@ -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;
-}

+ 0 - 104
drivers/char/drm/via_ds.h

@@ -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

+ 8 - 1
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, unsigned long chipset)
 	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;

+ 111 - 264
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;
 }