DRM from FreeBSD current, tested for r600
authorDavid Shao <davshao@gmail.com>
Fri, 9 Apr 2010 06:29:53 +0000 (23:29 -0700)
committerSamuel J. Greear <sjg@thesjg.com>
Fri, 21 Oct 2011 02:16:31 +0000 (20:16 -0600)
Author:    David Shao <davshao@gmail.com>

24 files changed:
sys/dev/drm/drm/Makefile
sys/dev/drm/drmP.h
sys/dev/drm/drm_hashtab.c [new file with mode: 0644]
sys/dev/drm/drm_hashtab.h [new file with mode: 0644]
sys/dev/drm/drm_linux_list.h
sys/dev/drm/drm_memory.c
sys/dev/drm/drm_mm.c [new file with mode: 0644]
sys/dev/drm/drm_mm.h [new file with mode: 0644]
sys/dev/drm/drm_pciids.h
sys/dev/drm/drm_priv_hash.h [new file with mode: 0644]
sys/dev/drm/drm_sman.c [new file with mode: 0644]
sys/dev/drm/drm_sman.h [new file with mode: 0644]
sys/dev/drm/drm_subr_hash.c [new file with mode: 0644]
sys/dev/drm/i915_drv.c
sys/dev/drm/i915_drv.h
sys/dev/drm/r600_blit.c [new file with mode: 0644]
sys/dev/drm/r600_cp.c
sys/dev/drm/radeon/Makefile
sys/dev/drm/radeon_cp.c
sys/dev/drm/radeon_cs.c [new file with mode: 0644]
sys/dev/drm/radeon_drm.h
sys/dev/drm/radeon_drv.h
sys/dev/drm/radeon_irq.c
sys/dev/drm/radeon_state.c

index fc7670b..e135ce8 100644 (file)
@@ -10,12 +10,16 @@ SRCS    = \
        drm_drawable.c \
        drm_drv.c \
        drm_fops.c \
+       drm_hashtab.c \
        drm_ioctl.c \
        drm_irq.c \
        drm_lock.c \
        drm_memory.c \
+       drm_mm.c \
        drm_pci.c \
        drm_scatter.c \
+       drm_sman.c \
+       drm_subr_hash.c \
        drm_sysctl.c \
        drm_vm.c
 
index 086258b..b7752ce 100644 (file)
@@ -63,6 +63,8 @@ struct drm_file;
 #include <vm/pmap.h>
 #include <vm/vm_extern.h>
 #include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
 #include <vm/vm_param.h>
 #include <machine/param.h>
 #include <machine/pmap.h>
@@ -140,6 +142,8 @@ MALLOC_DECLARE(DRM_MEM_AGPLISTS);
 MALLOC_DECLARE(DRM_MEM_CTXBITMAP);
 MALLOC_DECLARE(DRM_MEM_SGLISTS);
 MALLOC_DECLARE(DRM_MEM_DRAWABLE);
+MALLOC_DECLARE(DRM_MEM_MM);
+MALLOC_DECLARE(DRM_MEM_HASHTAB);
 
 #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)
 
@@ -184,6 +188,11 @@ typedef void                       irqreturn_t;
 #define IRQ_HANDLED            /* nothing */
 #define IRQ_NONE               /* nothing */
 
+#define unlikely(x)            __builtin_expect(!!(x), 0)
+#define container_of(ptr, type, member) ({                     \
+       __typeof( ((type *)0)->member ) *__mptr = (ptr);        \
+       (type *)( (char *)__mptr - offsetof(type,member) );})
+
 enum {
        DRM_IS_NOT_AGP,
        DRM_IS_AGP,
diff --git a/sys/dev/drm/drm_hashtab.c b/sys/dev/drm/drm_hashtab.c
new file mode 100644 (file)
index 0000000..e55c76e
--- /dev/null
@@ -0,0 +1,182 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ *
+ * __FBSDID("$FreeBSD: src/sys/dev/drm/drm_hashtab.c,v 1.1 2010/01/31 14:25:29 rnoland Exp $");
+ **************************************************************************/
+
+/*
+ * Simple open hash tab implementation.
+ *
+ * Authors:
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#include "dev/drm/drmP.h"
+#include "dev/drm/drm_hashtab.h"
+
+#if defined(__DragonFly__)
+#include "dev/drm/drm_priv_hash.h"
+#else
+#include <sys/hash.h>
+#endif
+
+int drm_ht_create(struct drm_open_hash *ht, unsigned int order)
+{
+       ht->size = 1 << order;
+       ht->order = order;
+       ht->table = NULL;
+       ht->table = drm_hashinit(ht->size, DRM_MEM_HASHTAB, &ht->mask);
+       if (!ht->table) {
+               DRM_ERROR("Out of memory for hash table\n");
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key)
+{
+       struct drm_hash_item *entry;
+       struct drm_hash_item_list *h_list;
+       unsigned int hashed_key;
+       int count = 0;
+
+       hashed_key = hash32_buf(&key, sizeof(key), ht->order);
+       DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key);
+       h_list = &ht->table[hashed_key & ht->mask];
+       LIST_FOREACH(entry, h_list, head)
+               DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key);
+}
+
+static struct drm_hash_item *
+drm_ht_find_key(struct drm_open_hash *ht, unsigned long key)
+{
+       struct drm_hash_item *entry;
+       struct drm_hash_item_list *h_list;
+       unsigned int hashed_key;
+
+       hashed_key = hash32_buf(&key, sizeof(key), ht->order);
+       h_list = &ht->table[hashed_key & ht->mask];
+       LIST_FOREACH(entry, h_list, head) {
+               if (entry->key == key)
+                       return entry;
+               if (entry->key > key)
+                       break;
+       }
+       return NULL;
+}
+
+
+int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item)
+{
+       struct drm_hash_item *entry, *parent;
+       struct drm_hash_item_list *h_list;
+       unsigned int hashed_key;
+       unsigned long key = item->key;
+
+       hashed_key = hash32_buf(&key, sizeof(key), ht->order);
+       h_list = &ht->table[hashed_key & ht->mask];
+       parent = NULL;
+       LIST_FOREACH(entry, h_list, head) {
+               if (entry->key == key)
+                       return -EINVAL;
+               if (entry->key > key)
+                       break;
+               parent = entry;
+       }
+       if (parent) {
+               LIST_INSERT_AFTER(parent, item, head);
+       } else {
+               LIST_INSERT_HEAD(h_list, item, head);
+       }
+       return 0;
+}
+
+/*
+ * Just insert an item and return any "bits" bit key that hasn't been
+ * used before.
+ */
+int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *item,
+                             unsigned long seed, int bits, int shift,
+                             unsigned long add)
+{
+       int ret;
+       unsigned long mask = (1 << bits) - 1;
+       unsigned long first, unshifted_key = 0;
+
+       unshifted_key = hash32_buf(&seed, sizeof(seed), unshifted_key);
+       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(struct drm_open_hash *ht, unsigned long key,
+                    struct drm_hash_item **item)
+{
+       struct drm_hash_item *entry;
+
+       entry = drm_ht_find_key(ht, key);
+       if (!entry)
+               return -EINVAL;
+
+       *item = entry;
+       return 0;
+}
+
+int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key)
+{
+       struct drm_hash_item *entry;
+
+       entry = drm_ht_find_key(ht, key);
+       if (entry) {
+               LIST_REMOVE(entry, head);
+               return 0;
+       }
+       return -EINVAL;
+}
+
+int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item)
+{
+       LIST_REMOVE(item, head);
+       return 0;
+}
+
+void drm_ht_remove(struct drm_open_hash *ht)
+{
+       if (ht->table) {
+               drm_hashdestroy(ht->table, DRM_MEM_HASHTAB, ht->mask);
+               ht->table = NULL;
+       }
+}
diff --git a/sys/dev/drm/drm_hashtab.h b/sys/dev/drm/drm_hashtab.h
new file mode 100644 (file)
index 0000000..feb0e68
--- /dev/null
@@ -0,0 +1,66 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ *
+ * __FBSDID("$FreeBSD: src/sys/dev/drm/drm_hashtab.h,v 1.1 2010/01/31 14:25:29 rnoland Exp $");
+ **************************************************************************/
+
+/*
+ * 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)
+
+struct drm_hash_item {
+       LIST_ENTRY(drm_hash_item) head;
+       unsigned long key;
+};
+
+struct drm_open_hash {
+       LIST_HEAD(drm_hash_item_list, drm_hash_item) *table;
+       unsigned int  size;
+       unsigned int order;
+       unsigned long mask;
+};
+
+extern int drm_ht_create(struct drm_open_hash *ht, unsigned int order);
+extern int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item);
+extern int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *item,
+                                    unsigned long seed, int bits, int shift,
+                                    unsigned long add);
+extern int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key, struct drm_hash_item **item);
+
+extern void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key);
+extern int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key);
+extern int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item);
+extern void drm_ht_remove(struct drm_open_hash *ht);
+
+#endif
index 15c1b6e..e5a478a 100644 (file)
  *
  */
 
+#include <sys/cdefs.h>
+
+#ifndef _DRM_LINUX_LIST_H_
+#define _DRM_LINUX_LIST_H_
+
 struct list_head {
        struct list_head *next, *prev;
 };
 
