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
#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>
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)
#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,
--- /dev/null
+/**************************************************************************
+ *
+ * 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;
+ }
+}
--- /dev/null
+/**************************************************************************
+ *
+ * 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
*
*/
+#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) {
}
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;
(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)
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_ */
"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)
{
--- /dev/null
+/**************************************************************************
+ *
+ * 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"));
+}
--- /dev/null
+/**************************************************************************
+ *
+ * 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
/*
- * $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 \
--- /dev/null
+/*-
+ * 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_ */
--- /dev/null
+/**************************************************************************
+ *
+ * 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;
+ }
+ }
+ }
+}
--- /dev/null
+/**************************************************************************
+ *
+ * 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
--- /dev/null
+/*-
+ * 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);
+}
#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"
#ifndef _I915_DRV_H_
#define _I915_DRV_H_
+#include "dev/drm/drm_mm.h"
#include "dev/drm/i915_reg.h"
/* General customization:
--- /dev/null
+/*-
+ * 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;
+}
* 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"
*/
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,
r600_do_engine_reset(dev);
r600_test_writeback(dev_priv);
+ r600_cs_init(dev);
+
return 0;
}
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;
+}
.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..
* 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"
{
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);
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) {
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 <=
buf->pending = 0;
return buf;
}
- start = 0;
+ if (++start >= dma->buf_count)
+ start = 0;
}
if (t) {
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;
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);
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;
/* 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 */
--- /dev/null
+/*-
+ * 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;
+}
* 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__
#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)
#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 {
#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;
#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
* 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__
#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
/*
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,
};
#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)
unsigned long fb_aper_offset;
int num_gb_pipes;
+ int num_z_pipes;
int track_flush;
drm_local_map_t *mmio;
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;
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));
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
*/
/* 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)
*/
#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)
#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; \
* 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"
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
*/
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) {
(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);
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;
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 */
* 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"
} 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;
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();
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;
}
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;
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;
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);
}
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);