-/* Cheat, assume the list_head is at the start of the struct */
-#define list_entry(entry, type, member)        (type *)(entry)
+#define list_entry(ptr, type, member) container_of(ptr,type,member)
+#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
 
 static __inline__ void
 INIT_LIST_HEAD(struct list_head *head) {
@@ -48,6 +53,14 @@ list_empty(struct list_head *head) {
 }
 
 static __inline__ void
+list_add(struct list_head *new, struct list_head *head) {
+        (head)->next->prev = new;
+        (new)->next = (head)->next;
+        (new)->prev = head;
+        (head)->next = new;
+}
+
+static __inline__ void
 list_add_tail(struct list_head *entry, struct list_head *head) {
        (entry)->prev = (head)->prev;
        (entry)->next = head;
@@ -61,6 +74,13 @@ list_del(struct list_head *entry) {
        (entry)->prev->next = (entry)->next;
 }
 
+static __inline__ void
+list_del_init(struct list_head *entry) {
+       (entry)->next->prev = (entry)->prev;
+       (entry)->prev->next = (entry)->next;
+       INIT_LIST_HEAD(entry);
+}
+
 #define list_for_each(entry, head)                             \
     for (entry = (head)->next; entry != head; entry = (entry)->next)
 
@@ -73,3 +93,17 @@ list_del(struct list_head *entry) {
        entry != head;                                          \
        entry = temp, temp = entry->next)
 
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:        the type * to use as a loop cursor.
+ * @n:          another type * to use as temporary storage
+ * @head:       the head for your list.
+ * @member:     the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)                 \
+       for (pos = list_entry((head)->next, __typeof(*pos), member),    \
+           n = list_entry(pos->member.next, __typeof(*pos), member);   \
+           &pos->member != (head);                                     \
+           pos = n, n = list_entry(n->member.next, __typeof(*n), member))
+
+#endif /* _DRM_LINUX_LIST_H_ */
index 85c0545..41a641c 100644 (file)
@@ -57,6 +57,8 @@ MALLOC_DEFINE(DRM_MEM_CTXBITMAP, "drm_ctxbitmap",
     "DRM CTXBITMAP Data Structures");
 MALLOC_DEFINE(DRM_MEM_SGLISTS, "drm_sglists", "DRM SGLISTS Data Structures");
 MALLOC_DEFINE(DRM_MEM_DRAWABLE, "drm_drawable", "DRM DRAWABLE Data Structures");
+MALLOC_DEFINE(DRM_MEM_MM, "drm_sman", "DRM MEMORY MANAGER Data Structures");
+MALLOC_DEFINE(DRM_MEM_HASHTAB, "drm_hashtab", "DRM HASHTABLE Data Structures");
 
 void drm_mem_init(void)
 {
diff --git a/sys/dev/drm/drm_mm.c b/sys/dev/drm/drm_mm.c
new file mode 100644 (file)
index 0000000..98ce850
--- /dev/null
@@ -0,0 +1,366 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ *
+ * __FBSDID("$FreeBSD: src/sys/dev/drm/drm_mm.c,v 1.1 2010/01/31 14:25:29 rnoland Exp $");
+ **************************************************************************/
+
+/*
+ * 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 "dev/drm/drmP.h"
+#include "dev/drm/drm_mm.h"
+
+#define MM_UNUSED_TARGET 4
+
+unsigned long drm_mm_tail_space(struct drm_mm *mm)
+{
+       struct list_head *tail_node;
+       struct drm_mm_node *entry;
+
+       tail_node = mm->ml_entry.prev;
+       entry = list_entry(tail_node, struct drm_mm_node, ml_entry);
+       if (!entry->free)
+               return 0;
+
+       return entry->size;
+}
+
+int drm_mm_remove_space_from_tail(struct drm_mm *mm, unsigned long size)
+{
+       struct list_head *tail_node;
+       struct drm_mm_node *entry;
+
+       tail_node = mm->ml_entry.prev;
+       entry = list_entry(tail_node, struct drm_mm_node, ml_entry);
+       if (!entry->free)
+               return -ENOMEM;
+
+       if (entry->size <= size)
+               return -ENOMEM;
+
+       entry->size -= size;
+       return 0;
+}
+
+static struct drm_mm_node *drm_mm_kmalloc(struct drm_mm *mm, int atomic)
+{
+       struct drm_mm_node *child;
+
+       if (atomic)
+               child = malloc(sizeof(*child), DRM_MEM_MM, M_NOWAIT);
+       else
+               child = malloc(sizeof(*child), DRM_MEM_MM, M_WAITOK);
+
+       if (unlikely(child == NULL)) {
+               DRM_SPINLOCK(&mm->unused_lock);
+               if (list_empty(&mm->unused_nodes))
+                       child = NULL;
+               else {
+                       child =
+                           list_entry(mm->unused_nodes.next,
+                                      struct drm_mm_node, fl_entry);
+                       list_del(&child->fl_entry);
+                       --mm->num_unused;
+               }
+               DRM_SPINUNLOCK(&mm->unused_lock);
+       }
+       return child;
+}
+
+int drm_mm_pre_get(struct drm_mm *mm)
+{
+       struct drm_mm_node *node;
+
+       DRM_SPINLOCK(&mm->unused_lock);
+       while (mm->num_unused < MM_UNUSED_TARGET) {
+               DRM_SPINUNLOCK(&mm->unused_lock);
+               node = malloc(sizeof(*node), DRM_MEM_MM, M_WAITOK);
+               DRM_SPINLOCK(&mm->unused_lock);
+
+               if (unlikely(node == NULL)) {
+                       int ret = (mm->num_unused < 2) ? -ENOMEM : 0;
+                       DRM_SPINUNLOCK(&mm->unused_lock);
+                       return ret;
+               }
+               ++mm->num_unused;
+               list_add_tail(&node->fl_entry, &mm->unused_nodes);
+       }
+       DRM_SPINUNLOCK(&mm->unused_lock);
+       return 0;
+}
+
+static int drm_mm_create_tail_node(struct drm_mm *mm,
+                                  unsigned long start,
+                                  unsigned long size, int atomic)
+{
+       struct drm_mm_node *child;
+
+       child = drm_mm_kmalloc(mm, atomic);
+       if (unlikely(child == NULL))
+               return -ENOMEM;
+
+       child->free = 1;
+       child->size = size;
+       child->start = start;
+       child->mm = mm;
+
+       list_add_tail(&child->ml_entry, &mm->ml_entry);
+       list_add_tail(&child->fl_entry, &mm->fl_entry);
+
+       return 0;
+}
+
+int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size, int atomic)
+{
+       struct list_head *tail_node;
+       struct drm_mm_node *entry;
+
+       tail_node = mm->ml_entry.prev;
+       entry = list_entry(tail_node, struct drm_mm_node, ml_entry);
+       if (!entry->free) {
+               return drm_mm_create_tail_node(mm, entry->start + entry->size,
+                                              size, atomic);
+       }
+       entry->size += size;
+       return 0;
+}
+
+static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent,
+                                                unsigned long size,
+                                                int atomic)
+{
+       struct drm_mm_node *child;
+
+       child = drm_mm_kmalloc(parent->mm, atomic);
+       if (unlikely(child == NULL))
+               return NULL;
+
+       INIT_LIST_HEAD(&child->fl_entry);
+
+       child->free = 0;
+       child->size = size;
+       child->start = parent->start;
+       child->mm = parent->mm;
+
+       list_add_tail(&child->ml_entry, &parent->ml_entry);
+       INIT_LIST_HEAD(&child->fl_entry);
+
+       parent->size -= size;
+       parent->start += size;
+       return child;
+}
+
+
+struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node,
+                                            unsigned long size,
+                                            unsigned alignment,
+                                            int atomic)
+{
+
+       struct drm_mm_node *align_splitoff = NULL;
+       unsigned tmp = 0;
+
+       if (alignment)
+               tmp = node->start % alignment;
+
+       if (tmp) {
+               align_splitoff =
+                   drm_mm_split_at_start(node, alignment - tmp, atomic);
+               if (unlikely(align_splitoff == NULL))
+                       return NULL;
+       }
+
+       if (node->size == size) {
+               list_del_init(&node->fl_entry);
+               node->free = 0;
+       } else {
+               node = drm_mm_split_at_start(node, size, atomic);
+       }
+
+       if (align_splitoff)
+               drm_mm_put_block(align_splitoff);
+
+       return node;
+}
+
+/*
+ * 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(struct drm_mm_node *cur)
+{
+
+       struct drm_mm *mm = cur->mm;
+       struct list_head *cur_head = &cur->ml_entry;
+       struct list_head *root_head = &mm->ml_entry;
+       struct drm_mm_node *prev_node = NULL;
+       struct drm_mm_node *next_node;
+
+       int merged = 0;
+
+       if (cur_head->prev != root_head) {
+               prev_node =
+                   list_entry(cur_head->prev, struct drm_mm_node, 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, struct drm_mm_node, 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);
+                               if (mm->num_unused < MM_UNUSED_TARGET) {
+                                       list_add(&next_node->fl_entry,
+                                                &mm->unused_nodes);
+                                       ++mm->num_unused;
+                               } else
+                                       free(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, &mm->fl_entry);
+       } else {
+               list_del(&cur->ml_entry);
+               if (mm->num_unused < MM_UNUSED_TARGET) {
+                       list_add(&cur->fl_entry, &mm->unused_nodes);
+                       ++mm->num_unused;
+               } else
+                       free(cur, DRM_MEM_MM);
+       }
+}
+
+struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm,
+                                      unsigned long size,
+                                      unsigned alignment, int best_match)
+{
+       struct list_head *list;
+       const struct list_head *free_stack = &mm->fl_entry;
+       struct drm_mm_node *entry;
+       struct drm_mm_node *best;
+       unsigned long best_size;
+       unsigned wasted;
+
+       best = NULL;
+       best_size = ~0UL;
+
+       list_for_each(list, free_stack) {
+               entry = list_entry(list, struct drm_mm_node, fl_entry);
+               wasted = 0;
+
+               if (entry->size < size)
+                       continue;
+
+               if (alignment) {
+                       register unsigned tmp = entry->start % alignment;
+                       if (tmp)
+                               wasted += alignment - tmp;
+               }
+
+               if (entry->size >= size + wasted) {
+                       if (!best_match)
+                               return entry;
+                       if (size < best_size) {
+                               best = entry;
+                               best_size = entry->size;
+                       }
+               }
+       }
+
+       return best;
+}
+
+int drm_mm_clean(struct drm_mm * mm)
+{
+       struct list_head *head = &mm->ml_entry;
+
+       return (head->next->next == head);
+}
+
+int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
+{
+       INIT_LIST_HEAD(&mm->ml_entry);
+       INIT_LIST_HEAD(&mm->fl_entry);
+       INIT_LIST_HEAD(&mm->unused_nodes);
+       mm->num_unused = 0;
+       DRM_SPININIT(&mm->unused_lock, "drm_unused");
+
+       return drm_mm_create_tail_node(mm, start, size, 0);
+}
+
+void drm_mm_takedown(struct drm_mm * mm)
+{
+       struct list_head *bnode = mm->fl_entry.next;
+       struct drm_mm_node *entry;
+       struct drm_mm_node *next;
+
+       entry = list_entry(bnode, struct drm_mm_node, fl_entry);
+
+       if (entry->ml_entry.next != &mm->ml_entry ||
+           entry->fl_entry.next != &mm->fl_entry) {
+               DRM_ERROR("Memory manager not clean. Delaying takedown\n");
+               return;
+       }
+
+       list_del(&entry->fl_entry);
+       list_del(&entry->ml_entry);
+       free(entry, DRM_MEM_MM);
+
+       DRM_SPINLOCK(&mm->unused_lock);
+       list_for_each_entry_safe(entry, next, &mm->unused_nodes, fl_entry) {
+               list_del(&entry->fl_entry);
+               free(entry, DRM_MEM_MM);
+               --mm->num_unused;
+       }
+       DRM_SPINUNLOCK(&mm->unused_lock);
+
+       DRM_SPINUNINIT(&mm->unused_lock);
+
+       KASSERT(mm->num_unused == 0, ("num_unused != 0"));
+}
diff --git a/sys/dev/drm/drm_mm.h b/sys/dev/drm/drm_mm.h
new file mode 100644 (file)
index 0000000..f9a9e8f
--- /dev/null
@@ -0,0 +1,98 @@
+/**************************************************************************
+ *
+ * Copyright 2006-2008 Tungsten Graphics, Inc., Cedar Park, TX. 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.
+ *
+ *
+ * __FBSDID("$FreeBSD: src/sys/dev/drm/drm_mm.h,v 1.1 2010/01/31 14:25:29 rnoland Exp $");
+ **************************************************************************/
+
+/*
+ * Authors:
+ * Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
+ */
+
+#ifndef _DRM_MM_H_
+#define _DRM_MM_H_
+
+#include "dev/drm/drm_linux_list.h"
+
+struct drm_mm_node {
+       struct list_head fl_entry;
+       struct list_head ml_entry;
+       int free;
+       unsigned long start;
+       unsigned long size;
+       struct drm_mm *mm;
+       void *private;
+};
+
+struct drm_mm {
+       struct list_head fl_entry;
+       struct list_head ml_entry;
+       struct list_head unused_nodes;
+       int num_unused;
+       DRM_SPINTYPE unused_lock;
+};
+
+/*
+ * Basic range manager support (drm_mm.c)
+ */
+extern struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node,
+                                                   unsigned long size,
+                                                   unsigned alignment,
+                                                   int atomic);
+static inline struct drm_mm_node *drm_mm_get_block(struct drm_mm_node *parent,
+                                                  unsigned long size,
+                                                  unsigned alignment)
+{
+       return drm_mm_get_block_generic(parent, size, alignment, 0);
+}
+static inline struct drm_mm_node *drm_mm_get_block_atomic(struct drm_mm_node *parent,
+                                                         unsigned long size,
+                                                         unsigned alignment)
+{
+       return drm_mm_get_block_generic(parent, size, alignment, 1);
+}
+extern void drm_mm_put_block(struct drm_mm_node *cur);
+extern struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm,
+                                             unsigned long size,
+                                             unsigned alignment,
+                                             int best_match);
+extern int drm_mm_init(struct drm_mm *mm, unsigned long start,
+                      unsigned long size);
+extern void drm_mm_takedown(struct drm_mm *mm);
+extern int drm_mm_clean(struct drm_mm *mm);
+extern unsigned long drm_mm_tail_space(struct drm_mm *mm);
+extern int drm_mm_remove_space_from_tail(struct drm_mm *mm,
+                                        unsigned long size);
+extern int drm_mm_add_space_to_tail(struct drm_mm *mm,
+                                   unsigned long size, int atomic);
+extern int drm_mm_pre_get(struct drm_mm *mm);
+
+static inline struct drm_mm *drm_get_mm(struct drm_mm_node *block)
+{
+       return block->mm;
+}
+
+#endif
index a2acc89..a6c6a58 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $FreeBSD$
+ * $FreeBSD: src/sys/dev/drm/drm_pciids.h,v 1.21 2010/03/13 11:51:18 rnoland Exp $
  */
 /*
    This file is auto-generated from the drm_pciids.txt in the DRM CVS
        {0x1002, 0x9440, CHIP_RV770|RADEON_NEW_MEMMAP, "ATI Radeon 4800 Series"}, \
        {0x1002, 0x9441, CHIP_RV770|RADEON_NEW_MEMMAP, "ATI Radeon 4870 X2"}, \
        {0x1002, 0x9442, CHIP_RV770|RADEON_NEW_MEMMAP, "ATI Radeon 4800 Series"}, \
+       {0x1002, 0x9443, CHIP_RV770|RADEON_NEW_MEMMAP, "ATI Radeon 4850 X2"}, \
        {0x1002, 0x944C, CHIP_RV770|RADEON_NEW_MEMMAP, "ATI Radeon 4800 Series"}, \
        {0x1002, 0x9450, CHIP_RV770|RADEON_NEW_MEMMAP, "AMD FireStream 9270"}, \
        {0x1002, 0x9452, CHIP_RV770|RADEON_NEW_MEMMAP, "AMD FireStream 9250"}, \
        {0x8086, 0x29B2, CHIP_I9XX|CHIP_I915, "Intel Q35"}, \
        {0x8086, 0x29D2, CHIP_I9XX|CHIP_I915, "Intel Q33"}, \
        {0x8086, 0x2A42, CHIP_I9XX|CHIP_I965, "Mobile Intel® GM45 Express Chipset"}, \
-       {0x8086, 0x2E02, CHIP_I9XX|CHIP_I965, "Intel Integrated Graphics Device"}, \
+       {0x8086, 0x2E02, CHIP_I9XX|CHIP_I965, "Intel Eaglelake"}, \
+       {0x8086, 0xA001, CHIP_I9XX|CHIP_I965, "Intel Pineview"}, \
+       {0x8086, 0xA011, CHIP_I9XX|CHIP_I965, "Intel Pineview (M)"}, \
        {0x8086, 0x2E12, CHIP_I9XX|CHIP_I965, "Intel Q45/Q43"}, \
        {0x8086, 0x2E22, CHIP_I9XX|CHIP_I965, "Intel G45/G43"}, \
        {0x8086, 0x2E32, CHIP_I9XX|CHIP_I965, "Intel G41"}, \
-       {0x8086, 0xA001, CHIP_I9XX|CHIP_I965, "Intel IGD"}, \
-       {0x8086, 0xA011, CHIP_I9XX|CHIP_I965, "Intel IGD"}, \
        {0, 0, 0, NULL}
 
 #define imagine_PCI_IDS \
diff --git a/sys/dev/drm/drm_priv_hash.h b/sys/dev/drm/drm_priv_hash.h
new file mode 100644 (file)
index 0000000..bc4e874
--- /dev/null
@@ -0,0 +1,130 @@
+/*-
+ * Copyright (c) 2001 Tobias Weingartner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $OpenBSD: hash.h,v 1.4 2004/05/25 18:37:23 jmc Exp $
+ * $FreeBSD: src/sys/sys/hash.h,v 1.3 2007/04/09 22:55:14 thompsa Exp $
+ */
+
+#ifndef _DRM_PRIV_HASH_H
+#define        _DRM_PRIV_HASH_H_
+#include <sys/types.h>
+
+/* Convenience */
+#ifndef        HASHINIT
+#define        HASHINIT        5381
+#define        HASHSTEP(x,c)   (((x << 5) + x) + (c))
+#endif
+
+/*
+ * Return a 32-bit hash of the given buffer.  The init
+ * value should be 0, or the previous hash value to extend
+ * the previous hash.
+ */
+static __inline uint32_t
+hash32_buf(const void *buf, size_t len, uint32_t hash)
+{
+       const unsigned char *p = buf;
+
+       while (len--)
+               hash = HASHSTEP(hash, *p++);
+
+       return hash;
+}
+
+/*
+ * Return a 32-bit hash of the given string.
+ */
+static __inline uint32_t
+hash32_str(const void *buf, uint32_t hash)
+{
+       const unsigned char *p = buf;
+
+       while (*p)
+               hash = HASHSTEP(hash, *p++);
+
+       return hash;
+}
+
+/*
+ * Return a 32-bit hash of the given string, limited by N.
+ */
+static __inline uint32_t
+hash32_strn(const void *buf, size_t len, uint32_t hash)
+{
+       const unsigned char *p = buf;
+
+       while (*p && len--)
+               hash = HASHSTEP(hash, *p++);
+
+       return hash;
+}
+
+/*
+ * Return a 32-bit hash of the given string terminated by C,
+ * (as well as 0).  This is mainly here as a helper for the
+ * namei() hashing of path name parts.
+ */
+static __inline uint32_t
+hash32_stre(const void *buf, int end, const char **ep, uint32_t hash)
+{
+       const unsigned char *p = buf;
+
+       while (*p && (*p != end))
+               hash = HASHSTEP(hash, *p++);
+
+       if (ep)
+               *ep = p;
+
+       return hash;
+}
+
+/*
+ * Return a 32-bit hash of the given string, limited by N,
+ * and terminated by C (as well as 0).  This is mainly here
+ * as a helper for the namei() hashing of path name parts.
+ */
+static __inline uint32_t
+hash32_strne(const void *buf, size_t len, int end, const char **ep,
+    uint32_t hash)
+{
+       const unsigned char *p = buf;
+
+       while (*p && (*p != end) && len--)
+               hash = HASHSTEP(hash, *p++);
+
+       if (ep)
+               *ep = p;
+
+       return hash;
+}
+
+/* Added to act as private header files for hash function */
+
+void *
+drm_hashinit(int elements, struct malloc_type *type, u_long *hashmask);
+
+void
+drm_hashdestroy(void *vhashtbl, struct malloc_type *type, u_long hashmask);
+
+#endif /* !_DRM_PRIV_HASH_H_ */
diff --git a/sys/dev/drm/drm_sman.c b/sys/dev/drm/drm_sman.c
new file mode 100644 (file)
index 0000000..620cdc5
--- /dev/null
@@ -0,0 +1,350 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ *
+ * __FBSDID("$FreeBSD: src/sys/dev/drm/drm_sman.c,v 1.1 2010/01/31 14:25:29 rnoland Exp $");
+ **************************************************************************/
+
+/*
+ * 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 "dev/drm/drmP.h"
+#include "dev/drm/drm_sman.h"
+
+struct drm_owner_item {
+       struct drm_hash_item owner_hash;
+       struct list_head sman_list;
+       struct list_head mem_blocks;
+};
+
+void drm_sman_takedown(struct drm_sman * 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);
+}
+
+int
+drm_sman_init(struct drm_sman * sman, unsigned int num_managers,
+             unsigned int user_order, unsigned int owner_order)
+{
+       int ret = 0;
+
+       sman->mm = (struct drm_sman_mm *) 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;
+}
+
+static void *drm_sman_mm_allocate(void *private, unsigned long size,
+                                 unsigned alignment)
+{
+       struct drm_mm *mm = (struct drm_mm *) private;
+       struct drm_mm_node *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)
+{
+       struct drm_mm_node *node = (struct drm_mm_node *) ref;
+
+       drm_mm_put_block(node);
+}
+
+static void drm_sman_mm_destroy(void *private)
+{
+       struct drm_mm *mm = (struct drm_mm *) private;
+       drm_mm_takedown(mm);
+       drm_free(mm, sizeof(*mm), DRM_MEM_MM);
+}
+
+static unsigned long drm_sman_mm_offset(void *private, void *ref)
+{
+       struct drm_mm_node *node = (struct drm_mm_node *) ref;
+       return node->start;
+}
+
+int
+drm_sman_set_range(struct drm_sman * sman, unsigned int manager,
+                  unsigned long start, unsigned long size)
+{
+       struct drm_sman_mm *sman_mm;
+       struct drm_mm *mm;
+       int ret;
+
+       KASSERT(manager < sman->num_managers, ("Invalid manager"));
+
+       sman_mm = &sman->mm[manager];
+       mm = malloc(sizeof(*mm), DRM_MEM_MM, M_WAITOK | M_ZERO);
+       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;
+}
+
+int
+drm_sman_set_manager(struct drm_sman * sman, unsigned int manager,
+                    struct drm_sman_mm * allocator)
+{
+       KASSERT(manager < sman->num_managers, ("Invalid manager"));
+       sman->mm[manager] = *allocator;
+
+       return 0;
+}
+
+static struct drm_owner_item *drm_sman_get_owner_item(struct drm_sman * sman,
+                                                unsigned long owner)
+{
+       int ret;
+       struct drm_hash_item *owner_hash_item;
+       struct drm_owner_item *owner_item;
+
+       ret = drm_ht_find_item(&sman->owner_hash_tab, owner, &owner_hash_item);
+       if (!ret) {
+               return drm_hash_entry(owner_hash_item, struct drm_owner_item,
+                                     owner_hash);
+       }
+
+       owner_item = malloc(sizeof(*owner_item), DRM_MEM_MM, M_WAITOK | M_ZERO);
+       if (!owner_item)
+               goto out;
+
+       INIT_LIST_HEAD(&owner_item->mem_blocks);
+       owner_item->owner_hash.key = owner;
+       DRM_DEBUG("owner_item = %p, mem_blocks = %p\n", owner_item, &owner_item->mem_blocks);
+       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;
+}
+
+struct drm_memblock_item *drm_sman_alloc(struct drm_sman *sman, unsigned int manager,
+                                   unsigned long size, unsigned alignment,
+                                   unsigned long owner)
+{
+       void *tmp;
+       struct drm_sman_mm *sman_mm;
+       struct drm_owner_item *owner_item;
+       struct drm_memblock_item *memblock;
+
+       KASSERT(manager < sman->num_managers, ("Invalid manager"));
+
+       sman_mm = &sman->mm[manager];
+       tmp = sman_mm->allocate(sman_mm->private, size, alignment);
+
+       if (!tmp) {
+               return NULL;
+       }
+
+       memblock = malloc(sizeof(*memblock), DRM_MEM_MM, M_WAITOK | M_ZERO);
+       DRM_DEBUG("allocated mem_block %p\n", memblock);
+       if (!memblock)
+               goto out;
+
+       memblock->mm_info = tmp;
+       memblock->mm = sman_mm;
+       memblock->sman = sman;
+       INIT_LIST_HEAD(&memblock->owner_list);
+
+       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;
+
+       DRM_DEBUG("owner_item = %p, mem_blocks = %p\n", owner_item, &owner_item->mem_blocks);
+       DRM_DEBUG("owner_list.prev = %p, mem_blocks.prev = %p\n", memblock->owner_list.prev, owner_item->mem_blocks.prev);
+       DRM_DEBUG("owner_list.next = %p, mem_blocks.next = %p\n", memblock->owner_list.next, owner_item->mem_blocks.next);
+       list_add_tail(&memblock->owner_list, &owner_item->mem_blocks);
+
+       DRM_DEBUG("Complete\n");
+       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;
+}
+
+static void drm_sman_free(struct drm_memblock_item *item)
+{
+       struct drm_sman *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(struct drm_sman *sman, unsigned int key)
+{
+       struct drm_hash_item *hash_item;
+       struct drm_memblock_item *memblock_item;
+
+       if (drm_ht_find_item(&sman->user_hash_tab, key, &hash_item))
+               return -EINVAL;
+
+       memblock_item = drm_hash_entry(hash_item, struct drm_memblock_item,
+                                      user_hash);
+       drm_sman_free(memblock_item);
+       return 0;
+}
+
+static void drm_sman_remove_owner(struct drm_sman *sman,
+                                 struct drm_owner_item *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(struct drm_sman *sman, unsigned long owner)
+{
+
+       struct drm_hash_item *hash_item;
+       struct drm_owner_item *owner_item;
+
+       if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) {
+               return -1;
+       }
+
+       owner_item = drm_hash_entry(hash_item, struct drm_owner_item, owner_hash);
+       DRM_DEBUG("cleaning owner_item %p\n", owner_item);
+       if (owner_item->mem_blocks.next == &owner_item->mem_blocks) {
+               drm_sman_remove_owner(sman, owner_item);
+               return -1;
+       }
+
+       return 0;
+}
+
+static void drm_sman_do_owner_cleanup(struct drm_sman *sman,
+                                     struct drm_owner_item *owner_item)
+{
+       struct drm_memblock_item *entry, *next;
+
+       list_for_each_entry_safe(entry, next, &owner_item->mem_blocks,
+                                owner_list) {
+               DRM_DEBUG("freeing mem_block %p\n", entry);
+               drm_sman_free(entry);
+       }
+       drm_sman_remove_owner(sman, owner_item);
+}
+
+void drm_sman_owner_cleanup(struct drm_sman *sman, unsigned long owner)
+{
+
+       struct drm_hash_item *hash_item;
+       struct drm_owner_item *owner_item;
+
+       if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) {
+
+               return;
+       }
+
+       owner_item = drm_hash_entry(hash_item, struct drm_owner_item, owner_hash);
+       drm_sman_do_owner_cleanup(sman, owner_item);
+}
+
+void drm_sman_cleanup(struct drm_sman *sman)
+{
+       struct drm_owner_item *entry, *next;
+       unsigned int i;
+       struct drm_sman_mm *sman_mm;
+
+       DRM_DEBUG("sman = %p, owner_items = %p\n",
+           sman, &sman->owner_items);
+       list_for_each_entry_safe(entry, next, &sman->owner_items, sman_list) {
+               DRM_DEBUG("cleaning owner_item = %p\n", entry);
+               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;
+                       }
+               }
+       }
+}
diff --git a/sys/dev/drm/drm_sman.h b/sys/dev/drm/drm_sman.h
new file mode 100644 (file)
index 0000000..63df55e
--- /dev/null
@@ -0,0 +1,179 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ *
+ * __FBSDID("$FreeBSD: src/sys/dev/drm/drm_sman.h,v 1.1 2010/01/31 14:25:29 rnoland Exp $");
+ **************************************************************************/
+
+/*
+ * 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 "dev/drm/drm_hashtab.h"
+#include "dev/drm/drm_linux_list.h"
+#include "dev/drm/drm_mm.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.
+ */
+
+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);
+};
+
+struct drm_memblock_item {
+       struct list_head owner_list;
+       struct drm_hash_item user_hash;
+       void *mm_info;
+       struct drm_sman_mm *mm;
+       struct drm_sman *sman;
+};
+
+struct drm_sman {
+       struct drm_sman_mm *mm;
+       int num_managers;
+       struct drm_open_hash owner_hash_tab;
+       struct drm_open_hash user_hash_tab;
+       struct list_head owner_items;
+};
+
+/*
+ * 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(struct drm_sman * 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(struct drm_sman * 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(struct drm_sman * 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(struct drm_sman * sman, unsigned int mananger,
+                               struct drm_sman_mm * allocator);
+
+/*
+ * Allocate a memory block. Aligment is not implemented yet.
+ */
+
+extern struct drm_memblock_item *drm_sman_alloc(struct drm_sman * 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(struct drm_sman * 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(struct drm_sman * 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(struct drm_sman * sman, unsigned long owner);
+
+/*
+ * Frees all stale memory blocks associated with the memory manager.
+ * See idling above.
+ */
+
+extern void drm_sman_cleanup(struct drm_sman * sman);
+
+#endif
diff --git a/sys/dev/drm/drm_subr_hash.c b/sys/dev/drm/drm_subr_hash.c
new file mode 100644 (file)
index 0000000..5feb5f4
--- /dev/null
@@ -0,0 +1,137 @@
+/*-
+ * Copyright (c) 1982, 1986, 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)kern_subr.c 8.3 (Berkeley) 1/21/94
+ * __FBSDID("$FreeBSD: src/sys/kern/subr_hash.c,v 1.1 2010/02/21 19:53:33 ed Exp $");
+ */
+
+#include "dev/drm/drmP.h"
+#include "dev/drm/drm_priv_hash.h"
+
+/* From FreeBSD's sys/systm.h */
+#ifndef HASH_NOWAIT
+#define HASH_NOWAIT     0x00000001
+#endif
+#ifndef HASH_WAITOK
+#define HASH_WAITOK     0x00000002
+#endif
+
+/*
+ * General routine to allocate a hash table with control of memory flags.
+ */
+void *
+drm_hashinit_flags(int elements, struct malloc_type *type, u_long *hashmask,
+    int flags)
+{
+       long hashsize;
+       LIST_HEAD(generic, generic) *hashtbl;
+       int i;
+
+       if (elements <= 0)
+               panic("hashinit: bad elements");
+
+       /* Exactly one of HASH_WAITOK and HASH_NOWAIT must be set. */
+       KASSERT((flags & HASH_WAITOK) ^ (flags & HASH_NOWAIT),
+           ("Bad flags (0x%x) passed to hashinit_flags", flags));
+
+       for (hashsize = 1; hashsize <= elements; hashsize <<= 1)
+               continue;
+       hashsize >>= 1;
+
+       if (flags & HASH_NOWAIT)
+               hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl),
+                   type, M_NOWAIT);
+       else
+               hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl),
+                   type, M_WAITOK);
+
+       if (hashtbl != NULL) {
+               for (i = 0; i < hashsize; i++)
+                       LIST_INIT(&hashtbl[i]);
+               *hashmask = hashsize - 1;
+       }
+       return (hashtbl);
+}
+
+/*
+ * Allocate and initialize a hash table with default flag: may sleep.
+ */
+void *
+drm_hashinit(int elements, struct malloc_type *type, u_long *hashmask)
+{
+
+       return (drm_hashinit_flags(elements, type, hashmask, HASH_WAITOK));
+}
+
+void
+drm_hashdestroy(void *vhashtbl, struct malloc_type *type, u_long hashmask)
+{
+       LIST_HEAD(generic, generic) *hashtbl, *hp;
+
+       hashtbl = vhashtbl;
+       for (hp = hashtbl; hp <= &hashtbl[hashmask]; hp++)
+               if (!LIST_EMPTY(hp))
+                       panic("hashdestroy: hash not empty");
+       free(hashtbl, type);
+}
+
+static const int primes[] = { 1, 13, 31, 61, 127, 251, 509, 761, 1021, 1531,
+                       2039, 2557, 3067, 3583, 4093, 4603, 5119, 5623, 6143,
+                       6653, 7159, 7673, 8191, 12281, 16381, 24571, 32749 };
+#define NPRIMES (sizeof(primes) / sizeof(primes[0]))
+
+/*
+ * General routine to allocate a prime number sized hash table.
+ */
+void *
+drm_phashinit(int elements, struct malloc_type *type, u_long *nentries)
+{
+       long hashsize;
+       LIST_HEAD(generic, generic) *hashtbl;
+       int i;
+
+       if (elements <= 0)
+               panic("phashinit: bad elements");
+       for (i = 1, hashsize = primes[1]; hashsize <= elements;) {
+               i++;
+               if (i == NPRIMES)
+                       break;
+               hashsize = primes[i];
+       }
+       hashsize = primes[i - 1];
+       hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, M_WAITOK);
+       for (i = 0; i < hashsize; i++)
+               LIST_INIT(&hashtbl[i]);
+       *nentries = hashsize;
+       return (hashtbl);
+}
index c00fe71..c9e5461 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "dev/drm/drmP.h"
 #include "dev/drm/drm.h"
+#include "dev/drm/drm_mm.h"
 #include "dev/drm/i915_drm.h"
 #include "dev/drm/i915_drv.h"
 #include "dev/drm/drm_pciids.h"
index 711fc68..0669a1b 100644 (file)
@@ -30,6 +30,7 @@
 #ifndef _I915_DRV_H_
 #define _I915_DRV_H_
 
+#include "dev/drm/drm_mm.h"
 #include "dev/drm/i915_reg.h"
 
 /* General customization:
diff --git a/sys/dev/drm/r600_blit.c b/sys/dev/drm/r600_blit.c
new file mode 100644 (file)
index 0000000..c34427a
--- /dev/null
@@ -0,0 +1,1998 @@
+/*-
+ * Copyright 2009 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) 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:
+ *     Alex Deucher <alexander.deucher@amd.com>
+ * __FBSDID("$FreeBSD: src/sys/dev/drm/r600_blit.c,v 1.5 2009/10/30 18:08:46 rnoland Exp $");
+ */
+
+#include "dev/drm/drmP.h"
+#include "dev/drm/drm.h"
+#include "dev/drm/radeon_drm.h"
+#include "dev/drm/radeon_drv.h"
+
+static u32 r6xx_default_state[] =
+{
+       0xc0002400,
+       0x00000000,
+       0xc0012800,
+       0x80000000,
+       0x80000000,
+       0xc0004600,
+       0x00000016,
+       0xc0016800,
+       0x00000010,
+       0x00028000,
+       0xc0016800,
+       0x00000010,
+       0x00008000,
+       0xc0016800,
+       0x00000542,
+       0x07000003,
+       0xc0016800,
+       0x000005c5,
+       0x00000000,
+       0xc0016800,
+       0x00000363,
+       0x00000000,
+       0xc0016800,
+       0x0000060c,
+       0x82000000,
+       0xc0016800,
+       0x0000060e,
+       0x01020204,
+       0xc0016f00,
+       0x00000000,
+       0x00000000,
+       0xc0016f00,
+       0x00000001,
+       0x00000000,
+       0xc0096900,
+       0x0000022a,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0xc0016900,
+       0x00000004,
+       0x00000000,
+       0xc0016900,
+       0x0000000a,
+       0x00000000,
+       0xc0016900,
+       0x0000000b,
+       0x00000000,
+       0xc0016900,
+       0x0000010c,
+       0x00000000,
+       0xc0016900,
+       0x0000010d,
+       0x00000000,
+       0xc0016900,
+       0x00000200,
+       0x00000000,
+       0xc0016900,
+       0x00000343,
+       0x00000060,
+       0xc0016900,
+       0x00000344,
+       0x00000040,
+       0xc0016900,
+       0x00000351,
+       0x0000aa00,
+       0xc0016900,
+       0x00000104,
+       0x00000000,
+       0xc0016900,
+       0x0000010e,
+       0x00000000,
+       0xc0046900,
+       0x00000105,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0xc0036900,
+       0x00000109,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0xc0046900,
+       0x0000030c,
+       0x01000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0xc0046900,
+       0x00000048,
+       0x3f800000,
+       0x00000000,
+       0x3f800000,
+       0x3f800000,
+       0xc0016900,
+       0x0000008e,
+       0x0000000f,
+       0xc0016900,
+       0x00000080,
+       0x00000000,
+       0xc0016900,
+       0x00000083,
+       0x0000ffff,
+       0xc0016900,
+       0x00000084,
+       0x00000000,
+       0xc0016900,
+       0x00000085,
+       0x20002000,
+       0xc0016900,
+       0x00000086,
+       0x00000000,
+       0xc0016900,
+       0x00000087,
+       0x20002000,
+       0xc0016900,
+       0x00000088,
+       0x00000000,
+       0xc0016900,
+       0x00000089,
+       0x20002000,
+       0xc0016900,
+       0x0000008a,
+       0x00000000,
+       0xc0016900,
+       0x0000008b,
+       0x20002000,
+       0xc0016900,
+       0x0000008c,
+       0x00000000,
+       0xc0016900,
+       0x00000094,
+       0x80000000,
+       0xc0016900,
+       0x00000095,
+       0x20002000,
+       0xc0026900,
+       0x000000b4,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x00000096,
+       0x80000000,
+       0xc0016900,
+       0x00000097,
+       0x20002000,
+       0xc0026900,
+       0x000000b6,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x00000098,
+       0x80000000,
+       0xc0016900,
+       0x00000099,
+       0x20002000,
+       0xc0026900,
+       0x000000b8,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x0000009a,
+       0x80000000,
+       0xc0016900,
+       0x0000009b,
+       0x20002000,
+       0xc0026900,
+       0x000000ba,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x0000009c,
+       0x80000000,
+       0xc0016900,
+       0x0000009d,
+       0x20002000,
+       0xc0026900,
+       0x000000bc,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x0000009e,
+       0x80000000,
+       0xc0016900,
+       0x0000009f,
+       0x20002000,
+       0xc0026900,
+       0x000000be,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x000000a0,
+       0x80000000,
+       0xc0016900,
+       0x000000a1,
+       0x20002000,
+       0xc0026900,
+       0x000000c0,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x000000a2,
+       0x80000000,
+       0xc0016900,
+       0x000000a3,
+       0x20002000,
+       0xc0026900,
+       0x000000c2,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x000000a4,
+       0x80000000,
+       0xc0016900,
+       0x000000a5,
+       0x20002000,
+       0xc0026900,
+       0x000000c4,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x000000a6,
+       0x80000000,
+       0xc0016900,
+       0x000000a7,
+       0x20002000,
+       0xc0026900,
+       0x000000c6,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x000000a8,
+       0x80000000,
+       0xc0016900,
+       0x000000a9,
+       0x20002000,
+       0xc0026900,
+       0x000000c8,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x000000aa,
+       0x80000000,
+       0xc0016900,
+       0x000000ab,
+       0x20002000,
+       0xc0026900,
+       0x000000ca,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x000000ac,
+       0x80000000,
+       0xc0016900,
+       0x000000ad,
+       0x20002000,
+       0xc0026900,
+       0x000000cc,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x000000ae,
+       0x80000000,
+       0xc0016900,
+       0x000000af,
+       0x20002000,
+       0xc0026900,
+       0x000000ce,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x000000b0,
+       0x80000000,
+       0xc0016900,
+       0x000000b1,
+       0x20002000,
+       0xc0026900,
+       0x000000d0,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x000000b2,
+       0x80000000,
+       0xc0016900,
+       0x000000b3,
+       0x20002000,
+       0xc0026900,
+       0x000000d2,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x00000293,
+       0x00004010,
+       0xc0016900,
+       0x00000300,
+       0x00000000,
+       0xc0016900,
+       0x00000301,
+       0x00000000,
+       0xc0016900,
+       0x00000312,
+       0xffffffff,
+       0xc0016900,
+       0x00000307,
+       0x00000000,
+       0xc0016900,
+       0x00000308,
+       0x00000000,
+       0xc0016900,
+       0x00000283,
+       0x00000000,
+       0xc0016900,
+       0x00000292,
+       0x00000000,
+       0xc0066900,
+       0x0000010f,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0xc0016900,
+       0x00000206,
+       0x00000000,
+       0xc0016900,
+       0x00000207,
+       0x00000000,
+       0xc0016900,
+       0x00000208,
+       0x00000000,
+       0xc0046900,
+       0x00000303,
+       0x3f800000,
+       0x3f800000,
+       0x3f800000,
+       0x3f800000,
+       0xc0016900,
+       0x00000205,
+       0x00000004,
+       0xc0016900,
+       0x00000280,
+       0x00000000,
+       0xc0016900,
+       0x00000281,
+       0x00000000,
+       0xc0016900,
+       0x0000037e,
+       0x00000000,
+       0xc0016900,
+       0x00000382,
+       0x00000000,
+       0xc0016900,
+       0x00000380,
+       0x00000000,
+       0xc0016900,
+       0x00000383,
+       0x00000000,
+       0xc0016900,
+       0x00000381,
+       0x00000000,
+       0xc0016900,
+       0x00000282,
+       0x00000008,
+       0xc0016900,
+       0x00000302,
+       0x0000002d,
+       0xc0016900,
+       0x0000037f,
+       0x00000000,
+       0xc0016900,
+       0x000001b2,
+       0x00000000,
+       0xc0016900,
+       0x000001b6,
+       0x00000000,
+       0xc0016900,
+       0x000001b7,
+       0x00000000,
+       0xc0016900,
+       0x000001b8,
+       0x00000000,
+       0xc0016900,
+       0x000001b9,
+       0x00000000,
+       0xc0016900,
+       0x00000225,
+       0x00000000,
+       0xc0016900,
+       0x00000229,
+       0x00000000,
+       0xc0016900,
+       0x00000237,
+       0x00000000,
+       0xc0016900,
+       0x00000100,
+       0x00000800,
+       0xc0016900,
+       0x00000101,
+       0x00000000,
+       0xc0016900,
+       0x00000102,
+       0x00000000,
+       0xc0016900,
+       0x000002a8,
+       0x00000000,
+       0xc0016900,
+       0x000002a9,
+       0x00000000,
+       0xc0016900,
+       0x00000103,
+       0x00000000,
+       0xc0016900,
+       0x00000284,
+       0x00000000,
+       0xc0016900,
+       0x00000290,
+       0x00000000,
+       0xc0016900,
+       0x00000285,
+       0x00000000,
+       0xc0016900,
+       0x00000286,
+       0x00000000,
+       0xc0016900,
+       0x00000287,
+       0x00000000,
+       0xc0016900,
+       0x00000288,
+       0x00000000,
+       0xc0016900,
+       0x00000289,
+       0x00000000,
+       0xc0016900,
+       0x0000028a,
+       0x00000000,
+       0xc0016900,
+       0x0000028b,
+       0x00000000,
+       0xc0016900,
+       0x0000028c,
+       0x00000000,
+       0xc0016900,
+       0x0000028d,
+       0x00000000,
+       0xc0016900,
+       0x0000028e,
+       0x00000000,
+       0xc0016900,
+       0x0000028f,
+       0x00000000,
+       0xc0016900,
+       0x000002a1,
+       0x00000000,
+       0xc0016900,
+       0x000002a5,
+       0x00000000,
+       0xc0016900,
+       0x000002ac,
+       0x00000000,
+       0xc0016900,
+       0x000002ad,
+       0x00000000,
+       0xc0016900,
+       0x000002ae,
+       0x00000000,
+       0xc0016900,
+       0x000002c8,
+       0x00000000,
+       0xc0016900,
+       0x00000206,
+       0x00000100,
+       0xc0016900,
+       0x00000204,
+       0x00010000,
+       0xc0036e00,
+       0x00000000,
+       0x00000012,
+       0x00000000,
+       0x00000000,
+       0xc0016900,
+       0x0000008f,
+       0x0000000f,
+       0xc0016900,
+       0x000001e8,
+       0x00000001,
+       0xc0016900,
+       0x00000202,
+       0x00cc0000,
+       0xc0016900,
+       0x00000205,
+       0x00000244,
+       0xc0016900,
+       0x00000203,
+       0x00000210,
+       0xc0016900,
+       0x000001b1,
+       0x00000000,
+       0xc0016900,
+       0x00000185,
+       0x00000000,
+       0xc0016900,
+       0x000001b3,
+       0x00000001,
+       0xc0016900,
+       0x000001b4,
+       0x00000000,
+       0xc0016900,
+       0x00000191,
+       0x00000b00,
+       0xc0016900,
+       0x000001b5,
+       0x00000000,
+};
+
+static u32 r7xx_default_state[] =
+{
+       0xc0012800,
+       0x80000000,
+       0x80000000,
+       0xc0004600,
+       0x00000016,
+       0xc0016800,
+       0x00000010,
+       0x00028000,
+       0xc0016800,
+       0x00000010,
+       0x00008000,
+       0xc0016800,
+       0x00000542,
+       0x07000002,
+       0xc0016800,
+       0x000005c5,
+       0x00000000,
+       0xc0016800,
+       0x00000363,
+       0x00004000,
+       0xc0016800,
+       0x0000060c,
+       0x00000000,
+       0xc0016800,
+       0x0000060e,
+       0x00420204,
+       0xc0016f00,
+       0x00000000,
+       0x00000000,
+       0xc0016f00,
+       0x00000001,
+       0x00000000,
+       0xc0096900,
+       0x0000022a,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0xc0016900,
+       0x00000004,
+       0x00000000,
+       0xc0016900,
+       0x0000000a,
+       0x00000000,
+       0xc0016900,
+       0x0000000b,
+       0x00000000,
+       0xc0016900,
+       0x0000010c,
+       0x00000000,
+       0xc0016900,
+       0x0000010d,
+       0x00000000,
+       0xc0016900,
+       0x00000200,
+       0x00000000,
+       0xc0016900,
+       0x00000343,
+       0x00000060,
+       0xc0016900,
+       0x00000344,
+       0x00000000,
+       0xc0016900,
+       0x00000351,
+       0x0000aa00,
+       0xc0016900,
+       0x00000104,
+       0x00000000,
+       0xc0016900,
+       0x0000010e,
+       0x00000000,
+       0xc0046900,
+       0x00000105,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0xc0046900,
+       0x0000030c,
+       0x01000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0xc0016900,
+       0x0000008e,
+       0x0000000f,
+       0xc0016900,
+       0x00000080,
+       0x00000000,
+       0xc0016900,
+       0x00000083,
+       0x0000ffff,
+       0xc0016900,
+       0x00000084,
+       0x00000000,
+       0xc0016900,
+       0x00000085,
+       0x20002000,
+       0xc0016900,
+       0x00000086,
+       0x00000000,
+       0xc0016900,
+       0x00000087,
+       0x20002000,
+       0xc0016900,
+       0x00000088,
+       0x00000000,
+       0xc0016900,
+       0x00000089,
+       0x20002000,
+       0xc0016900,
+       0x0000008a,
+       0x00000000,
+       0xc0016900,
+       0x0000008b,
+       0x20002000,
+       0xc0016900,
+       0x0000008c,
+       0xaaaaaaaa,
+       0xc0016900,
+       0x00000094,
+       0x80000000,
+       0xc0016900,
+       0x00000095,
+       0x20002000,
+       0xc0026900,
+       0x000000b4,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x00000096,
+       0x80000000,
+       0xc0016900,
+       0x00000097,
+       0x20002000,
+       0xc0026900,
+       0x000000b6,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x00000098,
+       0x80000000,
+       0xc0016900,
+       0x00000099,
+       0x20002000,
+       0xc0026900,
+       0x000000b8,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x0000009a,
+       0x80000000,
+       0xc0016900,
+       0x0000009b,
+       0x20002000,
+       0xc0026900,
+       0x000000ba,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x0000009c,
+       0x80000000,
+       0xc0016900,
+       0x0000009d,
+       0x20002000,
+       0xc0026900,
+       0x000000bc,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x0000009e,
+       0x80000000,
+       0xc0016900,
+       0x0000009f,
+       0x20002000,
+       0xc0026900,
+       0x000000be,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x000000a0,
+       0x80000000,
+       0xc0016900,
+       0x000000a1,
+       0x20002000,
+       0xc0026900,
+       0x000000c0,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x000000a2,
+       0x80000000,
+       0xc0016900,
+       0x000000a3,
+       0x20002000,
+       0xc0026900,
+       0x000000c2,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x000000a4,
+       0x80000000,
+       0xc0016900,
+       0x000000a5,
+       0x20002000,
+       0xc0026900,
+       0x000000c4,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x000000a6,
+       0x80000000,
+       0xc0016900,
+       0x000000a7,
+       0x20002000,
+       0xc0026900,
+       0x000000c6,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x000000a8,
+       0x80000000,
+       0xc0016900,
+       0x000000a9,
+       0x20002000,
+       0xc0026900,
+       0x000000c8,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x000000aa,
+       0x80000000,
+       0xc0016900,
+       0x000000ab,
+       0x20002000,
+       0xc0026900,
+       0x000000ca,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x000000ac,
+       0x80000000,
+       0xc0016900,
+       0x000000ad,
+       0x20002000,
+       0xc0026900,
+       0x000000cc,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x000000ae,
+       0x80000000,
+       0xc0016900,
+       0x000000af,
+       0x20002000,
+       0xc0026900,
+       0x000000ce,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x000000b0,
+       0x80000000,
+       0xc0016900,
+       0x000000b1,
+       0x20002000,
+       0xc0026900,
+       0x000000d0,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x000000b2,
+       0x80000000,
+       0xc0016900,
+       0x000000b3,
+       0x20002000,
+       0xc0026900,
+       0x000000d2,
+       0x00000000,
+       0x3f800000,
+       0xc0016900,
+       0x00000293,
+       0x00514000,
+       0xc0016900,
+       0x00000300,
+       0x00000000,
+       0xc0016900,
+       0x00000301,
+       0x00000000,
+       0xc0016900,
+       0x00000312,
+       0xffffffff,
+       0xc0016900,
+       0x00000307,
+       0x00000000,
+       0xc0016900,
+       0x00000308,
+       0x00000000,
+       0xc0016900,
+       0x00000283,
+       0x00000000,
+       0xc0016900,
+       0x00000292,
+       0x00000000,
+       0xc0066900,
+       0x0000010f,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0xc0016900,
+       0x00000206,
+       0x00000000,
+       0xc0016900,
+       0x00000207,
+       0x00000000,
+       0xc0016900,
+       0x00000208,
+       0x00000000,
+       0xc0046900,
+       0x00000303,
+       0x3f800000,
+       0x3f800000,
+       0x3f800000,
+       0x3f800000,
+       0xc0016900,
+       0x00000205,
+       0x00000004,
+       0xc0016900,
+       0x00000280,
+       0x00000000,
+       0xc0016900,
+       0x00000281,
+       0x00000000,
+       0xc0016900,
+       0x0000037e,
+       0x00000000,
+       0xc0016900,
+       0x00000382,
+       0x00000000,
+       0xc0016900,
+       0x00000380,
+       0x00000000,
+       0xc0016900,
+       0x00000383,
+       0x00000000,
+       0xc0016900,
+       0x00000381,
+       0x00000000,
+       0xc0016900,
+       0x00000282,
+       0x00000008,
+       0xc0016900,
+       0x00000302,
+       0x0000002d,
+       0xc0016900,
+       0x0000037f,
+       0x00000000,
+       0xc0016900,
+       0x000001b2,
+       0x00000001,
+       0xc0016900,
+       0x000001b6,
+       0x00000000,
+       0xc0016900,
+       0x000001b7,
+       0x00000000,
+       0xc0016900,
+       0x000001b8,
+       0x00000000,
+       0xc0016900,
+       0x000001b9,
+       0x00000000,
+       0xc0016900,
+       0x00000225,
+       0x00000000,
+       0xc0016900,
+       0x00000229,
+       0x00000000,
+       0xc0016900,
+       0x00000237,
+       0x00000000,
+       0xc0016900,
+       0x00000100,
+       0x00000800,
+       0xc0016900,
+       0x00000101,
+       0x00000000,
+       0xc0016900,
+       0x00000102,
+       0x00000000,
+       0xc0016900,
+       0x000002a8,
+       0x00000000,
+       0xc0016900,
+       0x000002a9,
+       0x00000000,
+       0xc0016900,
+       0x00000103,
+       0x00000000,
+       0xc0016900,
+       0x00000284,
+       0x00000000,
+       0xc0016900,
+       0x00000290,
+       0x00000000,
+       0xc0016900,
+       0x00000285,
+       0x00000000,
+       0xc0016900,
+       0x00000286,
+       0x00000000,
+       0xc0016900,
+       0x00000287,
+       0x00000000,
+       0xc0016900,
+       0x00000288,
+       0x00000000,
+       0xc0016900,
+       0x00000289,
+       0x00000000,
+       0xc0016900,
+       0x0000028a,
+       0x00000000,
+       0xc0016900,
+       0x0000028b,
+       0x00000000,
+       0xc0016900,
+       0x0000028c,
+       0x00000000,
+       0xc0016900,
+       0x0000028d,
+       0x00000000,
+       0xc0016900,
+       0x0000028e,
+       0x00000000,
+       0xc0016900,
+       0x0000028f,
+       0x00000000,
+       0xc0016900,
+       0x000002a1,
+       0x00000000,
+       0xc0016900,
+       0x000002a5,
+       0x00000000,
+       0xc0016900,
+       0x000002ac,
+       0x00000000,
+       0xc0016900,
+       0x000002ad,
+       0x00000000,
+       0xc0016900,
+       0x000002ae,
+       0x00000000,
+       0xc0016900,
+       0x000002c8,
+       0x00000000,
+       0xc0016900,
+       0x00000206,
+       0x00000100,
+       0xc0016900,
+       0x00000204,
+       0x00010000,
+       0xc0036e00,
+       0x00000000,
+       0x00000012,
+       0x00000000,
+       0x00000000,
+       0xc0016900,
+       0x0000008f,
+       0x0000000f,
+       0xc0016900,
+       0x000001e8,
+       0x00000001,
+       0xc0016900,
+       0x00000202,
+       0x00cc0000,
+       0xc0016900,
+       0x00000205,
+       0x00000244,
+       0xc0016900,
+       0x00000203,
+       0x00000210,
+       0xc0016900,
+       0x000001b1,
+       0x00000000,
+       0xc0016900,
+       0x00000185,
+       0x00000000,
+       0xc0016900,
+       0x000001b3,
+       0x00000001,
+       0xc0016900,
+       0x000001b4,
+       0x00000000,
+       0xc0016900,
+       0x00000191,
+       0x00000b00,
+       0xc0016900,
+       0x000001b5,
+       0x00000000,
+};
+
+/* same for r6xx/r7xx */
+static u32 r6xx_vs[] =
+{
+       0x00000004,
+       0x81000000,
+       0x0000203c,
+       0x94000b08,
+       0x00004000,
+       0x14200b1a,
+       0x00000000,
+       0x00000000,
+       0x3c000000,
+       0x68cd1000,
+       0x00080000,
+       0x00000000,
+};
+
+static u32 r6xx_ps[] =
+{
+       0x00000002,
+       0x80800000,
+       0x00000000,
+       0x94200688,
+       0x00000010,
+       0x000d1000,
+       0xb0800000,
+       0x00000000,
+};
+
+#define DI_PT_RECTLIST 0x11
+#define DI_INDEX_SIZE_16_BIT 0x0
+#define DI_SRC_SEL_AUTO_INDEX 0x2
+
+#define FMT_8 1
+#define FMT_5_6_5 8
+#define FMT_8_8_8_8 0x1a
+#define COLOR_8 1
+#define COLOR_5_6_5 8
+#define COLOR_8_8_8_8 0x1a
+
+#define R600_CB0_DEST_BASE_ENA (1 << 6)
+#define R600_TC_ACTION_ENA (1 << 23)
+#define R600_VC_ACTION_ENA (1 << 24)
+#define R600_CB_ACTION_ENA (1 << 25)
+#define R600_DB_ACTION_ENA (1 << 26)
+#define R600_SH_ACTION_ENA (1 << 27)
+#define R600_SMX_ACTION_ENA (1 << 28)
+
+#define R600_CB_COLOR0_SIZE 0x28060
+#define R600_CB_COLOR0_VIEW 0x28080
+#define R600_CB_COLOR0_INFO 0x280a0
+#define R600_CB_COLOR0_TILE 0x280c0
+#define R600_CB_COLOR0_FRAG 0x280e0
+#define R600_CB_COLOR0_MASK 0x28100
+
+#define R600_SQ_PGM_START_VS                                   0x28858
+#define R600_SQ_PGM_RESOURCES_VS 0x28868
+#define R600_SQ_PGM_CF_OFFSET_VS 0x288d0
+#define R600_SQ_PGM_START_PS                                   0x28840
+#define R600_SQ_PGM_RESOURCES_PS 0x28850
+#define R600_SQ_PGM_EXPORTS_PS 0x28854
+#define R600_SQ_PGM_CF_OFFSET_PS 0x288cc
+
+#define R600_VGT_PRIMITIVE_TYPE 0x8958
+
+#define R600_PA_SC_SCREEN_SCISSOR_TL 0x28030
+#define R600_PA_SC_GENERIC_SCISSOR_TL 0x28240
+#define R600_PA_SC_WINDOW_SCISSOR_TL 0x28204
+
+#define R600_SQ_TEX_VTX_INVALID_TEXTURE                        0x0
+#define R600_SQ_TEX_VTX_INVALID_BUFFER                         0x1
+#define R600_SQ_TEX_VTX_VALID_TEXTURE                          0x2
+#define R600_SQ_TEX_VTX_VALID_BUFFER                           0x3
+
+/* packet 3 type offsets */
+#define R600_SET_CONFIG_REG_OFFSET                             0x00008000
+#define R600_SET_CONFIG_REG_END                                0x0000ac00
+#define R600_SET_CONTEXT_REG_OFFSET                            0x00028000
+#define R600_SET_CONTEXT_REG_END                               0x00029000
+#define R600_SET_ALU_CONST_OFFSET                              0x00030000
+#define R600_SET_ALU_CONST_END                                 0x00032000
+#define R600_SET_RESOURCE_OFFSET                               0x00038000
+#define R600_SET_RESOURCE_END                                  0x0003c000
+#define R600_SET_SAMPLER_OFFSET                                0x0003c000
+#define R600_SET_SAMPLER_END                                   0x0003cff0
+#define R600_SET_CTL_CONST_OFFSET                              0x0003cff0
+#define R600_SET_CTL_CONST_END                                 0x0003e200
+#define R600_SET_LOOP_CONST_OFFSET                             0x0003e200
+#define R600_SET_LOOP_CONST_END                                0x0003e380
+#define R600_SET_BOOL_CONST_OFFSET                             0x0003e380
+#define R600_SET_BOOL_CONST_END                                0x00040000
+
+/* Packet 3 types */
+#define R600_IT_INDIRECT_BUFFER_END               0x00001700
+#define R600_IT_SET_PREDICATION                   0x00002000
+#define R600_IT_REG_RMW                           0x00002100
+#define R600_IT_COND_EXEC                         0x00002200
+#define R600_IT_PRED_EXEC                         0x00002300
+#define R600_IT_START_3D_CMDBUF                   0x00002400
+#define R600_IT_DRAW_INDEX_2                      0x00002700
+#define R600_IT_CONTEXT_CONTROL                   0x00002800
+#define R600_IT_DRAW_INDEX_IMMD_BE                0x00002900
+#define R600_IT_INDEX_TYPE                        0x00002A00
+#define R600_IT_DRAW_INDEX                        0x00002B00
+#define R600_IT_DRAW_INDEX_AUTO                   0x00002D00
+#define R600_IT_DRAW_INDEX_IMMD                   0x00002E00
+#define R600_IT_NUM_INSTANCES                     0x00002F00
+#define R600_IT_STRMOUT_BUFFER_UPDATE             0x00003400
+#define R600_IT_INDIRECT_BUFFER_MP                0x00003800
+#define R600_IT_MEM_SEMAPHORE                     0x00003900
+#define R600_IT_MPEG_INDEX                        0x00003A00
+#define R600_IT_WAIT_REG_MEM                      0x00003C00
+#define R600_IT_MEM_WRITE                         0x00003D00
+#define R600_IT_INDIRECT_BUFFER                   0x00003200
+#define R600_IT_CP_INTERRUPT                      0x00004000
+#define R600_IT_SURFACE_SYNC                      0x00004300
+#define R600_IT_ME_INITIALIZE                     0x00004400
+#define R600_IT_COND_WRITE                        0x00004500
+#define R600_IT_EVENT_WRITE                       0x00004600
+#define R600_IT_EVENT_WRITE_EOP                   0x00004700
+#define R600_IT_ONE_REG_WRITE                     0x00005700
+#define R600_IT_SET_CONFIG_REG                    0x00006800
+#define R600_IT_SET_CONTEXT_REG                   0x00006900
+#define R600_IT_SET_ALU_CONST                     0x00006A00
+#define R600_IT_SET_BOOL_CONST                    0x00006B00
+#define R600_IT_SET_LOOP_CONST                    0x00006C00
+#define R600_IT_SET_RESOURCE                      0x00006D00
+#define R600_IT_SET_SAMPLER                       0x00006E00
+#define R600_IT_SET_CTL_CONST                     0x00006F00
+#define R600_IT_SURFACE_BASE_UPDATE               0x00007300
+
+static inline void
+set_render_target(drm_radeon_private_t *dev_priv, int format, int w, int h, u64 gpu_addr)
+{
+       u32 cb_color_info;
+       int pitch, slice;
+       RING_LOCALS;
+       DRM_DEBUG("\n");
+
+       h = (h + 7) & ~7;
+       if (h < 8)
+               h = 8;
+
+       cb_color_info = ((format << 2) | (1 << 27));
+       pitch = (w / 8) - 1;
+       slice = ((w * h) / 64) - 1;
+
+       if (((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_R600) &&
+           ((dev_priv->flags & RADEON_FAMILY_MASK) < CHIP_RV770)) {
+               BEGIN_RING(21 + 2);
+               OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
+               OUT_RING((R600_CB_COLOR0_BASE - R600_SET_CONTEXT_REG_OFFSET) >> 2);
+               OUT_RING(gpu_addr >> 8);
+               OUT_RING(CP_PACKET3(R600_IT_SURFACE_BASE_UPDATE, 0));
+               OUT_RING(2 << 0);
+       } else {
+               BEGIN_RING(21);
+               OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
+               OUT_RING((R600_CB_COLOR0_BASE - R600_SET_CONTEXT_REG_OFFSET) >> 2);
+               OUT_RING(gpu_addr >> 8);
+       }
+
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
+        OUT_RING((R600_CB_COLOR0_SIZE - R600_SET_CONTEXT_REG_OFFSET) >> 2);
+       OUT_RING((pitch << 0) | (slice << 10));
+
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
+        OUT_RING((R600_CB_COLOR0_VIEW - R600_SET_CONTEXT_REG_OFFSET) >> 2);
+       OUT_RING(0);
+
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
+        OUT_RING((R600_CB_COLOR0_INFO - R600_SET_CONTEXT_REG_OFFSET) >> 2);
+       OUT_RING(cb_color_info);
+
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
+        OUT_RING((R600_CB_COLOR0_TILE - R600_SET_CONTEXT_REG_OFFSET) >> 2);
+       OUT_RING(0);
+
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
+        OUT_RING((R600_CB_COLOR0_FRAG - R600_SET_CONTEXT_REG_OFFSET) >> 2);
+       OUT_RING(0);
+
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
+        OUT_RING((R600_CB_COLOR0_MASK - R600_SET_CONTEXT_REG_OFFSET) >> 2);
+       OUT_RING(0);
+
+       ADVANCE_RING();
+}
+
+static inline void
+cp_set_surface_sync(drm_radeon_private_t *dev_priv,
+                   u32 sync_type, u32 size, u64 mc_addr)
+{
+       u32 cp_coher_size;
+       RING_LOCALS;
+       DRM_DEBUG("\n");
+
+       if (size == 0xffffffff)
+               cp_coher_size = 0xffffffff;
+       else
+               cp_coher_size = ((size + 255) >> 8);
+
+       BEGIN_RING(5);
+       OUT_RING(CP_PACKET3(R600_IT_SURFACE_SYNC, 3));
+       OUT_RING(sync_type);
+       OUT_RING(cp_coher_size);
+       OUT_RING((mc_addr >> 8));
+       OUT_RING(10); /* poll interval */
+       ADVANCE_RING();
+}
+
+static inline void
+set_shaders(struct drm_device *dev)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       u64 gpu_addr;
+       int shader_size, i;
+       u32 *vs, *ps;
+       uint32_t sq_pgm_resources;
+       RING_LOCALS;
+       DRM_DEBUG("\n");
+
+       /* load shaders */
+       vs = (u32 *) ((char *)dev->agp_buffer_map->handle + dev_priv->blit_vb->offset);
+       ps = (u32 *) ((char *)dev->agp_buffer_map->handle + dev_priv->blit_vb->offset + 256);
+
+       shader_size = sizeof(r6xx_vs) / 4;
+       for (i= 0; i < shader_size; i++)
+               vs[i] = r6xx_vs[i];
+       shader_size = sizeof(r6xx_ps) / 4;
+       for (i= 0; i < shader_size; i++)
+               ps[i] = r6xx_ps[i];
+
+       dev_priv->blit_vb->used = 512;
+
+       gpu_addr = dev_priv->gart_buffers_offset + dev_priv->blit_vb->offset;
+
+       /* setup shader regs */
+       sq_pgm_resources = (1 << 0);
+
+       BEGIN_RING(9 + 12);
+       /* VS */
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
+        OUT_RING((R600_SQ_PGM_START_VS - R600_SET_CONTEXT_REG_OFFSET) >> 2);
+       OUT_RING(gpu_addr >> 8);
+
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
+        OUT_RING((R600_SQ_PGM_RESOURCES_VS - R600_SET_CONTEXT_REG_OFFSET) >> 2);
+       OUT_RING(sq_pgm_resources);
+
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
+        OUT_RING((R600_SQ_PGM_CF_OFFSET_VS - R600_SET_CONTEXT_REG_OFFSET) >> 2);
+       OUT_RING(0);
+
+       /* PS */
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
+        OUT_RING((R600_SQ_PGM_START_PS - R600_SET_CONTEXT_REG_OFFSET) >> 2);
+       OUT_RING((gpu_addr + 256) >> 8);
+
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
+        OUT_RING((R600_SQ_PGM_RESOURCES_PS - R600_SET_CONTEXT_REG_OFFSET) >> 2);
+       OUT_RING(sq_pgm_resources | (1 << 28));
+
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
+        OUT_RING((R600_SQ_PGM_EXPORTS_PS - R600_SET_CONTEXT_REG_OFFSET) >> 2);
+       OUT_RING(2);
+
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
+        OUT_RING((R600_SQ_PGM_CF_OFFSET_PS - R600_SET_CONTEXT_REG_OFFSET) >> 2);
+       OUT_RING(0);
+       ADVANCE_RING();
+
+       cp_set_surface_sync(dev_priv,
+                           R600_SH_ACTION_ENA, 512, gpu_addr);
+}
+
+static inline void
+set_vtx_resource(drm_radeon_private_t *dev_priv, u64 gpu_addr)
+{
+       uint32_t sq_vtx_constant_word2;
+       RING_LOCALS;
+       DRM_DEBUG("\n");
+
+       sq_vtx_constant_word2 = (((gpu_addr >> 32) & 0xff) | (16 << 8));
+
+       BEGIN_RING(9);
+       OUT_RING(CP_PACKET3(R600_IT_SET_RESOURCE, 7));
+       OUT_RING(0x460);
+       OUT_RING(gpu_addr & 0xffffffff);
+       OUT_RING(48 - 1);
+       OUT_RING(sq_vtx_constant_word2);
+       OUT_RING(1 << 0);
+       OUT_RING(0);
+       OUT_RING(0);
+       OUT_RING(R600_SQ_TEX_VTX_VALID_BUFFER << 30);
+       ADVANCE_RING();
+
+       if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) ||
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) ||
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) ||
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880) ||
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV710))
+               cp_set_surface_sync(dev_priv,
+                                   R600_TC_ACTION_ENA, 48, gpu_addr);
+       else
+               cp_set_surface_sync(dev_priv,
+                                   R600_VC_ACTION_ENA, 48, gpu_addr);
+}
+
+static inline void
+set_tex_resource(drm_radeon_private_t *dev_priv,
+                int format, int w, int h, int pitch, u64 gpu_addr)
+{
+       uint32_t sq_tex_resource_word0, sq_tex_resource_word1, sq_tex_resource_word4;
+       RING_LOCALS;
+       DRM_DEBUG("\n");
+
+       if (h < 1)
+               h = 1;
+
+       sq_tex_resource_word0 = (1 << 0);
+       sq_tex_resource_word0 |= ((((pitch >> 3) - 1) << 8) |
+                                 ((w - 1) << 19));
+
+       sq_tex_resource_word1 = (format << 26);
+       sq_tex_resource_word1 |= ((h - 1) << 0);
+
+       sq_tex_resource_word4 = ((1 << 14) |
+                                (0 << 16) |
+                                (1 << 19) |
+                                (2 << 22) |
+                                (3 << 25));
+
+       BEGIN_RING(9);
+       OUT_RING(CP_PACKET3(R600_IT_SET_RESOURCE, 7));
+       OUT_RING(0);
+       OUT_RING(sq_tex_resource_word0);
+       OUT_RING(sq_tex_resource_word1);
+       OUT_RING(gpu_addr >> 8);
+       OUT_RING(gpu_addr >> 8);
+       OUT_RING(sq_tex_resource_word4);
+       OUT_RING(0);
+       OUT_RING(R600_SQ_TEX_VTX_VALID_TEXTURE << 30);
+       ADVANCE_RING();
+
+}
+
+static inline void
+set_scissors(drm_radeon_private_t *dev_priv, int x1, int y1, int x2, int y2)
+{
+       RING_LOCALS;
+       DRM_DEBUG("\n");
+
+       BEGIN_RING(12);
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 2));
+        OUT_RING((R600_PA_SC_SCREEN_SCISSOR_TL - R600_SET_CONTEXT_REG_OFFSET) >> 2);
+       OUT_RING((x1 << 0) | (y1 << 16));
+       OUT_RING((x2 << 0) | (y2 << 16));
+
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 2));
+        OUT_RING((R600_PA_SC_GENERIC_SCISSOR_TL - R600_SET_CONTEXT_REG_OFFSET) >> 2);
+       OUT_RING((x1 << 0) | (y1 << 16) | (1 << 31));
+       OUT_RING((x2 << 0) | (y2 << 16));
+
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 2));
+        OUT_RING((R600_PA_SC_WINDOW_SCISSOR_TL - R600_SET_CONTEXT_REG_OFFSET) >> 2);
+       OUT_RING((x1 << 0) | (y1 << 16) | (1 << 31));
+       OUT_RING((x2 << 0) | (y2 << 16));
+       ADVANCE_RING();
+}
+
+static inline void
+draw_auto(drm_radeon_private_t *dev_priv)
+{
+       RING_LOCALS;
+       DRM_DEBUG("\n");
+
+       BEGIN_RING(10);
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONFIG_REG, 1));
+        OUT_RING((R600_VGT_PRIMITIVE_TYPE - R600_SET_CONFIG_REG_OFFSET) >> 2);
+       OUT_RING(DI_PT_RECTLIST);
+
+       OUT_RING(CP_PACKET3(R600_IT_INDEX_TYPE, 0));
+       OUT_RING(DI_INDEX_SIZE_16_BIT);
+
+       OUT_RING(CP_PACKET3(R600_IT_NUM_INSTANCES, 0));
+       OUT_RING(1);
+
+       OUT_RING(CP_PACKET3(R600_IT_DRAW_INDEX_AUTO, 1));
+       OUT_RING(3);
+       OUT_RING(DI_SRC_SEL_AUTO_INDEX);
+
+       ADVANCE_RING();
+       COMMIT_RING();
+}
+
+static inline void
+set_default_state(drm_radeon_private_t *dev_priv)
+{
+       int default_state_dw, i;
+       u32 sq_config, sq_gpr_resource_mgmt_1, sq_gpr_resource_mgmt_2;
+       u32 sq_thread_resource_mgmt, sq_stack_resource_mgmt_1, sq_stack_resource_mgmt_2;
+       int num_ps_gprs, num_vs_gprs, num_temp_gprs, num_gs_gprs, num_es_gprs;
+       int num_ps_threads, num_vs_threads, num_gs_threads, num_es_threads;
+       int num_ps_stack_entries, num_vs_stack_entries, num_gs_stack_entries, num_es_stack_entries;
+       RING_LOCALS;
+
+       switch ((dev_priv->flags & RADEON_FAMILY_MASK)) {
+       case CHIP_R600:
+               num_ps_gprs = 192;
+               num_vs_gprs = 56;
+               num_temp_gprs = 4;
+               num_gs_gprs = 0;
+               num_es_gprs = 0;
+               num_ps_threads = 136;
+               num_vs_threads = 48;
+               num_gs_threads = 4;
+               num_es_threads = 4;
+               num_ps_stack_entries = 128;
+               num_vs_stack_entries = 128;
+               num_gs_stack_entries = 0;
+               num_es_stack_entries = 0;
+               break;
+       case CHIP_RV630:
+       case CHIP_RV635:
+               num_ps_gprs = 84;
+               num_vs_gprs = 36;
+               num_temp_gprs = 4;
+               num_gs_gprs = 0;
+               num_es_gprs = 0;
+               num_ps_threads = 144;
+               num_vs_threads = 40;
+               num_gs_threads = 4;
+               num_es_threads = 4;
+               num_ps_stack_entries = 40;
+               num_vs_stack_entries = 40;
+               num_gs_stack_entries = 32;
+               num_es_stack_entries = 16;
+               break;
+       case CHIP_RV610:
+       case CHIP_RV620:
+       case CHIP_RS780:
+       case CHIP_RS880:
+       default:
+               num_ps_gprs = 84;
+               num_vs_gprs = 36;
+               num_temp_gprs = 4;
+               num_gs_gprs = 0;
+               num_es_gprs = 0;
+               num_ps_threads = 136;
+               num_vs_threads = 48;
+               num_gs_threads = 4;
+               num_es_threads = 4;
+               num_ps_stack_entries = 40;
+               num_vs_stack_entries = 40;
+               num_gs_stack_entries = 32;
+               num_es_stack_entries = 16;
+               break;
+       case CHIP_RV670:
+               num_ps_gprs = 144;
+               num_vs_gprs = 40;
+               num_temp_gprs = 4;
+               num_gs_gprs = 0;
+               num_es_gprs = 0;
+               num_ps_threads = 136;
+               num_vs_threads = 48;
+               num_gs_threads = 4;
+               num_es_threads = 4;
+               num_ps_stack_entries = 40;
+               num_vs_stack_entries = 40;
+               num_gs_stack_entries = 32;
+               num_es_stack_entries = 16;
+               break;
+       case CHIP_RV770:
+               num_ps_gprs = 192;
+               num_vs_gprs = 56;
+               num_temp_gprs = 4;
+               num_gs_gprs = 0;
+               num_es_gprs = 0;
+               num_ps_threads = 188;
+               num_vs_threads = 60;
+               num_gs_threads = 0;
+               num_es_threads = 0;
+               num_ps_stack_entries = 256;
+               num_vs_stack_entries = 256;
+               num_gs_stack_entries = 0;
+               num_es_stack_entries = 0;
+               break;
+       case CHIP_RV730:
+       case CHIP_RV740:
+               num_ps_gprs = 84;
+               num_vs_gprs = 36;
+               num_temp_gprs = 4;
+               num_gs_gprs = 0;
+               num_es_gprs = 0;
+               num_ps_threads = 188;
+               num_vs_threads = 60;
+               num_gs_threads = 0;
+               num_es_threads = 0;
+               num_ps_stack_entries = 128;
+               num_vs_stack_entries = 128;
+               num_gs_stack_entries = 0;
+               num_es_stack_entries = 0;
+               break;
+       case CHIP_RV710:
+               num_ps_gprs = 192;
+               num_vs_gprs = 56;
+               num_temp_gprs = 4;
+               num_gs_gprs = 0;
+               num_es_gprs = 0;
+               num_ps_threads = 144;
+               num_vs_threads = 48;
+               num_gs_threads = 0;
+               num_es_threads = 0;
+               num_ps_stack_entries = 128;
+               num_vs_stack_entries = 128;
+               num_gs_stack_entries = 0;
+               num_es_stack_entries = 0;
+               break;
+       }
+
+       if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) ||
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) ||
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) ||
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880) ||
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV710))
+               sq_config = 0;
+       else
+               sq_config = R600_VC_ENABLE;
+
+       sq_config |= (R600_DX9_CONSTS |
+                     R600_ALU_INST_PREFER_VECTOR |
+                     R600_PS_PRIO(0) |
+                     R600_VS_PRIO(1) |
+                     R600_GS_PRIO(2) |
+                     R600_ES_PRIO(3));
+
+       sq_gpr_resource_mgmt_1 = (R600_NUM_PS_GPRS(num_ps_gprs) |
+                                 R600_NUM_VS_GPRS(num_vs_gprs) |
+                                 R600_NUM_CLAUSE_TEMP_GPRS(num_temp_gprs));
+       sq_gpr_resource_mgmt_2 = (R600_NUM_GS_GPRS(num_gs_gprs) |
+                                 R600_NUM_ES_GPRS(num_es_gprs));
+       sq_thread_resource_mgmt = (R600_NUM_PS_THREADS(num_ps_threads) |
+                                  R600_NUM_VS_THREADS(num_vs_threads) |
+                                  R600_NUM_GS_THREADS(num_gs_threads) |
+                                  R600_NUM_ES_THREADS(num_es_threads));
+       sq_stack_resource_mgmt_1 = (R600_NUM_PS_STACK_ENTRIES(num_ps_stack_entries) |
+                                   R600_NUM_VS_STACK_ENTRIES(num_vs_stack_entries));
+       sq_stack_resource_mgmt_2 = (R600_NUM_GS_STACK_ENTRIES(num_gs_stack_entries) |
+                                   R600_NUM_ES_STACK_ENTRIES(num_es_stack_entries));
+
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770) {
+               default_state_dw = sizeof(r7xx_default_state) / 4;
+               BEGIN_RING(default_state_dw + 10);
+               for (i = 0; i < default_state_dw; i++)
+                       OUT_RING(r7xx_default_state[i]);
+       } else {
+               default_state_dw = sizeof(r6xx_default_state) / 4;
+               BEGIN_RING(default_state_dw + 10);
+               for (i = 0; i < default_state_dw; i++)
+                       OUT_RING(r6xx_default_state[i]);
+       }
+       OUT_RING(CP_PACKET3(R600_IT_EVENT_WRITE, 0));
+       OUT_RING(R600_CACHE_FLUSH_AND_INV_EVENT);
+       /* SQ config */
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONFIG_REG, 6));
+        OUT_RING((R600_SQ_CONFIG - R600_SET_CONFIG_REG_OFFSET) >> 2);
+       OUT_RING(sq_config);
+       OUT_RING(sq_gpr_resource_mgmt_1);
+       OUT_RING(sq_gpr_resource_mgmt_2);
+       OUT_RING(sq_thread_resource_mgmt);
+       OUT_RING(sq_stack_resource_mgmt_1);
+       OUT_RING(sq_stack_resource_mgmt_2);
+       ADVANCE_RING();
+}
+
+static inline uint32_t i2f(uint32_t input)
+{
+       u32 result, i, exponent, fraction;
+
+       if ((input & 0x3fff) == 0)
+               result = 0; /* 0 is a special case */
+       else {
+               exponent = 140; /* exponent biased by 127; */
+               fraction = (input & 0x3fff) << 10; /* cheat and only
+                                                     handle numbers below 2^^15 */
+               for (i = 0; i < 14; i++) {
+                       if (fraction & 0x800000)
+                               break;
+                       else {
+                               fraction = fraction << 1; /* keep
+                                                            shifting left until top bit = 1 */
+                               exponent = exponent -1;
+                       }
+               }
+               result = exponent << 23 | (fraction & 0x7fffff); /* mask
+                                                                   off top bit; assumed 1 */
+       }
+       return result;
+}
+
+int
+r600_prepare_blit_copy(struct drm_device *dev)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       DRM_DEBUG("\n");
+
+       dev_priv->blit_vb = radeon_freelist_get(dev);
+       if (!dev_priv->blit_vb) {
+               DRM_ERROR("Unable to allocate vertex buffer for blit\n");
+               return -EAGAIN;
+       }
+
+       set_default_state(dev_priv);
+       set_shaders(dev);
+
+       return 0;
+}
+
+void
+r600_done_blit_copy(struct drm_device *dev)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       RING_LOCALS;
+       DRM_DEBUG("\n");
+
+       BEGIN_RING(5);
+       OUT_RING(CP_PACKET3(R600_IT_EVENT_WRITE, 0));
+       OUT_RING(R600_CACHE_FLUSH_AND_INV_EVENT);
+       /* wait for 3D idle clean */
+       OUT_RING(CP_PACKET3(R600_IT_SET_CONFIG_REG, 1));
+       OUT_RING((R600_WAIT_UNTIL - R600_SET_CONFIG_REG_OFFSET) >> 2);
+       OUT_RING(RADEON_WAIT_3D_IDLE | RADEON_WAIT_3D_IDLECLEAN);
+
+       ADVANCE_RING();
+       COMMIT_RING();
+
+       dev_priv->blit_vb->used = 0;
+       radeon_cp_discard_buffer(dev, dev_priv->blit_vb);
+}
+
+void
+r600_blit_copy(struct drm_device *dev,
+              uint64_t src_gpu_addr, uint64_t dst_gpu_addr,
+              int size_bytes)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       int max_bytes;
+       u64 vb_addr;
+       u32 *vb;
+
+       vb = (u32 *) ((char *)dev->agp_buffer_map->handle +
+           dev_priv->blit_vb->offset + dev_priv->blit_vb->used);
+       DRM_DEBUG("src=0x%016llx, dst=0x%016llx, size=%d\n",
+           (unsigned long long)src_gpu_addr,
+           (unsigned long long)dst_gpu_addr, size_bytes);
+
+       if ((size_bytes & 3) || (src_gpu_addr & 3) || (dst_gpu_addr & 3)) {
+               max_bytes = 8192;
+
+               while (size_bytes) {
+                       int cur_size = size_bytes;
+                       int src_x = src_gpu_addr & 255;
+                       int dst_x = dst_gpu_addr & 255;
+                       int h = 1;
+                       src_gpu_addr = src_gpu_addr & ~255;
+                       dst_gpu_addr = dst_gpu_addr & ~255;
+
+                       if (!src_x && !dst_x) {
+                               h = (cur_size / max_bytes);
+                               if (h > 8192)
+                                       h = 8192;
+                               if (h == 0)
+                                       h = 1;
+                               else
+                                       cur_size = max_bytes;
+                       } else {
+                               if (cur_size > max_bytes)
+                                       cur_size = max_bytes;
+                               if (cur_size > (max_bytes - dst_x))
+                                       cur_size = (max_bytes - dst_x);
+                               if (cur_size > (max_bytes - src_x))
+                                       cur_size = (max_bytes - src_x);
+                       }
+
+                       if ((dev_priv->blit_vb->used + 48) > dev_priv->blit_vb->total) {
+                               dev_priv->blit_vb->used = 0;
+                               radeon_cp_discard_buffer(dev, dev_priv->blit_vb);
+                               dev_priv->blit_vb = radeon_freelist_get(dev);
+                               if (!dev_priv->blit_vb)
+                                       return;
+                               set_shaders(dev);
+                               vb = (u32 *) ((char *)dev->agp_buffer_map->handle +
+                                   dev_priv->blit_vb->offset + dev_priv->blit_vb->used);
+                       }
+
+                       vb[0] = i2f(dst_x);
+                       vb[1] = 0;
+                       vb[2] = i2f(src_x);
+                       vb[3] = 0;
+
+                       vb[4] = i2f(dst_x);
+                       vb[5] = i2f(h);
+                       vb[6] = i2f(src_x);
+                       vb[7] = i2f(h);
+
+                       vb[8] = i2f(dst_x + cur_size);
+                       vb[9] = i2f(h);
+                       vb[10] = i2f(src_x + cur_size);
+                       vb[11] = i2f(h);
+
+                       /* src */
+                       set_tex_resource(dev_priv, FMT_8,
+                                        src_x + cur_size, h, src_x + cur_size,
+                                        src_gpu_addr);
+
+                       cp_set_surface_sync(dev_priv,
+                                           R600_TC_ACTION_ENA, (src_x + cur_size * h), src_gpu_addr);
+
+                       /* dst */
+                       set_render_target(dev_priv, COLOR_8,
+                                         dst_x + cur_size, h,
+                                         dst_gpu_addr);
+
+                       /* scissors */
+                       set_scissors(dev_priv, dst_x, 0, dst_x + cur_size, h);
+
+                       /* Vertex buffer setup */
+                       vb_addr = dev_priv->gart_buffers_offset +
+                                dev_priv->blit_vb->offset +
+                               dev_priv->blit_vb->used;
+                       set_vtx_resource(dev_priv, vb_addr);
+
+                       /* draw */
+                       draw_auto(dev_priv);
+
+                       cp_set_surface_sync(dev_priv,
+                                           R600_CB_ACTION_ENA | R600_CB0_DEST_BASE_ENA,
+                                           cur_size * h, dst_gpu_addr);
+
+                       vb += 12;
+                       dev_priv->blit_vb->used += 12 * 4;
+
+                       src_gpu_addr += cur_size * h;
+                       dst_gpu_addr += cur_size * h;
+                       size_bytes -= cur_size * h;
+               }
+       } else {
+               max_bytes = 8192 * 4;
+
+               while (size_bytes) {
+                       int cur_size = size_bytes;
+                       int src_x = (src_gpu_addr & 255);
+                       int dst_x = (dst_gpu_addr & 255);
+                       int h = 1;
+                       src_gpu_addr = src_gpu_addr & ~255;
+                       dst_gpu_addr = dst_gpu_addr & ~255;
+
+                       if (!src_x && !dst_x) {
+                               h = (cur_size / max_bytes);
+                               if (h > 8192)
+                                       h = 8192;
+                               if (h == 0)
+                                       h = 1;
+                               else
+                                       cur_size = max_bytes;
+                       } else {
+                               if (cur_size > max_bytes)
+                                   cur_size = max_bytes;
+                               if (cur_size > (max_bytes - dst_x))
+                                       cur_size = (max_bytes - dst_x);
+                               if (cur_size > (max_bytes - src_x))
+                                       cur_size = (max_bytes - src_x);
+                       }
+
+                       if ((dev_priv->blit_vb->used + 48) > dev_priv->blit_vb->total) {
+                               dev_priv->blit_vb->used = 0;
+                               radeon_cp_discard_buffer(dev, dev_priv->blit_vb);
+                               dev_priv->blit_vb = radeon_freelist_get(dev);
+                               if (!dev_priv->blit_vb)
+                                       return;
+                               set_shaders(dev);
+                               vb = (u32 *) ((char *)dev->agp_buffer_map->handle +
+                                   dev_priv->blit_vb->offset + dev_priv->blit_vb->used);
+                       }
+
+                       vb[0] = i2f(dst_x / 4);
+                       vb[1] = 0;
+                       vb[2] = i2f(src_x / 4);
+                       vb[3] = 0;
+
+                       vb[4] = i2f(dst_x / 4);
+                       vb[5] = i2f(h);
+                       vb[6] = i2f(src_x / 4);
+                       vb[7] = i2f(h);
+
+                       vb[8] = i2f((dst_x + cur_size) / 4);
+                       vb[9] = i2f(h);
+                       vb[10] = i2f((src_x + cur_size) / 4);
+                       vb[11] = i2f(h);
+
+                       /* src */
+                       set_tex_resource(dev_priv, FMT_8_8_8_8,
+                                        (src_x + cur_size) / 4,
+                                        h, (src_x + cur_size) / 4,
+                                        src_gpu_addr);
+
+                       cp_set_surface_sync(dev_priv,
+                                           R600_TC_ACTION_ENA, (src_x + cur_size * h), src_gpu_addr);
+
+                       /* dst */
+                       set_render_target(dev_priv, COLOR_8_8_8_8,
+                                         (dst_x + cur_size) / 4, h,
+                                         dst_gpu_addr);
+
+                       /* scissors */
+                       set_scissors(dev_priv, (dst_x / 4), 0, (dst_x + cur_size / 4), h);
+
+                       /* Vertex buffer setup */
+                       vb_addr = dev_priv->gart_buffers_offset +
+                                dev_priv->blit_vb->offset +
+                               dev_priv->blit_vb->used;
+                       set_vtx_resource(dev_priv, vb_addr);
+
+                       /* draw */
+                       draw_auto(dev_priv);
+
+                       cp_set_surface_sync(dev_priv,
+                                           R600_CB_ACTION_ENA | R600_CB0_DEST_BASE_ENA,
+                                           cur_size * h, dst_gpu_addr);
+
+                       vb += 12;
+                       dev_priv->blit_vb->used += 12 * 4;
+
+                       src_gpu_addr += cur_size * h;
+                       dst_gpu_addr += cur_size * h;
+                       size_bytes -= cur_size * h;
+               }
+       }
+}
+
+void
+r600_blit_swap(struct drm_device *dev,
+              uint64_t src_gpu_addr, uint64_t dst_gpu_addr,
+              int sx, int sy, int dx, int dy,
+              int w, int h, int src_pitch, int dst_pitch, int cpp)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       int cb_format, tex_format;
+       int sx2, sy2, dx2, dy2;
+       u64 vb_addr;
+       u32 *vb;
+
+       if ((dev_priv->blit_vb->used + 48) > dev_priv->blit_vb->total) {
+               dev_priv->blit_vb->used = 0;
+               radeon_cp_discard_buffer(dev, dev_priv->blit_vb);
+               dev_priv->blit_vb = radeon_freelist_get(dev);
+               if (!dev_priv->blit_vb)
+                       return;
+               set_shaders(dev);
+       }
+       vb = (u32 *) ((char *)dev->agp_buffer_map->handle +
+           dev_priv->blit_vb->offset + dev_priv->blit_vb->used);
+
+       sx2 = sx + w;
+       sy2 = sy + h;
+       dx2 = dx + w;
+       dy2 = dy + h;
+
+       vb[0] = i2f(dx);
+       vb[1] = i2f(dy);
+       vb[2] = i2f(sx);
+       vb[3] = i2f(sy);
+
+       vb[4] = i2f(dx);
+       vb[5] = i2f(dy2);
+       vb[6] = i2f(sx);
+       vb[7] = i2f(sy2);
+
+       vb[8] = i2f(dx2);
+       vb[9] = i2f(dy2);
+       vb[10] = i2f(sx2);
+       vb[11] = i2f(sy2);
+
+       switch(cpp) {
+       case 4:
+               cb_format = COLOR_8_8_8_8;
+               tex_format = FMT_8_8_8_8;
+               break;
+       case 2:
+               cb_format = COLOR_5_6_5;
+               tex_format = FMT_5_6_5;
+               break;
+       default:
+               cb_format = COLOR_8;
+               tex_format = FMT_8;
+               break;
+       }
+
+       /* src */
+       set_tex_resource(dev_priv, tex_format,
+                        src_pitch / cpp,
+                        sy2, src_pitch / cpp,
+                        src_gpu_addr);
+
+       cp_set_surface_sync(dev_priv,
+                           R600_TC_ACTION_ENA, src_pitch * sy2, src_gpu_addr);
+
+       /* dst */
+       set_render_target(dev_priv, cb_format,
+                         dst_pitch / cpp, dy2,
+                         dst_gpu_addr);
+
+       /* scissors */
+       set_scissors(dev_priv, dx, dy, dx2, dy2);
+
+       /* Vertex buffer setup */
+       vb_addr = dev_priv->gart_buffers_offset +
+               dev_priv->blit_vb->offset +
+               dev_priv->blit_vb->used;
+       set_vtx_resource(dev_priv, vb_addr);
+
+       /* draw */
+       draw_auto(dev_priv);
+
+       cp_set_surface_sync(dev_priv,
+                           R600_CB_ACTION_ENA | R600_CB0_DEST_BASE_ENA,
+                           dst_pitch * dy2, dst_gpu_addr);
+
+       dev_priv->blit_vb->used += 12 * 4;
+}
index 9af4b71..19d44f5 100644 (file)
@@ -24,6 +24,7 @@
  * Authors:
  *     Dave Airlie <airlied@redhat.com>
  *     Alex Deucher <alexander.deucher@amd.com>
+ * __FBSDID("$FreeBSD: src/sys/dev/drm/r600_cp.c,v 1.10 2009/08/23 14:55:57 rnoland Exp $");
  */
 
 #include "dev/drm/drmP.h"
@@ -1840,6 +1841,7 @@ int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
         */
        dev_priv->vblank_crtc = DRM_RADEON_VBLANK_CRTC1;
 
+       dev_priv->do_boxes = 0;
        dev_priv->cp_mode = init->cp_mode;
 
        /* We don't support anything other than bus-mastering ring mode,
@@ -2097,6 +2099,8 @@ int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
        r600_do_engine_reset(dev);
        r600_test_writeback(dev_priv);
 
+       r600_cs_init(dev);
+
        return 0;
 }
 
@@ -2229,3 +2233,135 @@ int r600_cp_dispatch_indirect(struct drm_device *dev,
 
        return 0;
 }
+
+void r600_cp_dispatch_swap(struct drm_device * dev)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
+       int nbox = sarea_priv->nbox;
+       struct drm_clip_rect *pbox = sarea_priv->boxes;
+       int i, cpp, src_pitch, dst_pitch;
+       uint64_t src, dst;
+       RING_LOCALS;
+       DRM_DEBUG("\n");
+
+       if (dev_priv->color_fmt == RADEON_COLOR_FORMAT_ARGB8888)
+               cpp = 4;
+       else
+               cpp = 2;
+
+       if (dev_priv->sarea_priv->pfCurrentPage == 0) {
+               src_pitch = dev_priv->back_pitch;
+               dst_pitch = dev_priv->front_pitch;
+               src = dev_priv->back_offset + dev_priv->fb_location;
+               dst = dev_priv->front_offset + dev_priv->fb_location;
+       } else {
+               src_pitch = dev_priv->front_pitch;
+               dst_pitch = dev_priv->back_pitch;
+               src = dev_priv->front_offset + dev_priv->fb_location;
+               dst = dev_priv->back_offset + dev_priv->fb_location;
+       }
+
+       if (r600_prepare_blit_copy(dev)) {
+               DRM_ERROR("unable to allocate vertex buffer for swap buffer\n");
+               return;
+       }
+       for (i = 0; i < nbox; i++) {
+               int x = pbox[i].x1;
+               int y = pbox[i].y1;
+               int w = pbox[i].x2 - x;
+               int h = pbox[i].y2 - y;
+
+               DRM_DEBUG("%d,%d-%d,%d\n", x, y, w, h);
+
+               r600_blit_swap(dev,
+                              src, dst,
+                              x, y, x, y, w, h,
+                              src_pitch, dst_pitch, cpp);
+       }
+       r600_done_blit_copy(dev);
+
+       /* Increment the frame counter.  The client-side 3D driver must
+        * throttle the framerate by waiting for this value before
+        * performing the swapbuffer ioctl.
+        */
+       dev_priv->sarea_priv->last_frame++;
+
+       BEGIN_RING(3);
+       R600_FRAME_AGE(dev_priv->sarea_priv->last_frame);
+       ADVANCE_RING();
+}
+
+int r600_cp_dispatch_texture(struct drm_device * dev,
+                            struct drm_file *file_priv,
+                            drm_radeon_texture_t * tex,
+                            drm_radeon_tex_image_t * image)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       struct drm_buf *buf;
+       u32 *buffer;
+       const u8 __user *data;
+       int size, pass_size;
+       u64 src_offset, dst_offset;
+
+       if (!radeon_check_offset(dev_priv, tex->offset)) {
+               DRM_ERROR("Invalid destination offset\n");
+               return -EINVAL;
+       }
+
+       /* this might fail for zero-sized uploads - are those illegal? */
+       if (!radeon_check_offset(dev_priv, tex->offset + tex->height * tex->pitch - 1)) {
+               DRM_ERROR("Invalid final destination offset\n");
+               return -EINVAL;
+       }
+
+       size = tex->height * tex->pitch;
+
+       if (size == 0)
+               return 0;
+
+       dst_offset = tex->offset;
+
+       r600_prepare_blit_copy(dev);
+       do {
+               data = (const u8 __user *)image->data;
+               pass_size = size;
+
+               buf = radeon_freelist_get(dev);
+               if (!buf) {
+                       DRM_DEBUG("EAGAIN\n");
+                       if (DRM_COPY_TO_USER(tex->image, image, sizeof(*image)))
+                               return -EFAULT;
+                       return -EAGAIN;
+               }
+
+               if (pass_size > buf->total)
+                       pass_size = buf->total;
+
+               /* Dispatch the indirect buffer.
+                */
+               buffer =
+                   (u32 *) ((char *)dev->agp_buffer_map->handle + buf->offset);
+
+               if (DRM_COPY_FROM_USER(buffer, data, pass_size)) {
+                       DRM_ERROR("EFAULT on pad, %d bytes\n", pass_size);
+                       return -EFAULT;
+               }
+
+               buf->file_priv = file_priv;
+               buf->used = pass_size;
+               src_offset = dev_priv->gart_buffers_offset + buf->offset;
+
+               r600_blit_copy(dev, src_offset, dst_offset, pass_size);
+
+               radeon_cp_discard_buffer(dev, buf);
+
+               /* Update the input parameters for next time */
+               image->data = (const u8 __user *)image->data + pass_size;
+               dst_offset += pass_size;
+               size -= pass_size;
+       } while (size > 0);
+       r600_done_blit_copy(dev);
+
+       return 0;
+}
index 313381d..b25c057 100644 (file)
@@ -1,7 +1,7 @@
 .PATH: ${.CURDIR}/..
 KMOD   = radeon
 SRCS    = r300_cmdbuf.c r600_cp.c radeon_cp.c radeon_drv.c radeon_state.c \
-         radeon_irq.c radeon_mem.c
+         radeon_irq.c radeon_mem.c radeon_cs.c r600_blit.c
 SRCS   += device_if.h bus_if.h pci_if.h opt_drm.h
 CFLAGS += ${DEBUG_FLAGS} -I. -I..
 
index db5d1fa..ef5cfc8 100644 (file)
@@ -26,6 +26,7 @@
  * Authors:
  *    Kevin E. Martin <martin@valinux.com>
  *    Gareth Hughes <gareth@valinux.com>
+ * __FBSDID("$FreeBSD: src/sys/dev/drm/radeon_cp.c,v 1.36 2009/10/30 18:07:22 rnoland Exp $");
  */
 
 #include "dev/drm/drmP.h"
@@ -405,6 +406,15 @@ static void radeon_init_pipes(drm_radeon_private_t *dev_priv)
 {
        uint32_t gb_tile_config, gb_pipe_sel = 0;
 
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV530) {
+               uint32_t z_pipe_sel = RADEON_READ(RV530_GB_PIPE_SELECT2);
+               if ((z_pipe_sel & 3) == 3)
+                       dev_priv->num_z_pipes = 2;
+               else
+                       dev_priv->num_z_pipes = 1;
+       } else
+               dev_priv->num_z_pipes = 1;
+
        /* RS4xx/RS6xx/R4xx/R5xx */
        if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R420) {
                gb_pipe_sel = RADEON_READ(R400_GB_PIPE_SELECT);
@@ -1695,6 +1705,10 @@ void radeon_do_release(struct drm_device * dev)
                                                    PCATCH | PINTERLOCKED,
                                                    "rdnrel", 0);
                                        DRM_LOCK();
+/* DragonFly equivalent of
+ *                                     mtx_sleep(&ret, &dev->dev_lock, 0,
+ *                                         "rdnrel", 1);
+ */
                                }
                        } else {
                                while ((ret = radeon_do_cp_idle(dev_priv)) != 0) {
@@ -1858,8 +1872,8 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev)
        for (t = 0; t < dev_priv->usec_timeout; t++) {
                u32 done_age = GET_SCRATCH(dev_priv, 1);
                DRM_DEBUG("done_age = %d\n", done_age);
-               for (i = start; i < dma->buf_count; i++) {
-                       buf = dma->buflist[i];
+               for (i = 0; i < dma->buf_count; i++) {
+                       buf = dma->buflist[start];
                        buf_priv = buf->dev_private;
                        if (buf->file_priv == NULL || (buf->pending &&
                                                       buf_priv->age <=
@@ -1868,7 +1882,8 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev)
                                buf->pending = 0;
                                return buf;
                        }
-                       start = 0;
+                       if (++start >= dma->buf_count)
+                               start = 0;
                }
 
                if (t) {
@@ -1881,43 +1896,6 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev)
        return NULL;
 }
 
-#if 0
-struct drm_buf *radeon_freelist_get(struct drm_device * dev)
-{
-       struct drm_device_dma *dma = dev->dma;
-       drm_radeon_private_t *dev_priv = dev->dev_private;
-       drm_radeon_buf_priv_t *buf_priv;
-       struct drm_buf *buf;
-       int i, t;
-       int start;
-       u32 done_age;
-
-       done_age = radeon_read_ring_rptr(dev_priv, RADEON_SCRATCHOFF(1));
-       if (++dev_priv->last_buf >= dma->buf_count)
-               dev_priv->last_buf = 0;
-
-       start = dev_priv->last_buf;
-       dev_priv->stats.freelist_loops++;
-
-       for (t = 0; t < 2; t++) {
-               for (i = start; i < dma->buf_count; i++) {
-                       buf = dma->buflist[i];
-                       buf_priv = buf->dev_private;
-                       if (buf->file_priv == 0 || (buf->pending &&
-                                                   buf_priv->age <=
-                                                   done_age)) {
-                               dev_priv->stats.requested_bufs++;
-                               buf->pending = 0;
-                               return buf;
-                       }
-               }
-               start = 0;
-       }
-
-       return NULL;
-}
-#endif
-
 void radeon_freelist_reset(struct drm_device * dev)
 {
        struct drm_device_dma *dma = dev->dma;
@@ -2067,6 +2045,8 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags)
        else
                dev_priv->flags |= RADEON_IS_PCI;
 
+       DRM_SPININIT(&dev_priv->cs.cs_mutex, "cs_mtx");
+
        ret = drm_addmap(dev, drm_get_resource_start(dev, 2),
                         drm_get_resource_len(dev, 2), _DRM_REGISTERS,
                         _DRM_READ_ONLY | _DRM_DRIVER, &dev_priv->mmio);
@@ -2119,6 +2099,8 @@ int radeon_driver_unload(struct drm_device *dev)
 
        drm_rmmap(dev, dev_priv->mmio);
 
+       DRM_SPINUNINIT(&dev_priv->cs.cs_mutex);
+
        drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
 
        dev->dev_private = NULL;
@@ -2133,9 +2115,9 @@ void radeon_commit_ring(drm_radeon_private_t *dev_priv)
 
        /* check if the ring is padded out to 16-dword alignment */
 
-       tail_aligned = dev_priv->ring.tail & 0xf;
+       tail_aligned = dev_priv->ring.tail & (RADEON_RING_ALIGN - 1);
        if (tail_aligned) {
-               int num_p2 = 16 - tail_aligned;
+               int num_p2 = RADEON_RING_ALIGN - tail_aligned;
 
                ring = dev_priv->ring.start;
                /* pad with some CP_PACKET2 */
diff --git a/sys/dev/drm/radeon_cs.c b/sys/dev/drm/radeon_cs.c
new file mode 100644 (file)
index 0000000..e49830d
--- /dev/null
@@ -0,0 +1,855 @@
+/*-
+ * Copyright 2008 Jerome Glisse.
+ * 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:
+ *    Jerome Glisse <glisse@freedesktop.org>
+ * __FBSDID("$FreeBSD: src/sys/dev/drm/radeon_cs.c,v 1.2 2009/09/28 22:41:28 rnoland Exp $");
+ */
+
+#include "dev/drm/drmP.h"
+#include "dev/drm/radeon_drm.h"
+#include "dev/drm/radeon_drv.h"
+
+/* regs */
+#define AVIVO_D1MODE_VLINE_START_END                           0x6538
+#define AVIVO_D2MODE_VLINE_START_END                           0x6d38
+#define R600_CP_COHER_BASE                                     0x85f8
+#define R600_DB_DEPTH_BASE                                     0x2800c
+#define R600_CB_COLOR0_BASE                                    0x28040
+#define R600_CB_COLOR1_BASE                                    0x28044
+#define R600_CB_COLOR2_BASE                                    0x28048
+#define R600_CB_COLOR3_BASE                                    0x2804c
+#define R600_CB_COLOR4_BASE                                    0x28050
+#define R600_CB_COLOR5_BASE                                    0x28054
+#define R600_CB_COLOR6_BASE                                    0x28058
+#define R600_CB_COLOR7_BASE                                    0x2805c
+#define R600_SQ_PGM_START_FS                                   0x28894
+#define R600_SQ_PGM_START_ES                                   0x28880
+#define R600_SQ_PGM_START_VS                                   0x28858
+#define R600_SQ_PGM_START_GS                                   0x2886c
+#define R600_SQ_PGM_START_PS                                   0x28840
+#define R600_VGT_DMA_BASE                                      0x287e8
+#define R600_VGT_DMA_BASE_HI                                   0x287e4
+#define R600_VGT_STRMOUT_BASE_OFFSET_0                         0x28b10
+#define R600_VGT_STRMOUT_BASE_OFFSET_1                         0x28b14
+#define R600_VGT_STRMOUT_BASE_OFFSET_2                         0x28b18
+#define R600_VGT_STRMOUT_BASE_OFFSET_3                         0x28b1c
+#define R600_VGT_STRMOUT_BASE_OFFSET_HI_0                      0x28b44
+#define R600_VGT_STRMOUT_BASE_OFFSET_HI_1                      0x28b48
+#define R600_VGT_STRMOUT_BASE_OFFSET_HI_2                      0x28b4c
+#define R600_VGT_STRMOUT_BASE_OFFSET_HI_3                      0x28b50
+#define R600_VGT_STRMOUT_BUFFER_BASE_0                         0x28ad8
+#define R600_VGT_STRMOUT_BUFFER_BASE_1                         0x28ae8
+#define R600_VGT_STRMOUT_BUFFER_BASE_2                         0x28af8
+#define R600_VGT_STRMOUT_BUFFER_BASE_3                         0x28b08
+#define R600_VGT_STRMOUT_BUFFER_OFFSET_0                       0x28adc
+#define R600_VGT_STRMOUT_BUFFER_OFFSET_1                       0x28aec
+#define R600_VGT_STRMOUT_BUFFER_OFFSET_2                       0x28afc
+#define R600_VGT_STRMOUT_BUFFER_OFFSET_3                       0x28b0c
+
+/* resource type */
+#define R600_SQ_TEX_VTX_INVALID_TEXTURE                        0x0
+#define R600_SQ_TEX_VTX_INVALID_BUFFER                         0x1
+#define R600_SQ_TEX_VTX_VALID_TEXTURE                          0x2
+#define R600_SQ_TEX_VTX_VALID_BUFFER                           0x3
+
+/* packet 3 type offsets */
+#define R600_SET_CONFIG_REG_OFFSET                             0x00008000
+#define R600_SET_CONFIG_REG_END                                0x0000ac00
+#define R600_SET_CONTEXT_REG_OFFSET                            0x00028000
+#define R600_SET_CONTEXT_REG_END                               0x00029000
+#define R600_SET_ALU_CONST_OFFSET                              0x00030000
+#define R600_SET_ALU_CONST_END                                 0x00032000
+#define R600_SET_RESOURCE_OFFSET                               0x00038000
+#define R600_SET_RESOURCE_END                                  0x0003c000
+#define R600_SET_SAMPLER_OFFSET                                0x0003c000
+#define R600_SET_SAMPLER_END                                   0x0003cff0
+#define R600_SET_CTL_CONST_OFFSET                              0x0003cff0
+#define R600_SET_CTL_CONST_END                                 0x0003e200
+#define R600_SET_LOOP_CONST_OFFSET                             0x0003e200
+#define R600_SET_LOOP_CONST_END                                0x0003e380
+#define R600_SET_BOOL_CONST_OFFSET                             0x0003e380
+#define R600_SET_BOOL_CONST_END                                0x00040000
+
+/* Packet 3 types */
+#define R600_IT_INDIRECT_BUFFER_END               0x00001700
+#define R600_IT_SET_PREDICATION                   0x00002000
+#define R600_IT_REG_RMW                           0x00002100
+#define R600_IT_COND_EXEC                         0x00002200
+#define R600_IT_PRED_EXEC                         0x00002300
+#define R600_IT_START_3D_CMDBUF                   0x00002400
+#define R600_IT_DRAW_INDEX_2                      0x00002700
+#define R600_IT_CONTEXT_CONTROL                   0x00002800
+#define R600_IT_DRAW_INDEX_IMMD_BE                0x00002900
+#define R600_IT_INDEX_TYPE                        0x00002A00
+#define R600_IT_DRAW_INDEX                        0x00002B00
+#define R600_IT_DRAW_INDEX_AUTO                   0x00002D00
+#define R600_IT_DRAW_INDEX_IMMD                   0x00002E00
+#define R600_IT_NUM_INSTANCES                     0x00002F00
+#define R600_IT_STRMOUT_BUFFER_UPDATE             0x00003400
+#define R600_IT_INDIRECT_BUFFER_MP                0x00003800
+#define R600_IT_MEM_SEMAPHORE                     0x00003900
+#define R600_IT_MPEG_INDEX                        0x00003A00
+#define R600_IT_WAIT_REG_MEM                      0x00003C00
+#define R600_IT_MEM_WRITE                         0x00003D00
+#define R600_IT_INDIRECT_BUFFER                   0x00003200
+#define R600_IT_CP_INTERRUPT                      0x00004000
+#define R600_IT_SURFACE_SYNC                      0x00004300
+#define R600_IT_ME_INITIALIZE                     0x00004400
+#define R600_IT_COND_WRITE                        0x00004500
+#define R600_IT_EVENT_WRITE                       0x00004600
+#define R600_IT_EVENT_WRITE_EOP                   0x00004700
+#define R600_IT_ONE_REG_WRITE                     0x00005700
+#define R600_IT_SET_CONFIG_REG                    0x00006800
+#define R600_IT_SET_CONTEXT_REG                   0x00006900
+#define R600_IT_SET_ALU_CONST                     0x00006A00
+#define R600_IT_SET_BOOL_CONST                    0x00006B00
+#define R600_IT_SET_LOOP_CONST                    0x00006C00
+#define R600_IT_SET_RESOURCE                      0x00006D00
+#define R600_IT_SET_SAMPLER                       0x00006E00
+#define R600_IT_SET_CTL_CONST                     0x00006F00
+#define R600_IT_SURFACE_BASE_UPDATE               0x00007300
+
+int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv)
+{
+       struct drm_radeon_cs_parser parser;
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct drm_radeon_cs *cs = data;
+       uint32_t cs_id;
+       struct drm_radeon_cs_chunk __user **chunk_ptr = NULL;
+       uint64_t *chunk_array;
+       uint64_t *chunk_array_ptr;
+       long size;
+       int r, i;
+
+       DRM_SPINLOCK(&dev_priv->cs.cs_mutex);
+       /* set command stream id to 0 which is fake id */
+       cs_id = 0;
+       cs->cs_id = cs_id;
+
+       if (dev_priv == NULL) {
+               DRM_ERROR("called with no initialization\n");
+               DRM_SPINUNLOCK(&dev_priv->cs.cs_mutex);
+               return -EINVAL;
+       }
+       if (!cs->num_chunks) {
+               DRM_SPINUNLOCK(&dev_priv->cs.cs_mutex);
+               return 0;
+       }
+
+
+       chunk_array = drm_calloc(cs->num_chunks, sizeof(uint64_t), DRM_MEM_DRIVER);
+       if (!chunk_array) {
+               DRM_SPINUNLOCK(&dev_priv->cs.cs_mutex);
+               return -ENOMEM;
+       }
+
+       chunk_array_ptr = (uint64_t *)(unsigned long)(cs->chunks);
+
+       if (DRM_COPY_FROM_USER(chunk_array, chunk_array_ptr, sizeof(uint64_t)*cs->num_chunks)) {
+               r = -EFAULT;
+               goto out;
+       }
+
+       parser.dev = dev;
+       parser.file_priv = fpriv;
+       parser.reloc_index = -1;
+       parser.ib_index = -1;
+       parser.num_chunks = cs->num_chunks;
+       /* copy out the chunk headers */
+       parser.chunks = drm_calloc(parser.num_chunks, sizeof(struct drm_radeon_kernel_chunk), DRM_MEM_DRIVER);
+       if (!parser.chunks) {
+               r = -ENOMEM;
+               goto out;
+       }
+
+       for (i = 0; i < parser.num_chunks; i++) {
+               struct drm_radeon_cs_chunk user_chunk;
+
+               chunk_ptr = (void __user *)(unsigned long)chunk_array[i];
+
+               if (DRM_COPY_FROM_USER(&user_chunk, chunk_ptr, sizeof(struct drm_radeon_cs_chunk))){
+                       r = -EFAULT;
+                       goto out;
+               }
+               parser.chunks[i].chunk_id = user_chunk.chunk_id;
+
+               if (parser.chunks[i].chunk_id == RADEON_CHUNK_ID_RELOCS)
+                       parser.reloc_index = i;
+
+               if (parser.chunks[i].chunk_id == RADEON_CHUNK_ID_IB)
+                       parser.ib_index = i;
+
+               if (parser.chunks[i].chunk_id == RADEON_CHUNK_ID_OLD) {
+                       parser.ib_index = i;
+                       parser.reloc_index = -1;
+               }
+
+               parser.chunks[i].length_dw = user_chunk.length_dw;
+               parser.chunks[i].chunk_data = (uint32_t *)(unsigned long)user_chunk.chunk_data;
+
+               parser.chunks[i].kdata = NULL;
+               size = parser.chunks[i].length_dw * sizeof(uint32_t);
+
+               switch(parser.chunks[i].chunk_id) {
+               case RADEON_CHUNK_ID_IB:
+               case RADEON_CHUNK_ID_OLD:
+                       if (size == 0) {
+                               r = -EINVAL;
+                               goto out;
+                       }
+               case RADEON_CHUNK_ID_RELOCS:
+                       if (size) {
+                               parser.chunks[i].kdata = drm_alloc(size, DRM_MEM_DRIVER);
+                               if (!parser.chunks[i].kdata) {
+                                       r = -ENOMEM;
+                                       goto out;
+                               }
+
+                               if (DRM_COPY_FROM_USER(parser.chunks[i].kdata, parser.chunks[i].chunk_data, size)) {
+                                       r = -EFAULT;
+                                       goto out;
+                               }
+                       } else
+                               parser.chunks[i].kdata = NULL;
+                       break;
+               default:
+                       break;
+               }
+               DRM_DEBUG("chunk %d %d %d %p\n", i, parser.chunks[i].chunk_id, parser.chunks[i].length_dw,
+                         parser.chunks[i].chunk_data);
+       }
+
+       if (parser.chunks[parser.ib_index].length_dw > (16 * 1024)) {
+               DRM_ERROR("cs->dwords too big: %d\n", parser.chunks[parser.ib_index].length_dw);
+               r = -EINVAL;
+               goto out;
+       }
+
+       /* get ib */
+       r = dev_priv->cs.ib_get(&parser);
+       if (r) {
+               DRM_ERROR("ib_get failed\n");
+               goto out;
+       }
+
+       /* now parse command stream */
+       r = dev_priv->cs.parse(&parser);
+       if (r) {
+               goto out;
+       }
+
+out:
+       dev_priv->cs.ib_free(&parser, r);
+
+       /* emit cs id sequence */
+       dev_priv->cs.id_emit(&parser, &cs_id);
+
+       cs->cs_id = cs_id;
+
+       DRM_SPINUNLOCK(&dev_priv->cs.cs_mutex);
+
+       for (i = 0; i < parser.num_chunks; i++) {
+               if (parser.chunks[i].kdata)
+                       drm_free(parser.chunks[i].kdata, parser.chunks[i].length_dw * sizeof(uint32_t), DRM_MEM_DRIVER);
+       }
+
+       drm_free(parser.chunks, sizeof(struct drm_radeon_kernel_chunk)*parser.num_chunks, DRM_MEM_DRIVER);
+       drm_free(chunk_array, sizeof(uint64_t)*parser.num_chunks, DRM_MEM_DRIVER);
+
+       return r;
+}
+
+/* for non-mm */
+static int r600_nomm_relocate(struct drm_radeon_cs_parser *parser, uint32_t *reloc, uint64_t *offset)
+{
+       struct drm_device *dev = parser->dev;
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       struct drm_radeon_kernel_chunk *reloc_chunk = &parser->chunks[parser->reloc_index];
+       uint32_t offset_dw = reloc[1];
+
+       //DRM_INFO("reloc: 0x%08x 0x%08x\n", reloc[0], reloc[1]);
+       //DRM_INFO("length: %d\n", reloc_chunk->length_dw);
+
+       if (!reloc_chunk->kdata)
+               return -EINVAL;
+
+       if (offset_dw > reloc_chunk->length_dw) {
+               DRM_ERROR("Offset larger than chunk 0x%x %d\n", offset_dw, reloc_chunk->length_dw);
+               return -EINVAL;
+       }
+
+       /* 40 bit addr */
+       *offset = reloc_chunk->kdata[offset_dw + 3];
+       *offset <<= 32;
+       *offset |= reloc_chunk->kdata[offset_dw + 0];
+
+       //DRM_INFO("offset 0x%lx\n", *offset);
+
+       if (!radeon_check_offset(dev_priv, *offset)) {
+               DRM_ERROR("bad offset! 0x%lx\n", (unsigned long)*offset);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static inline int r600_cs_packet0(struct drm_radeon_cs_parser *parser, uint32_t *offset_dw_p)
+{
+       uint32_t hdr, num_dw, reg;
+       int count_dw = 1;
+       int ret = 0;
+       uint32_t offset_dw = *offset_dw_p;
+       int incr = 2;
+
+       hdr = parser->chunks[parser->ib_index].kdata[offset_dw];
+       num_dw = ((hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16) + 2;
+       reg = (hdr & 0xffff) << 2;
+
+       while (count_dw < num_dw) {
+               switch (reg) {
+               case AVIVO_D1MODE_VLINE_START_END:
+               case AVIVO_D2MODE_VLINE_START_END:
+                       break;
+               default:
+                       ret = -EINVAL;
+                       DRM_ERROR("bad packet 0 reg: 0x%08x\n", reg);
+                       break;
+               }
+               if (ret)
+                       break;
+               count_dw++;
+               reg += 4;
+       }
+       *offset_dw_p += incr;
+       return ret;
+}
+
+static inline int r600_cs_packet3(struct drm_radeon_cs_parser *parser, uint32_t *offset_dw_p)
+{
+       struct drm_device *dev = parser->dev;
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       uint32_t hdr, num_dw, start_reg, end_reg, reg;
+       uint32_t *reloc;
+       uint64_t offset;
+       int ret = 0;
+       uint32_t offset_dw = *offset_dw_p;
+       int incr = 2;
+       int i;
+       struct drm_radeon_kernel_chunk *ib_chunk;
+
+       ib_chunk = &parser->chunks[parser->ib_index];
+
+       hdr = ib_chunk->kdata[offset_dw];
+       num_dw = ((hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16) + 2;
+
+       /* just the ones we use for now, add more later */
+       switch (hdr & 0xff00) {
+       case R600_IT_START_3D_CMDBUF:
+               //DRM_INFO("R600_IT_START_3D_CMDBUF\n");
+               if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770)
+                       ret = -EINVAL;
+               if (num_dw != 2)
+                       ret = -EINVAL;
+               if (ret)
+                       DRM_ERROR("bad START_3D\n");
+               break;
+       case R600_IT_CONTEXT_CONTROL:
+               //DRM_INFO("R600_IT_CONTEXT_CONTROL\n");
+               if (num_dw != 3)
+                       ret = -EINVAL;
+               if (ret)
+                       DRM_ERROR("bad CONTEXT_CONTROL\n");
+               break;
+       case R600_IT_INDEX_TYPE:
+       case R600_IT_NUM_INSTANCES:
+               //DRM_INFO("R600_IT_INDEX_TYPE/R600_IT_NUM_INSTANCES\n");
+               if (num_dw != 2)
+                       ret = -EINVAL;
+               if (ret)
+                       DRM_ERROR("bad INDEX_TYPE/NUM_INSTANCES\n");
+               break;
+       case R600_IT_DRAW_INDEX:
+               //DRM_INFO("R600_IT_DRAW_INDEX\n");
+               if (num_dw != 5) {
+                       ret = -EINVAL;
+                       DRM_ERROR("bad DRAW_INDEX\n");
+                       break;
+               }
+               reloc = ib_chunk->kdata + offset_dw + num_dw;
+               ret = dev_priv->cs.relocate(parser, reloc, &offset);
+               if (ret) {
+                       DRM_ERROR("bad DRAW_INDEX\n");
+                       break;
+               }
+               ib_chunk->kdata[offset_dw + 1] += (offset & 0xffffffff);
+               ib_chunk->kdata[offset_dw + 2] += (upper_32_bits(offset) & 0xff);
+               break;
+       case R600_IT_DRAW_INDEX_AUTO:
+               //DRM_INFO("R600_IT_DRAW_INDEX_AUTO\n");
+               if (num_dw != 3)
+                       ret = -EINVAL;
+               if (ret)
+                       DRM_ERROR("bad DRAW_INDEX_AUTO\n");
+               break;
+       case R600_IT_DRAW_INDEX_IMMD_BE:
+       case R600_IT_DRAW_INDEX_IMMD:
+               //DRM_INFO("R600_IT_DRAW_INDEX_IMMD\n");
+               if (num_dw < 4)
+                       ret = -EINVAL;
+               if (ret)
+                       DRM_ERROR("bad DRAW_INDEX_IMMD\n");
+               break;
+       case R600_IT_WAIT_REG_MEM:
+               //DRM_INFO("R600_IT_WAIT_REG_MEM\n");
+               if (num_dw != 7)
+                       ret = -EINVAL;
+               /* bit 4 is reg (0) or mem (1) */
+               if (ib_chunk->kdata[offset_dw + 1] & 0x10) {
+                       reloc = ib_chunk->kdata + offset_dw + num_dw;
+                       ret = dev_priv->cs.relocate(parser, reloc, &offset);
+                       if (ret) {
+                               DRM_ERROR("bad WAIT_REG_MEM\n");
+                               break;
+                       }
+                       ib_chunk->kdata[offset_dw + 2] += (offset & 0xffffffff);
+                       ib_chunk->kdata[offset_dw + 3] += (upper_32_bits(offset) & 0xff);
+               }
+               if (ret)
+                       DRM_ERROR("bad WAIT_REG_MEM\n");
+               break;
+       case R600_IT_SURFACE_SYNC:
+               //DRM_INFO("R600_IT_SURFACE_SYNC\n");
+               if (num_dw != 5)
+                       ret = -EINVAL;
+               /* 0xffffffff/0x0 is flush all cache flag */
+               else if ((ib_chunk->kdata[offset_dw + 2] == 0xffffffff) &&
+                        (ib_chunk->kdata[offset_dw + 3] == 0))
+                       ret = 0;
+               else {
+                       reloc = ib_chunk->kdata + offset_dw + num_dw;
+                       ret = dev_priv->cs.relocate(parser, reloc, &offset);
+                       if (ret) {
+                               DRM_ERROR("bad SURFACE_SYNC\n");
+                               break;
+                       }
+                       ib_chunk->kdata[offset_dw + 3] += ((offset >> 8) & 0xffffffff);
+               }
+               break;
+       case R600_IT_EVENT_WRITE:
+               //DRM_INFO("R600_IT_EVENT_WRITE\n");
+               if ((num_dw != 4) && (num_dw != 2))
+                       ret = -EINVAL;
+               if (num_dw > 2) {
+                       reloc = ib_chunk->kdata + offset_dw + num_dw;
+                       ret = dev_priv->cs.relocate(parser, reloc, &offset);
+                       if (ret) {
+                               DRM_ERROR("bad EVENT_WRITE\n");
+                               break;
+                       }
+                       ib_chunk->kdata[offset_dw + 2] += (offset & 0xffffffff);
+                       ib_chunk->kdata[offset_dw + 3] += (upper_32_bits(offset) & 0xff);
+               }
+               if (ret)
+                       DRM_ERROR("bad EVENT_WRITE\n");
+               break;
+       case R600_IT_EVENT_WRITE_EOP:
+               //DRM_INFO("R600_IT_EVENT_WRITE_EOP\n");
+               if (num_dw != 6) {
+                       ret = -EINVAL;
+                       DRM_ERROR("bad EVENT_WRITE_EOP\n");
+                       break;
+               }
+               reloc = ib_chunk->kdata + offset_dw + num_dw;
+               ret = dev_priv->cs.relocate(parser, reloc, &offset);
+               if (ret) {
+                       DRM_ERROR("bad EVENT_WRITE_EOP\n");
+                       break;
+               }
+               ib_chunk->kdata[offset_dw + 2] += (offset & 0xffffffff);
+               ib_chunk->kdata[offset_dw + 3] += (upper_32_bits(offset) & 0xff);
+               break;
+       case R600_IT_SET_CONFIG_REG:
+               //DRM_INFO("R600_IT_SET_CONFIG_REG\n");
+               start_reg = (ib_chunk->kdata[offset_dw + 1] << 2) + R600_SET_CONFIG_REG_OFFSET;
+               end_reg = 4 * (num_dw - 2) + start_reg - 4;
+               if ((start_reg < R600_SET_CONFIG_REG_OFFSET) ||
+                   (start_reg >= R600_SET_CONFIG_REG_END) ||
+                   (end_reg >= R600_SET_CONFIG_REG_END))
+                       ret = -EINVAL;
+               else {
+                       for (i = 0; i < (num_dw - 2); i++) {
+                               reg = start_reg + (4 * i);
+                               switch (reg) {
+                               case R600_CP_COHER_BASE:
+                                       /* use R600_IT_SURFACE_SYNC */
+                                       ret = -EINVAL;
+                                       break;
+                               default:
+                                       break;
+                               }
+                               if (ret)
+                                       break;
+                       }
+               }
+               if (ret)
+                       DRM_ERROR("bad SET_CONFIG_REG\n");
+               break;
+       case R600_IT_SET_CONTEXT_REG:
+               //DRM_INFO("R600_IT_SET_CONTEXT_REG\n");
+               start_reg = ib_chunk->kdata[offset_dw + 1] << 2;
+               start_reg += R600_SET_CONTEXT_REG_OFFSET;
+               end_reg = 4 * (num_dw - 2) + start_reg - 4;
+               if ((start_reg < R600_SET_CONTEXT_REG_OFFSET) ||
+                   (start_reg >= R600_SET_CONTEXT_REG_END) ||
+                   (end_reg >= R600_SET_CONTEXT_REG_END))
+                       ret = -EINVAL;
+               else {
+                       for (i = 0; i < (num_dw - 2); i++) {
+                               reg = start_reg + (4 * i);
+                               switch (reg) {
+                               case R600_DB_DEPTH_BASE:
+                               case R600_CB_COLOR0_BASE:
+                               case R600_CB_COLOR1_BASE:
+                               case R600_CB_COLOR2_BASE:
+                               case R600_CB_COLOR3_BASE:
+                               case R600_CB_COLOR4_BASE:
+                               case R600_CB_COLOR5_BASE:
+                               case R600_CB_COLOR6_BASE:
+                               case R600_CB_COLOR7_BASE:
+                               case R600_SQ_PGM_START_FS:
+                               case R600_SQ_PGM_START_ES:
+                               case R600_SQ_PGM_START_VS:
+                               case R600_SQ_PGM_START_GS:
+                               case R600_SQ_PGM_START_PS:
+                                       //DRM_INFO("reg: 0x%08x\n", reg);
+                                       reloc = ib_chunk->kdata + offset_dw + num_dw + (i * 2);
+                                       ret = dev_priv->cs.relocate(parser, reloc, &offset);
+                                       if (ret) {
+                                               DRM_ERROR("bad SET_CONTEXT_REG\n");
+                                               break;
+                                       }
+                                       ib_chunk->kdata[offset_dw + 2 + i] +=
+                                               ((offset >> 8) & 0xffffffff);
+                                       break;
+                               case R600_VGT_DMA_BASE:
+                               case R600_VGT_DMA_BASE_HI:
+                                       /* These should be handled by DRAW_INDEX packet 3 */
+                               case R600_VGT_STRMOUT_BASE_OFFSET_0:
+                               case R600_VGT_STRMOUT_BASE_OFFSET_1:
+                               case R600_VGT_STRMOUT_BASE_OFFSET_2:
+                               case R600_VGT_STRMOUT_BASE_OFFSET_3:
+                               case R600_VGT_STRMOUT_BASE_OFFSET_HI_0:
+                               case R600_VGT_STRMOUT_BASE_OFFSET_HI_1:
+                               case R600_VGT_STRMOUT_BASE_OFFSET_HI_2:
+                               case R600_VGT_STRMOUT_BASE_OFFSET_HI_3:
+                               case R600_VGT_STRMOUT_BUFFER_BASE_0:
+                               case R600_VGT_STRMOUT_BUFFER_BASE_1:
+                               case R600_VGT_STRMOUT_BUFFER_BASE_2:
+                               case R600_VGT_STRMOUT_BUFFER_BASE_3:
+                               case R600_VGT_STRMOUT_BUFFER_OFFSET_0:
+                               case R600_VGT_STRMOUT_BUFFER_OFFSET_1:
+                               case R600_VGT_STRMOUT_BUFFER_OFFSET_2:
+                               case R600_VGT_STRMOUT_BUFFER_OFFSET_3:
+                                       /* These should be handled by STRMOUT_BUFFER packet 3 */
+                                       DRM_ERROR("bad context reg: 0x%08x\n", reg);
+                                       ret = -EINVAL;
+                                       break;
+                               default:
+                                       break;
+                               }
+                               if (ret)
+                                       break;
+                       }
+               }
+               if (ret)
+                       DRM_ERROR("bad SET_CONTEXT_REG\n");
+               break;
+       case R600_IT_SET_RESOURCE:
+               //DRM_INFO("R600_IT_SET_RESOURCE\n");
+               if ((num_dw - 2) % 7)
+                       ret = -EINVAL;
+               start_reg = ib_chunk->kdata[offset_dw + 1] << 2;
+               start_reg += R600_SET_RESOURCE_OFFSET;
+               end_reg = 4 * (num_dw - 2) + start_reg - 4;
+               if ((start_reg < R600_SET_RESOURCE_OFFSET) ||
+                   (start_reg >= R600_SET_RESOURCE_END) ||
+                   (end_reg >= R600_SET_RESOURCE_END))
+                       ret = -EINVAL;
+               else {
+                       for (i = 0; i < ((num_dw - 2) / 7); i++) {
+                               switch ((ib_chunk->kdata[offset_dw + (i * 7) + 6 + 2] & 0xc0000000) >> 30) {
+                               case R600_SQ_TEX_VTX_INVALID_TEXTURE:
+                               case R600_SQ_TEX_VTX_INVALID_BUFFER:
+                               default:
+                                       ret = -EINVAL;
+                                       break;
+                               case R600_SQ_TEX_VTX_VALID_TEXTURE:
+                                       /* tex base */
+                                       reloc = ib_chunk->kdata + offset_dw + num_dw + (i * 4);
+                                       ret = dev_priv->cs.relocate(parser, reloc, &offset);
+                                       if (ret)
+                                               break;
+                                       ib_chunk->kdata[offset_dw + (i * 7) + 2 + 2] +=
+                                               ((offset >> 8) & 0xffffffff);
+                                       /* tex mip base */
+                                       reloc = ib_chunk->kdata + offset_dw + num_dw + (i * 4) + 2;
+                                       ret = dev_priv->cs.relocate(parser, reloc, &offset);
+                                       if (ret)
+                                               break;
+                                       ib_chunk->kdata[offset_dw + (i * 7) + 3 + 2] +=
+                                               ((offset >> 8) & 0xffffffff);
+                                       break;
+                               case R600_SQ_TEX_VTX_VALID_BUFFER:
+                                       /* vtx base */
+                                       reloc = ib_chunk->kdata + offset_dw + num_dw + (i * 2);
+                                       ret = dev_priv->cs.relocate(parser, reloc, &offset);
+                                       if (ret)
+                                               break;
+                                       ib_chunk->kdata[offset_dw + (i * 7) + 0 + 2] += (offset & 0xffffffff);
+                                       ib_chunk->kdata[offset_dw + (i * 7) + 2 + 2] += (upper_32_bits(offset) & 0xff);
+                                       break;
+                               }
+                               if (ret)
+                                       break;
+                       }
+               }
+               if (ret)
+                       DRM_ERROR("bad SET_RESOURCE\n");
+               break;
+       case R600_IT_SET_ALU_CONST:
+               //DRM_INFO("R600_IT_SET_ALU_CONST\n");
+               start_reg = ib_chunk->kdata[offset_dw + 1] << 2;
+               start_reg += R600_SET_ALU_CONST_OFFSET;
+               end_reg = 4 * (num_dw - 2) + start_reg - 4;
+               if ((start_reg < R600_SET_ALU_CONST_OFFSET) ||
+                   (start_reg >= R600_SET_ALU_CONST_END) ||
+                   (end_reg >= R600_SET_ALU_CONST_END))
+                       ret = -EINVAL;
+               if (ret)
+                       DRM_ERROR("bad SET_ALU_CONST\n");
+               break;
+       case R600_IT_SET_BOOL_CONST:
+               //DRM_INFO("R600_IT_SET_BOOL_CONST\n");
+               start_reg = ib_chunk->kdata[offset_dw + 1] << 2;
+               start_reg += R600_SET_BOOL_CONST_OFFSET;
+               end_reg = 4 * (num_dw - 2) + start_reg - 4;
+               if ((start_reg < R600_SET_BOOL_CONST_OFFSET) ||
+                   (start_reg >= R600_SET_BOOL_CONST_END) ||
+                   (end_reg >= R600_SET_BOOL_CONST_END))
+                       ret = -EINVAL;
+               if (ret)
+                       DRM_ERROR("bad SET_BOOL_CONST\n");
+               break;
+       case R600_IT_SET_LOOP_CONST:
+               //DRM_INFO("R600_IT_SET_LOOP_CONST\n");
+               start_reg = ib_chunk->kdata[offset_dw + 1] << 2;
+               start_reg += R600_SET_LOOP_CONST_OFFSET;
+               end_reg = 4 * (num_dw - 2) + start_reg - 4;
+               if ((start_reg < R600_SET_LOOP_CONST_OFFSET) ||
+                   (start_reg >= R600_SET_LOOP_CONST_END) ||
+                   (end_reg >= R600_SET_LOOP_CONST_END))
+                       ret = -EINVAL;
+               if (ret)
+                       DRM_ERROR("bad SET_LOOP_CONST\n");
+               break;
+       case R600_IT_SET_CTL_CONST:
+               //DRM_INFO("R600_IT_SET_CTL_CONST\n");
+               start_reg = ib_chunk->kdata[offset_dw + 1] << 2;
+               start_reg += R600_SET_CTL_CONST_OFFSET;
+               end_reg = 4 * (num_dw - 2) + start_reg - 4;
+               if ((start_reg < R600_SET_CTL_CONST_OFFSET) ||
+                   (start_reg >= R600_SET_CTL_CONST_END) ||
+                   (end_reg >= R600_SET_CTL_CONST_END))
+                       ret = -EINVAL;
+               if (ret)
+                       DRM_ERROR("bad SET_CTL_CONST\n");
+               break;
+       case R600_IT_SET_SAMPLER:
+               //DRM_INFO("R600_IT_SET_SAMPLER\n");
+               if ((num_dw - 2) % 3)
+                       ret = -EINVAL;
+               start_reg = ib_chunk->kdata[offset_dw + 1] << 2;
+               start_reg += R600_SET_SAMPLER_OFFSET;
+               end_reg = 4 * (num_dw - 2) + start_reg - 4;
+               if ((start_reg < R600_SET_SAMPLER_OFFSET) ||
+                   (start_reg >= R600_SET_SAMPLER_END) ||
+                   (end_reg >= R600_SET_SAMPLER_END))
+                       ret = -EINVAL;
+               if (ret)
+                       DRM_ERROR("bad SET_SAMPLER\n");
+               break;
+       case R600_IT_SURFACE_BASE_UPDATE:
+               //DRM_INFO("R600_IT_SURFACE_BASE_UPDATE\n");
+               if (((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770) ||
+                   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R600))
+                       ret = -EINVAL;
+               if (num_dw != 2)
+                       ret = -EINVAL;
+               if (ret)
+                       DRM_ERROR("bad SURFACE_BASE_UPDATE\n");
+               break;
+       case RADEON_CP_NOP:
+               //DRM_INFO("NOP: %d\n", ib_chunk->kdata[offset_dw + 1]);
+               break;
+       default:
+               DRM_ERROR("invalid packet 3 0x%08x\n", 0xff00);
+               ret = -EINVAL;
+               break;
+       }
+
+       *offset_dw_p += incr;
+       return ret;
+}
+
+static int r600_cs_parse(struct drm_radeon_cs_parser *parser)
+{
+       volatile int rb;
+       struct drm_radeon_kernel_chunk *ib_chunk;
+       /* scan the packet for various things */
+       int count_dw = 0, size_dw;
+       int ret = 0;
+
+       ib_chunk = &parser->chunks[parser->ib_index];
+       size_dw = ib_chunk->length_dw;
+
+       while (count_dw < size_dw && ret == 0) {
+               int hdr = ib_chunk->kdata[count_dw];
+               int num_dw = (hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16;
+
+               switch (hdr & RADEON_CP_PACKET_MASK) {
+               case RADEON_CP_PACKET0:
+                       ret = r600_cs_packet0(parser, &count_dw);
+                       break;
+               case RADEON_CP_PACKET1:
+                       ret = -EINVAL;
+                       break;
+               case RADEON_CP_PACKET2:
+                       DRM_DEBUG("Packet 2\n");
+                       num_dw += 1;
+                       break;
+               case RADEON_CP_PACKET3:
+                       ret = r600_cs_packet3(parser, &count_dw);
+                       break;
+               }
+
+               count_dw += num_dw;
+       }
+
+       if (ret)
+               return ret;
+
+
+       /* copy the packet into the IB */
+       memcpy(parser->ib, ib_chunk->kdata, ib_chunk->length_dw * sizeof(uint32_t));
+
+       /* read back last byte to flush WC buffers */
+       rb = readl(((vm_offset_t)parser->ib + (ib_chunk->length_dw-1) * sizeof(uint32_t)));
+
+       return 0;
+}
+
+static uint32_t radeon_cs_id_get(struct drm_radeon_private *radeon)
+{
+       /* FIXME: protect with a spinlock */
+       /* FIXME: check if wrap affect last reported wrap & sequence */
+       radeon->cs.id_scnt = (radeon->cs.id_scnt + 1) & 0x00FFFFFF;
+       if (!radeon->cs.id_scnt) {
+               /* increment wrap counter */
+               radeon->cs.id_wcnt += 0x01000000;
+               /* valid sequence counter start at 1 */
+               radeon->cs.id_scnt = 1;
+       }
+       return (radeon->cs.id_scnt | radeon->cs.id_wcnt);
+}
+
+static void r600_cs_id_emit(struct drm_radeon_cs_parser *parser, uint32_t *id)
+{
+       drm_radeon_private_t *dev_priv = parser->dev->dev_private;
+       RING_LOCALS;
+
+       //dev_priv->irq_emitted = radeon_update_breadcrumb(parser->dev);
+
+       *id = radeon_cs_id_get(dev_priv);
+
+       /* SCRATCH 2 */
+       BEGIN_RING(3);
+       R600_CLEAR_AGE(*id);
+       ADVANCE_RING();
+       COMMIT_RING();
+}
+
+static uint32_t r600_cs_id_last_get(struct drm_device *dev)
+{
+       //drm_radeon_private_t *dev_priv = dev->dev_private;
+
+       //return GET_R600_SCRATCH(dev_priv, 2);
+       return 0;
+}
+
+static int r600_ib_get(struct drm_radeon_cs_parser *parser)
+{
+       struct drm_device *dev = parser->dev;
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       struct drm_buf *buf;
+
+       buf = radeon_freelist_get(dev);
+       if (!buf) {
+               dev_priv->cs_buf = NULL;
+               return -EBUSY;
+       }
+       buf->file_priv = parser->file_priv;
+       dev_priv->cs_buf = buf;
+       parser->ib = (void *)((vm_offset_t)dev->agp_buffer_map->handle +
+           buf->offset);
+
+       return 0;
+}
+
+static void r600_ib_free(struct drm_radeon_cs_parser *parser, int error)
+{
+       struct drm_device *dev = parser->dev;
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       struct drm_buf *buf = dev_priv->cs_buf;
+
+       if (buf) {
+               if (!error)
+                       r600_cp_dispatch_indirect(dev, buf, 0,
+                                                 parser->chunks[parser->ib_index].length_dw * sizeof(uint32_t));
+               radeon_cp_discard_buffer(dev, buf);
+               COMMIT_RING();
+       }
+}
+
+int r600_cs_init(struct drm_device *dev)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+
+       dev_priv->cs.ib_get = r600_ib_get;
+       dev_priv->cs.ib_free = r600_ib_free;
+       dev_priv->cs.id_emit = r600_cs_id_emit;
+       dev_priv->cs.id_last_get = r600_cs_id_last_get;
+       dev_priv->cs.parse = r600_cs_parse;
+       dev_priv->cs.relocate = r600_nomm_relocate;
+       return 0;
+}
index c0d566c..ba6100a 100644 (file)
@@ -28,6 +28,7 @@
  *    Kevin E. Martin <martin@valinux.com>
  *    Gareth Hughes <gareth@valinux.com>
  *    Keith Whitwell <keith@tungstengraphics.com>
+ * __FBSDID("$FreeBSD: src/sys/dev/drm/radeon_drm.h,v 1.18 2009/08/23 15:02:58 rnoland Exp $");
  */
 
 #ifndef __RADEON_DRM_H__
@@ -494,6 +495,8 @@ typedef struct {
 #define DRM_RADEON_SURF_ALLOC 0x1a
 #define DRM_RADEON_SURF_FREE  0x1b
 
+#define DRM_RADEON_CS         0x26
+
 #define DRM_IOCTL_RADEON_CP_INIT    DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_INIT, drm_radeon_init_t)
 #define DRM_IOCTL_RADEON_CP_START   DRM_IO(  DRM_COMMAND_BASE + DRM_RADEON_CP_START)
 #define DRM_IOCTL_RADEON_CP_STOP    DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_STOP, drm_radeon_cp_stop_t)
@@ -521,6 +524,7 @@ typedef struct {
 #define DRM_IOCTL_RADEON_SETPARAM   DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_SETPARAM, drm_radeon_setparam_t)
 #define DRM_IOCTL_RADEON_SURF_ALLOC DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_SURF_ALLOC, drm_radeon_surface_alloc_t)
 #define DRM_IOCTL_RADEON_SURF_FREE  DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_SURF_FREE, drm_radeon_surface_free_t)
+#define DRM_IOCTL_RADEON_CS DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_CS, struct drm_radeon_cs)
 
 typedef struct drm_radeon_init {
        enum {
@@ -682,6 +686,8 @@ typedef struct drm_radeon_indirect {
 #define RADEON_PARAM_VBLANK_CRTC           13   /* VBLANK CRTC */
 #define RADEON_PARAM_FB_LOCATION           14   /* FB location */
 #define RADEON_PARAM_NUM_GB_PIPES          15   /* num GB pipes */
+#define RADEON_PARAM_DEVICE_ID             16
+#define RADEON_PARAM_NUM_Z_PIPES           17   /* num Z pipes */
 
 typedef struct drm_radeon_getparam {
        int param;
@@ -752,4 +758,23 @@ typedef struct drm_radeon_surface_free {
 #define        DRM_RADEON_VBLANK_CRTC1         1
 #define        DRM_RADEON_VBLANK_CRTC2         2
 
+/* New interface which obsolete all previous interface.
+ */
+#define RADEON_CHUNK_ID_RELOCS 0x01
+#define RADEON_CHUNK_ID_IB     0x02
+#define RADEON_CHUNK_ID_OLD 0xff
+
+struct drm_radeon_cs_chunk {
+       uint32_t chunk_id;
+       uint32_t length_dw;
+       uint64_t chunk_data;
+};
+
+struct drm_radeon_cs {
+       uint32_t        num_chunks;
+       uint32_t        cs_id;
+       uint64_t        chunks; /* this points to uint64_t * which point to
+                                  cs chunks */
+};
+
 #endif
index 511e3eb..33001a2 100644 (file)
@@ -26,6 +26,7 @@
  * Authors:
  *    Kevin E. Martin <martin@valinux.com>
  *    Gareth Hughes <gareth@valinux.com>
+ * __FBSDID("$FreeBSD: src/sys/dev/drm/radeon_drv.h,v 1.27 2009/09/28 22:40:29 rnoland Exp $");
  */
 
 #ifndef __RADEON_DRV_H__
@@ -38,7 +39,7 @@
 
 #define DRIVER_NAME            "radeon"
 #define DRIVER_DESC            "ATI Radeon"
-#define DRIVER_DATE            "20080528"
+#define DRIVER_DATE            "20080613"
 
 /* Interface history:
  *
  * 1.27- Add support for IGP GART
  * 1.28- Add support for VBL on CRTC2
  * 1.29- R500 3D cmd buffer support
+ * 1.30- Add support for occlusion queries
+ * 1.31- Add support for num Z pipes from GET_PARAM
  */
 #define DRIVER_MAJOR           1
-#define DRIVER_MINOR           29
+#define DRIVER_MINOR           31
 #define DRIVER_PATCHLEVEL      0
 
 /*
@@ -138,15 +141,15 @@ enum radeon_family {
        CHIP_R600,
        CHIP_RV610,
        CHIP_RV630,
+       CHIP_RV670,
        CHIP_RV620,
        CHIP_RV635,
-       CHIP_RV670,
        CHIP_RS780,
        CHIP_RS880,
        CHIP_RV770,
-       CHIP_RV740,
        CHIP_RV730,
        CHIP_RV710,
+       CHIP_RV740,
        CHIP_LAST,
 };
 
@@ -233,6 +236,46 @@ struct radeon_virt_surface {
 #define PCIGART_FILE_PRIV      ((void *) -1L)
 };
 
+struct drm_radeon_kernel_chunk {
+       uint32_t chunk_id;
+       uint32_t length_dw;
+       uint32_t __user *chunk_data;
+       uint32_t *kdata;
+};
+
+struct drm_radeon_cs_parser {
+       struct drm_device *dev;
+       struct drm_file *file_priv;
+       uint32_t num_chunks;
+       struct drm_radeon_kernel_chunk *chunks;
+       int ib_index;
+       int reloc_index;
+       uint32_t card_offset;
+       void *ib;
+};
+
+/* command submission struct */
+struct drm_radeon_cs_priv {
+       DRM_SPINTYPE cs_mutex;
+       uint32_t id_wcnt;
+       uint32_t id_scnt;
+       uint32_t id_last_wcnt;
+       uint32_t id_last_scnt;
+
+       int (*parse)(struct drm_radeon_cs_parser *parser);
+       void (*id_emit)(struct drm_radeon_cs_parser *parser, uint32_t *id);
+       uint32_t (*id_last_get)(struct drm_device *dev);
+       /* this ib handling callback are for hidding memory manager drm
+        * from memory manager less drm, free have to emit ib discard
+        * sequence into the ring */
+       int (*ib_get)(struct drm_radeon_cs_parser *parser);
+       uint32_t (*ib_get_ptr)(struct drm_device *dev, void *ib);
+       void (*ib_free)(struct drm_radeon_cs_parser *parser, int error);
+       /* do a relocation either MM or non-MM */
+       int (*relocate)(struct drm_radeon_cs_parser *parser,
+                       uint32_t *reloc, uint64_t *offset);
+};
+
 #define RADEON_FLUSH_EMITED    (1 << 0)
 #define RADEON_PURGE_EMITED    (1 << 1)
 
@@ -325,6 +368,7 @@ typedef struct drm_radeon_private {
        unsigned long fb_aper_offset;
 
        int num_gb_pipes;
+       int num_z_pipes;
        int track_flush;
        drm_local_map_t *mmio;
 
@@ -346,6 +390,12 @@ typedef struct drm_radeon_private {
        int r700_sc_prim_fifo_size;
        int r700_sc_hiz_tile_fifo_size;
        int r700_sc_earlyz_tile_fifo_fize;
+       /* r6xx/r7xx drm blit vertex buffer */
+       struct drm_buf *blit_vb;
+
+       /* CS */
+       struct drm_radeon_cs_priv cs;
+       struct drm_buf *cs_buf;
 
 } drm_radeon_private_t;
 
@@ -376,10 +426,10 @@ extern void radeon_set_ring_head(drm_radeon_private_t *dev_priv, u32 val);
 static __inline__ int radeon_check_offset(drm_radeon_private_t *dev_priv,
                                          u64 off)
 {
-       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;
+       u64 fb_start = dev_priv->fb_location;
+       u64 fb_end = fb_start + dev_priv->fb_size - 1;
+       u64 gart_start = dev_priv->gart_vm_start;
+       u64 gart_end = gart_start + dev_priv->gart_size - 1;
 
        return ((off >= fb_start && off <= fb_end) ||
                (off >= gart_start && off <= gart_end));
@@ -473,6 +523,33 @@ extern int r600_cp_dispatch_indirect(struct drm_device *dev,
                                     struct drm_buf *buf, int start, int end);
 extern int r600_page_table_init(struct drm_device *dev);
 extern void r600_page_table_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info);
+extern void r600_cp_dispatch_swap(struct drm_device * dev);
+extern int r600_cp_dispatch_texture(struct drm_device * dev,
+                                   struct drm_file *file_priv,
+                                   drm_radeon_texture_t * tex,
+                                   drm_radeon_tex_image_t * image);
+
+/* r600_blit.c */
+extern int
+r600_prepare_blit_copy(struct drm_device *dev);
+extern void
+r600_done_blit_copy(struct drm_device *dev);
+extern void
+r600_blit_copy(struct drm_device *dev,
+              uint64_t src_gpu_addr, uint64_t dst_gpu_addr,
+              int size_bytes);
+extern void
+r600_blit_swap(struct drm_device *dev,
+              uint64_t src_gpu_addr, uint64_t dst_gpu_addr,
+              int sx, int sy, int dx, int dy,
+              int w, int h, int src_pitch, int dst_pitch, int cpp);
+
+/* radeon_state.c */
+extern void radeon_cp_discard_buffer(struct drm_device * dev, struct drm_buf * buf);
+
+/* radeon_cs.c */
+extern int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv);
+extern int r600_cs_init(struct drm_device *dev);
 
 /* Flags for stats.boxes
  */
@@ -682,6 +759,7 @@ extern void r600_page_table_cleanup(struct drm_device *dev, struct drm_ati_pciga
 
 /* pipe config regs */
 #define R400_GB_PIPE_SELECT             0x402c
+#define RV530_GB_PIPE_SELECT2           0x4124
 #define R500_DYN_SCLK_PWMEM_PIPE        0x000d /* PLL */
 #define R300_GB_TILE_CONFIG             0x4018
 #       define R300_ENABLE_TILING       (1 << 0)
@@ -1824,26 +1902,38 @@ do {                                                                    \
  */
 
 #define RADEON_WAIT_UNTIL_2D_IDLE() do {                               \
-       OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) );                 \
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)        \
+               OUT_RING( CP_PACKET0( R600_WAIT_UNTIL, 0 ) );           \
+       else                                                            \
+               OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) );         \
        OUT_RING( (RADEON_WAIT_2D_IDLECLEAN |                           \
                   RADEON_WAIT_HOST_IDLECLEAN) );                       \
 } while (0)
 
 #define RADEON_WAIT_UNTIL_3D_IDLE() do {                               \
-       OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) );                 \
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)        \
+               OUT_RING( CP_PACKET0( R600_WAIT_UNTIL, 0 ) );           \
+       else                                                            \
+               OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) );         \
        OUT_RING( (RADEON_WAIT_3D_IDLECLEAN |                           \
                   RADEON_WAIT_HOST_IDLECLEAN) );                       \
 } while (0)
 
 #define RADEON_WAIT_UNTIL_IDLE() do {                                  \
-       OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) );                 \
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)        \
+               OUT_RING( CP_PACKET0( R600_WAIT_UNTIL, 0 ) );           \
+       else                                                            \
+               OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) );         \
        OUT_RING( (RADEON_WAIT_2D_IDLECLEAN |                           \
                   RADEON_WAIT_3D_IDLECLEAN |                           \
                   RADEON_WAIT_HOST_IDLECLEAN) );                       \
 } while (0)
 
 #define RADEON_WAIT_UNTIL_PAGE_FLIPPED() do {                          \
-       OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) );                 \
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)        \
+               OUT_RING( CP_PACKET0( R600_WAIT_UNTIL, 0 ) );           \
+       else                                                            \
+               OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) );         \
        OUT_RING( RADEON_WAIT_CRTC_PFLIP );                             \
 } while (0)
 
@@ -1958,14 +2048,17 @@ do {                                                            \
 
 #define RING_LOCALS    int write, _nr, _align_nr; unsigned int mask; u32 *ring;
 
+#define RADEON_RING_ALIGN 16
+
 #define BEGIN_RING( n ) do {                                           \
        if ( RADEON_VERBOSE ) {                                         \
                DRM_INFO( "BEGIN_RING( %d )\n", (n));                   \
        }                                                               \
-       _align_nr = (n + 0xf) & ~0xf;                                   \
-       if (dev_priv->ring.space <= (_align_nr * sizeof(u32))) {        \
-                COMMIT_RING();                                         \
-               radeon_wait_ring( dev_priv, _align_nr * sizeof(u32));   \
+       _align_nr = RADEON_RING_ALIGN - ((dev_priv->ring.tail + n) & (RADEON_RING_ALIGN - 1)); \
+       _align_nr += n;                                                 \
+       if ( dev_priv->ring.space <= (_align_nr) * sizeof(u32) ) {      \
+               COMMIT_RING();                                          \
+               radeon_wait_ring( dev_priv, (_align_nr) * sizeof(u32) ); \
        }                                                               \
        _nr = n; dev_priv->ring.space -= (n) * sizeof(u32);             \
        ring = dev_priv->ring.start;                                    \
index 9ff3bfd..8165025 100644 (file)
@@ -28,6 +28,7 @@
  * Authors:
  *    Keith Whitwell <keith@tungstengraphics.com>
  *    Michel D�zer <michel@daenzer.net>
+ * __FBSDID("$FreeBSD: src/sys/dev/drm/radeon_irq.c,v 1.16 2009/09/28 22:37:07 rnoland Exp $");
  */
 
 #include "dev/drm/drmP.h"
@@ -191,6 +192,9 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
        u32 r500_disp_int;
        u32 tmp;
 
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+               return IRQ_NONE;
+
        /* Only consider the bits we're interested in - others could be used
         * outside the DRM
         */
@@ -320,6 +324,9 @@ int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_pr
        drm_radeon_irq_emit_t *emit = data;
        int result;
 
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+               return -EINVAL;
+
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (!dev_priv) {
@@ -360,6 +367,9 @@ void radeon_driver_irq_preinstall(struct drm_device * dev)
            (drm_radeon_private_t *) dev->dev_private;
        u32 dummy;
 
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+               return;
+
        /* Disable *all* interrupts */
        if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600)
                RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
@@ -377,6 +387,9 @@ int radeon_driver_irq_postinstall(struct drm_device * dev)
        atomic_set(&dev_priv->swi_emitted, 0);
        DRM_INIT_WAITQUEUE(&dev_priv->swi_queue);
 
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+               return 0;
+
        radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
 
        return 0;
@@ -391,6 +404,9 @@ void radeon_driver_irq_uninstall(struct drm_device * dev)
 
        dev_priv->irq_enabled = 0;
 
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+               return;
+
        if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600)
                RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
        /* Disable *all* interrupts */
index e7c5c5e..a77f475 100644 (file)
  * Authors:
  *    Gareth Hughes <gareth@valinux.com>
  *    Kevin E. Martin <martin@valinux.com>
+ * __FBSDID("$FreeBSD: src/sys/dev/drm/radeon_state.c,v 1.27 2009/09/28 22:37:07 rnoland Exp $");
  */
 
+#include <sys/cdefs.h>
+
 #include "dev/drm/drmP.h"
 #include "dev/drm/drm.h"
 #include "dev/drm/drm_sarea.h"
@@ -1538,7 +1541,7 @@ static void radeon_cp_dispatch_vertex(struct drm_device * dev,
        } while (i < nbox);
 }
 
-static void radeon_cp_discard_buffer(struct drm_device *dev, struct drm_buf *buf)
+void radeon_cp_discard_buffer(struct drm_device *dev, struct drm_buf *buf)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
        drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
@@ -2199,7 +2202,10 @@ static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *f
        if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
                sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
 
-       radeon_cp_dispatch_swap(dev);
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+               r600_cp_dispatch_swap(dev);
+       else
+               radeon_cp_dispatch_swap(dev);
        sarea_priv->ctx_owner = 0;
 
        COMMIT_RING();
@@ -2396,7 +2402,10 @@ static int radeon_cp_texture(struct drm_device *dev, void *data, struct drm_file
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
        VB_AGE_TEST_WITH_RETURN(dev_priv);
 
-       ret = radeon_cp_dispatch_texture(dev, file_priv, tex, &image);
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+               ret = r600_cp_dispatch_texture(dev, file_priv, tex, &image);
+       else
+               ret = radeon_cp_dispatch_texture(dev, file_priv, tex, &image);
 
        return ret;
 }
@@ -3015,7 +3024,10 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil
                value = GET_SCRATCH(dev_priv, 2);
                break;
        case RADEON_PARAM_IRQ_NR:
-               value = dev->irq;
+               if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+                       value = 0;
+               else
+                       value = dev->irq;
                break;
        case RADEON_PARAM_GART_BASE:
                value = dev_priv->gart_vm_start;
@@ -3069,6 +3081,9 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil
        case RADEON_PARAM_NUM_GB_PIPES:
                value = dev_priv->num_gb_pipes;
                break;
+       case RADEON_PARAM_NUM_Z_PIPES:
+               value = dev_priv->num_z_pipes;
+               break;
        default:
                DRM_DEBUG("Invalid parameter %d\n", param->param);
                return -EINVAL;
@@ -3153,6 +3168,14 @@ void radeon_driver_preclose(struct drm_device *dev, struct drm_file *file_priv)
 void radeon_driver_lastclose(struct drm_device *dev)
 {
        radeon_surfaces_release(PCIGART_FILE_PRIV, dev->dev_private);
+       if (dev->dev_private) {
+               drm_radeon_private_t *dev_priv = dev->dev_private;
+
+               if (dev_priv->sarea_priv &&
+                   dev_priv->sarea_priv->pfCurrentPage != 0)
+                       radeon_cp_dispatch_flip(dev);
+       }
+
        radeon_do_release(dev);
 }
 
@@ -3213,7 +3236,8 @@ struct drm_ioctl_desc radeon_ioctls[] = {
        DRM_IOCTL_DEF(DRM_RADEON_IRQ_WAIT, radeon_irq_wait, DRM_AUTH),
        DRM_IOCTL_DEF(DRM_RADEON_SETPARAM, radeon_cp_setparam, DRM_AUTH),
        DRM_IOCTL_DEF(DRM_RADEON_SURF_ALLOC, radeon_surface_alloc, DRM_AUTH),
-       DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH)
+       DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_CS, radeon_cs_ioctl, DRM_AUTH)
 };
 
 int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls);