From c9b2d4590c4e1418bd378d7e6c4cafda9b2d5861 Mon Sep 17 00:00:00 2001 From: "Sergey Semyonov (Serge)" Date: Thu, 2 Jul 2009 17:11:39 +0000 Subject: [PATCH] the simplest memory manager & index buffers git-svn-id: svn://kolibrios.org@1120 a494cfbc-eb01-0410-851d-a64ba20cac60 --- drivers/video/drm/include/drm_mm.h | 105 ++ drivers/video/drm/include/list.h | 703 +++++++++ drivers/video/drm/radeon/atom.c | 2 +- drivers/video/drm/radeon/pci.c | 8 +- drivers/video/drm/radeon/r100.c | 19 +- drivers/video/drm/radeon/r300.c | 1535 ++++++++++++++++++++ drivers/video/drm/radeon/r520.c | 297 +--- drivers/video/drm/radeon/radeon.h | 66 +- drivers/video/drm/radeon/radeon_asic.h | 4 +- drivers/video/drm/radeon/radeon_atombios.c | 2 +- drivers/video/drm/radeon/radeon_bios.c | 2 +- drivers/video/drm/radeon/radeon_device.c | 51 +- drivers/video/drm/radeon/radeon_gart.c | 261 ++++ drivers/video/drm/radeon/radeon_object.c | 1084 ++++++++++++++ drivers/video/drm/radeon/radeon_ring.c | 43 +- drivers/video/drm/radeon/rv515.c | 10 +- 16 files changed, 3798 insertions(+), 394 deletions(-) create mode 100644 drivers/video/drm/include/drm_mm.h create mode 100644 drivers/video/drm/include/list.h create mode 100644 drivers/video/drm/radeon/r300.c create mode 100644 drivers/video/drm/radeon/radeon_gart.c create mode 100644 drivers/video/drm/radeon/radeon_object.c diff --git a/drivers/video/drm/include/drm_mm.h b/drivers/video/drm/include/drm_mm.h new file mode 100644 index 0000000000..cde783403b --- /dev/null +++ b/drivers/video/drm/include/drm_mm.h @@ -0,0 +1,105 @@ +/************************************************************************** + * + * 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. + * + * + **************************************************************************/ +/* + * Authors: + * Thomas Hellstrom + */ + +#ifndef _DRM_MM_H_ +#define _DRM_MM_H_ + +/* + * Generic range manager structs + */ +#include +#include +#include + +#define spin_lock_init(x) +#define spin_lock(x) +#define spin_unlock(x) + +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; +// spinlock_t 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 diff --git a/drivers/video/drm/include/list.h b/drivers/video/drm/include/list.h new file mode 100644 index 0000000000..23bb56cd90 --- /dev/null +++ b/drivers/video/drm/include/list.h @@ -0,0 +1,703 @@ +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +//#include +//#include +//#include +//#include + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +#define LIST_POISON1 ((struct list_head*)0xFFFF0100) +#define LIST_POISON2 ((struct list_head*)0xFFFF0200) + +#define prefetch(x) __builtin_prefetch(x) + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +#ifndef CONFIG_DEBUG_LIST +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} +#else +extern void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next); +#endif + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +#ifndef CONFIG_DEBUG_LIST +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} +#else +extern void list_del(struct list_head *entry); +#endif + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void list_replace_init(struct list_head *old, + struct list_head *new) +{ + list_replace(old, new); + INIT_LIST_HEAD(old); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) +{ + return list->next == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is empty and not being modified + * @head: the list to test + * + * Description: + * tests whether a list is empty _and_ checks that no other CPU might be + * in the process of modifying either member (next or prev) + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +/** + * list_is_singular - tests whether a list has just one entry. + * @head: the list to test. + */ +static inline int list_is_singular(const struct list_head *head) +{ + return !list_empty(head) && (head->next == head->prev); +} + +static inline void __list_cut_position(struct list_head *list, + struct list_head *head, struct list_head *entry) +{ + struct list_head *new_first = entry->next; + list->next = head->next; + list->next->prev = list; + list->prev = entry; + entry->next = list; + head->next = new_first; + new_first->prev = head; +} + +/** + * list_cut_position - cut a list into two + * @list: a new list to add all removed entries + * @head: a list with entries + * @entry: an entry within head, could be the head itself + * and if so we won't cut the list + * + * This helper moves the initial part of @head, up to and + * including @entry, from @head to @list. You should + * pass on @entry an element you know is on @head. @list + * should be an empty list or a list you do not care about + * losing its data. + * + */ +static inline void list_cut_position(struct list_head *list, + struct list_head *head, struct list_head *entry) +{ + if (list_empty(head)) + return; + if (list_is_singular(head) && + (head->next != entry && head != entry)) + return; + if (entry == head) + INIT_LIST_HEAD(list); + else + __list_cut_position(list, head, entry); +} + +static inline void __list_splice(const struct list_head *list, + struct list_head *prev, + struct list_head *next) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + + first->prev = prev; + prev->next = first; + + last->next = next; + next->prev = last; +} + +/** + * list_splice - join two lists, this is designed for stacks + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(const struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head, head->next); +} + +/** + * list_splice_tail - join two lists, each list being a queue + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice_tail(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head->prev, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head, head->next); + INIT_LIST_HEAD(list); + } +} + +/** + * list_splice_tail_init - join two lists and reinitialise the emptied list + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * Each of the lists is a queue. + * The list at @list is reinitialised + */ +static inline void list_splice_tail_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head->prev, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; prefetch(pos->next), pos != (head); \ + pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ + pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_prev_safe(pos, n, head) \ + for (pos = (head)->prev, n = pos->prev; \ + prefetch(pos->prev), pos != (head); \ + pos = n, n = pos->prev) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + prefetch(pos->member.prev), &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + * + * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_continue_reverse - iterate backwards from the given point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Start to iterate over list of given type backwards, continuing after + * the current position. + */ +#define list_for_each_entry_continue_reverse(pos, head, member) \ + for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ + prefetch(pos->member.prev), &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_for_each_entry_from(pos, head, member) \ + for (; prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * 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)) + +/** + * list_for_each_entry_safe_continue + * @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. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos = list_entry(pos->member.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)) + +/** + * list_for_each_entry_safe_from + * @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. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_reverse + * @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. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + n = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.prev, typeof(*n), member)) + +/* + * Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +#if 0 +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +#define HLIST_HEAD_INIT { .first = NULL } +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) +static inline void INIT_HLIST_NODE(struct hlist_node *h) +{ + h->next = NULL; + h->pprev = NULL; +} + +static inline int hlist_unhashed(const struct hlist_node *h) +{ + return !h->pprev; +} + +static inline int hlist_empty(const struct hlist_head *h) +{ + return !h->first; +} + +static inline void __hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + *pprev = next; + if (next) + next->pprev = pprev; +} + +static inline void hlist_del(struct hlist_node *n) +{ + __hlist_del(n); + n->next = LIST_POISON1; + n->pprev = LIST_POISON2; +} + +static inline void hlist_del_init(struct hlist_node *n) +{ + if (!hlist_unhashed(n)) { + __hlist_del(n); + INIT_HLIST_NODE(n); + } +} + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + +/* next must be != NULL */ +static inline void hlist_add_before(struct hlist_node *n, + struct hlist_node *next) +{ + n->pprev = next->pprev; + n->next = next; + next->pprev = &n->next; + *(n->pprev) = n; +} + +static inline void hlist_add_after(struct hlist_node *n, + struct hlist_node *next) +{ + next->next = n->next; + n->next = next; + next->pprev = &n->next; + + if(next->next) + next->next->pprev = &next->next; +} + +/* + * Move a list from one list head to another. Fixup the pprev + * reference of the first entry if it exists. + */ +static inline void hlist_move_list(struct hlist_head *old, + struct hlist_head *new) +{ + new->first = old->first; + if (new->first) + new->first->pprev = &new->first; + old->first = NULL; +} + +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ + pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) + +/** + * hlist_for_each_entry - iterate over list of given type + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_continue - iterate over a hlist continuing after current point + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_continue(tpos, pos, member) \ + for (pos = (pos)->next; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_from - iterate over a hlist continuing from current point + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_from(tpos, pos, member) \ + for (; pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @n: another &struct hlist_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ + for (pos = (head)->first; \ + pos && ({ n = pos->next; 1; }) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = n) + +#endif + +#endif diff --git a/drivers/video/drm/radeon/atom.c b/drivers/video/drm/radeon/atom.c index 6e2dd7480d..06964cb378 100644 --- a/drivers/video/drm/radeon/atom.c +++ b/drivers/video/drm/radeon/atom.c @@ -1165,7 +1165,7 @@ struct atom_context *atom_parse(struct card_info *card, void *bios) int atom_asic_init(struct atom_context *ctx) { - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR); uint32_t ps[16]; diff --git a/drivers/video/drm/radeon/pci.c b/drivers/video/drm/radeon/pci.c index bd2b4bd8dd..e1c9092d6f 100644 --- a/drivers/video/drm/radeon/pci.c +++ b/drivers/video/drm/radeon/pci.c @@ -3,7 +3,7 @@ #include #include -link_t devices; +static LIST_HEAD(devices); static dev_t* pci_scan_device(u32_t bus, int devfn); @@ -346,7 +346,7 @@ static dev_t* pci_scan_device(u32_t bus, int devfn) dev = (dev_t*)malloc(sizeof(dev_t)); - link_initialize(&dev->link); + INIT_LIST_HEAD(&dev->link); if(unlikely(dev == NULL)) return NULL; @@ -375,7 +375,7 @@ int pci_scan_slot(u32_t bus, int devfn) dev = pci_scan_device(bus, devfn); if( dev ) { - list_append(&dev->link, &devices); + list_add(&dev->link, &devices); nr++; @@ -420,7 +420,7 @@ int enum_pci_devices() u32_t last_bus; u32_t bus = 0 , devfn = 0; - list_initialize(&devices); + // list_initialize(&devices); last_bus = PciApi(1); diff --git a/drivers/video/drm/radeon/r100.c b/drivers/video/drm/radeon/r100.c index c2d553a5a2..3f7b8a9167 100644 --- a/drivers/video/drm/radeon/r100.c +++ b/drivers/video/drm/radeon/r100.c @@ -268,6 +268,7 @@ void r100_fence_ring_emit(struct radeon_device *rdev, radeon_ring_write(rdev, RADEON_SW_INT_FIRE); } +#endif /* * Writeback @@ -307,14 +308,16 @@ int r100_wb_init(struct radeon_device *rdev) void r100_wb_fini(struct radeon_device *rdev) { if (rdev->wb.wb_obj) { - radeon_object_kunmap(rdev->wb.wb_obj); - radeon_object_unpin(rdev->wb.wb_obj); - radeon_object_unref(&rdev->wb.wb_obj); +// radeon_object_kunmap(rdev->wb.wb_obj); +// radeon_object_unpin(rdev->wb.wb_obj); +// radeon_object_unref(&rdev->wb.wb_obj); rdev->wb.wb = NULL; rdev->wb.wb_obj = NULL; } } + +#if 0 int r100_copy_blit(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, @@ -415,7 +418,7 @@ static void r100_cp_load_microcode(struct radeon_device *rdev) { int i; - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); if (r100_gui_wait_for_idle(rdev)) { printk(KERN_WARNING "Failed to wait GUI idle while " @@ -498,7 +501,7 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size) uint32_t tmp; int r; - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); // if (r100_debugfs_cp_init(rdev)) { // DRM_ERROR("Failed to register debugfs file for CP !\n"); @@ -624,7 +627,7 @@ int r100_cp_reset(struct radeon_device *rdev) bool reinit_cp; int i; - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); reinit_cp = rdev->cp.ready; @@ -1170,7 +1173,7 @@ void r100_hdp_reset(struct radeon_device *rdev) { uint32_t tmp; - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); tmp = RREG32(RADEON_HOST_PATH_CNTL) & RADEON_HDP_APER_CNTL; tmp |= (7 << 28); @@ -1187,7 +1190,7 @@ int r100_rb2d_reset(struct radeon_device *rdev) uint32_t tmp; int i; - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); WREG32(RADEON_RBBM_SOFT_RESET, RADEON_SOFT_RESET_E2); (void)RREG32(RADEON_RBBM_SOFT_RESET); diff --git a/drivers/video/drm/radeon/r300.c b/drivers/video/drm/radeon/r300.c new file mode 100644 index 0000000000..f171bf5bd1 --- /dev/null +++ b/drivers/video/drm/radeon/r300.c @@ -0,0 +1,1535 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +//#include +//#include "drmP.h" +//#include "drm.h" +#include "radeon_reg.h" +#include "radeon.h" + +/* r300,r350,rv350,rv370,rv380 depends on : */ +void r100_hdp_reset(struct radeon_device *rdev); +int r100_cp_reset(struct radeon_device *rdev); +int r100_rb2d_reset(struct radeon_device *rdev); +int r100_cp_init(struct radeon_device *rdev, unsigned ring_size); +int r100_pci_gart_enable(struct radeon_device *rdev); +void r100_pci_gart_disable(struct radeon_device *rdev); +void r100_mc_setup(struct radeon_device *rdev); +void r100_mc_disable_clients(struct radeon_device *rdev); +int r100_gui_wait_for_idle(struct radeon_device *rdev); +int r100_cs_packet_parse(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt, + unsigned idx); +int r100_cs_packet_next_reloc(struct radeon_cs_parser *p, + struct radeon_cs_reloc **cs_reloc); +int r100_cs_parse_packet0(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt, + const unsigned *auth, unsigned n, + radeon_packet0_check_t check); +void r100_cs_dump_packet(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt); +int r100_cs_track_check_pkt3_indx_buffer(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt, + struct radeon_object *robj); + +/* This files gather functions specifics to: + * r300,r350,rv350,rv370,rv380 + * + * Some of these functions might be used by newer ASICs. + */ +void r300_gpu_init(struct radeon_device *rdev); +int r300_mc_wait_for_idle(struct radeon_device *rdev); +int rv370_debugfs_pcie_gart_info_init(struct radeon_device *rdev); + + +/* + * rv370,rv380 PCIE GART + */ +void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev) +{ + uint32_t tmp; + int i; + + /* Workaround HW bug do flush 2 times */ + for (i = 0; i < 2; i++) { + tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); + WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp | RADEON_PCIE_TX_GART_INVALIDATE_TLB); + (void)RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); + WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); + mb(); + } +} + +int rv370_pcie_gart_enable(struct radeon_device *rdev) +{ + uint32_t table_addr; + uint32_t tmp; + int r; + + /* Initialize common gart structure */ + r = radeon_gart_init(rdev); + if (r) { + return r; + } +// r = rv370_debugfs_pcie_gart_info_init(rdev); +// if (r) { +// DRM_ERROR("Failed to register debugfs file for PCIE gart !\n"); +// } + rdev->gart.table_size = rdev->gart.num_gpu_pages * 4; + r = radeon_gart_table_vram_alloc(rdev); + if (r) { + return r; + } + /* discard memory request outside of configured range */ + tmp = RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; + WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); + WREG32_PCIE(RADEON_PCIE_TX_GART_START_LO, rdev->mc.gtt_location); + tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 4096; + WREG32_PCIE(RADEON_PCIE_TX_GART_END_LO, tmp); + WREG32_PCIE(RADEON_PCIE_TX_GART_START_HI, 0); + WREG32_PCIE(RADEON_PCIE_TX_GART_END_HI, 0); + table_addr = rdev->gart.table_addr; + WREG32_PCIE(RADEON_PCIE_TX_GART_BASE, table_addr); + /* FIXME: setup default page */ + WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_LO, rdev->mc.vram_location); + WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_HI, 0); + /* Clear error */ + WREG32_PCIE(0x18, 0); + tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); + tmp |= RADEON_PCIE_TX_GART_EN; + tmp |= RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; + WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); + rv370_pcie_gart_tlb_flush(rdev); + DRM_INFO("PCIE GART of %uM enabled (table at 0x%08X).\n", + rdev->mc.gtt_size >> 20, table_addr); + rdev->gart.ready = true; + return 0; +} + +void rv370_pcie_gart_disable(struct radeon_device *rdev) +{ + uint32_t tmp; + + tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); + tmp |= RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; + WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp & ~RADEON_PCIE_TX_GART_EN); + if (rdev->gart.table.vram.robj) { +// radeon_object_kunmap(rdev->gart.table.vram.robj); +// radeon_object_unpin(rdev->gart.table.vram.robj); + } +} + +int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) +{ + void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; + + if (i < 0 || i > rdev->gart.num_gpu_pages) { + return -EINVAL; + } + addr = (((u32_t)addr) >> 8) | ((upper_32_bits(addr) & 0xff) << 4) | 0xC; + writel(cpu_to_le32(addr), ((void __iomem *)ptr) + (i * 4)); + return 0; +} + +int r300_gart_enable(struct radeon_device *rdev) +{ +#if __OS_HAS_AGP + if (rdev->flags & RADEON_IS_AGP) { + if (rdev->family > CHIP_RV350) { + rv370_pcie_gart_disable(rdev); + } else { + r100_pci_gart_disable(rdev); + } + return 0; + } +#endif + if (rdev->flags & RADEON_IS_PCIE) { + rdev->asic->gart_disable = &rv370_pcie_gart_disable; + rdev->asic->gart_tlb_flush = &rv370_pcie_gart_tlb_flush; + rdev->asic->gart_set_page = &rv370_pcie_gart_set_page; + return rv370_pcie_gart_enable(rdev); + } +// return r100_pci_gart_enable(rdev); +} + +#if 0 +/* + * MC + */ +int r300_mc_init(struct radeon_device *rdev) +{ + int r; + + if (r100_debugfs_rbbm_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for RBBM !\n"); + } + + r300_gpu_init(rdev); + r100_pci_gart_disable(rdev); + if (rdev->flags & RADEON_IS_PCIE) { + rv370_pcie_gart_disable(rdev); + } + + /* Setup GPU memory space */ + rdev->mc.vram_location = 0xFFFFFFFFUL; + rdev->mc.gtt_location = 0xFFFFFFFFUL; + if (rdev->flags & RADEON_IS_AGP) { + r = radeon_agp_init(rdev); + if (r) { + printk(KERN_WARNING "[drm] Disabling AGP\n"); + rdev->flags &= ~RADEON_IS_AGP; + rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; + } else { + rdev->mc.gtt_location = rdev->mc.agp_base; + } + } + r = radeon_mc_setup(rdev); + if (r) { + return r; + } + + /* Program GPU memory space */ + r100_mc_disable_clients(rdev); + if (r300_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait MC idle while " + "programming pipes. Bad things might happen.\n"); + } + r100_mc_setup(rdev); + return 0; +} + +void r300_mc_fini(struct radeon_device *rdev) +{ + if (rdev->flags & RADEON_IS_PCIE) { + rv370_pcie_gart_disable(rdev); + radeon_gart_table_vram_free(rdev); + } else { + r100_pci_gart_disable(rdev); + radeon_gart_table_ram_free(rdev); + } + radeon_gart_fini(rdev); +} + + +/* + * Fence emission + */ +void r300_fence_ring_emit(struct radeon_device *rdev, + struct radeon_fence *fence) +{ + /* Who ever call radeon_fence_emit should call ring_lock and ask + * for enough space (today caller are ib schedule and buffer move) */ + /* Write SC register so SC & US assert idle */ + radeon_ring_write(rdev, PACKET0(0x43E0, 0)); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, PACKET0(0x43E4, 0)); + radeon_ring_write(rdev, 0); + /* Flush 3D cache */ + radeon_ring_write(rdev, PACKET0(0x4E4C, 0)); + radeon_ring_write(rdev, (2 << 0)); + radeon_ring_write(rdev, PACKET0(0x4F18, 0)); + radeon_ring_write(rdev, (1 << 0)); + /* Wait until IDLE & CLEAN */ + radeon_ring_write(rdev, PACKET0(0x1720, 0)); + radeon_ring_write(rdev, (1 << 17) | (1 << 16) | (1 << 9)); + /* Emit fence sequence & fire IRQ */ + radeon_ring_write(rdev, PACKET0(rdev->fence_drv.scratch_reg, 0)); + radeon_ring_write(rdev, fence->seq); + radeon_ring_write(rdev, PACKET0(RADEON_GEN_INT_STATUS, 0)); + radeon_ring_write(rdev, RADEON_SW_INT_FIRE); +} + + +/* + * Global GPU functions + */ +int r300_copy_dma(struct radeon_device *rdev, + uint64_t src_offset, + uint64_t dst_offset, + unsigned num_pages, + struct radeon_fence *fence) +{ + uint32_t size; + uint32_t cur_size; + int i, num_loops; + int r = 0; + + /* radeon pitch is /64 */ + size = num_pages << PAGE_SHIFT; + num_loops = DIV_ROUND_UP(size, 0x1FFFFF); + r = radeon_ring_lock(rdev, num_loops * 4 + 64); + if (r) { + DRM_ERROR("radeon: moving bo (%d).\n", r); + return r; + } + /* Must wait for 2D idle & clean before DMA or hangs might happen */ + radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0 )); + radeon_ring_write(rdev, (1 << 16)); + for (i = 0; i < num_loops; i++) { + cur_size = size; + if (cur_size > 0x1FFFFF) { + cur_size = 0x1FFFFF; + } + size -= cur_size; + radeon_ring_write(rdev, PACKET0(0x720, 2)); + radeon_ring_write(rdev, src_offset); + radeon_ring_write(rdev, dst_offset); + radeon_ring_write(rdev, cur_size | (1 << 31) | (1 << 30)); + src_offset += cur_size; + dst_offset += cur_size; + } + radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0)); + radeon_ring_write(rdev, RADEON_WAIT_DMA_GUI_IDLE); + if (fence) { + r = radeon_fence_emit(rdev, fence); + } + radeon_ring_unlock_commit(rdev); + return r; +} + +void r300_ring_start(struct radeon_device *rdev) +{ + unsigned gb_tile_config; + int r; + + /* Sub pixel 1/12 so we can have 4K rendering according to doc */ + gb_tile_config = (R300_ENABLE_TILING | R300_TILE_SIZE_16); + switch(rdev->num_gb_pipes) { + case 2: + gb_tile_config |= R300_PIPE_COUNT_R300; + break; + case 3: + gb_tile_config |= R300_PIPE_COUNT_R420_3P; + break; + case 4: + gb_tile_config |= R300_PIPE_COUNT_R420; + break; + case 1: + default: + gb_tile_config |= R300_PIPE_COUNT_RV350; + break; + } + + r = radeon_ring_lock(rdev, 64); + if (r) { + return; + } + radeon_ring_write(rdev, PACKET0(RADEON_ISYNC_CNTL, 0)); + radeon_ring_write(rdev, + RADEON_ISYNC_ANY2D_IDLE3D | + RADEON_ISYNC_ANY3D_IDLE2D | + RADEON_ISYNC_WAIT_IDLEGUI | + RADEON_ISYNC_CPSCRATCH_IDLEGUI); + radeon_ring_write(rdev, PACKET0(R300_GB_TILE_CONFIG, 0)); + radeon_ring_write(rdev, gb_tile_config); + radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0)); + radeon_ring_write(rdev, + RADEON_WAIT_2D_IDLECLEAN | + RADEON_WAIT_3D_IDLECLEAN); + radeon_ring_write(rdev, PACKET0(0x170C, 0)); + radeon_ring_write(rdev, 1 << 31); + radeon_ring_write(rdev, PACKET0(R300_GB_SELECT, 0)); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, PACKET0(R300_GB_ENABLE, 0)); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); + radeon_ring_write(rdev, R300_RB3D_DC_FLUSH | R300_RB3D_DC_FREE); + radeon_ring_write(rdev, PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0)); + radeon_ring_write(rdev, R300_ZC_FLUSH | R300_ZC_FREE); + radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0)); + radeon_ring_write(rdev, + RADEON_WAIT_2D_IDLECLEAN | + RADEON_WAIT_3D_IDLECLEAN); + radeon_ring_write(rdev, PACKET0(R300_GB_AA_CONFIG, 0)); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); + radeon_ring_write(rdev, R300_RB3D_DC_FLUSH | R300_RB3D_DC_FREE); + radeon_ring_write(rdev, PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0)); + radeon_ring_write(rdev, R300_ZC_FLUSH | R300_ZC_FREE); + radeon_ring_write(rdev, PACKET0(R300_GB_MSPOS0, 0)); + radeon_ring_write(rdev, + ((6 << R300_MS_X0_SHIFT) | + (6 << R300_MS_Y0_SHIFT) | + (6 << R300_MS_X1_SHIFT) | + (6 << R300_MS_Y1_SHIFT) | + (6 << R300_MS_X2_SHIFT) | + (6 << R300_MS_Y2_SHIFT) | + (6 << R300_MSBD0_Y_SHIFT) | + (6 << R300_MSBD0_X_SHIFT))); + radeon_ring_write(rdev, PACKET0(R300_GB_MSPOS1, 0)); + radeon_ring_write(rdev, + ((6 << R300_MS_X3_SHIFT) | + (6 << R300_MS_Y3_SHIFT) | + (6 << R300_MS_X4_SHIFT) | + (6 << R300_MS_Y4_SHIFT) | + (6 << R300_MS_X5_SHIFT) | + (6 << R300_MS_Y5_SHIFT) | + (6 << R300_MSBD1_SHIFT))); + radeon_ring_write(rdev, PACKET0(R300_GA_ENHANCE, 0)); + radeon_ring_write(rdev, R300_GA_DEADLOCK_CNTL | R300_GA_FASTSYNC_CNTL); + radeon_ring_write(rdev, PACKET0(R300_GA_POLY_MODE, 0)); + radeon_ring_write(rdev, + R300_FRONT_PTYPE_TRIANGE | R300_BACK_PTYPE_TRIANGE); + radeon_ring_write(rdev, PACKET0(R300_GA_ROUND_MODE, 0)); + radeon_ring_write(rdev, + R300_GEOMETRY_ROUND_NEAREST | + R300_COLOR_ROUND_NEAREST); + radeon_ring_unlock_commit(rdev); +} + +void r300_errata(struct radeon_device *rdev) +{ + rdev->pll_errata = 0; + + if (rdev->family == CHIP_R300 && + (RREG32(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) == RADEON_CFG_ATI_REV_A11) { + rdev->pll_errata |= CHIP_ERRATA_R300_CG; + } +} + +int r300_mc_wait_for_idle(struct radeon_device *rdev) +{ + unsigned i; + uint32_t tmp; + + for (i = 0; i < rdev->usec_timeout; i++) { + /* read MC_STATUS */ + tmp = RREG32(0x0150); + if (tmp & (1 << 4)) { + return 0; + } + DRM_UDELAY(1); + } + return -1; +} + +void r300_gpu_init(struct radeon_device *rdev) +{ + uint32_t gb_tile_config, tmp; + + r100_hdp_reset(rdev); + /* FIXME: rv380 one pipes ? */ + if ((rdev->family == CHIP_R300) || (rdev->family == CHIP_R350)) { + /* r300,r350 */ + rdev->num_gb_pipes = 2; + } else { + /* rv350,rv370,rv380 */ + rdev->num_gb_pipes = 1; + } + gb_tile_config = (R300_ENABLE_TILING | R300_TILE_SIZE_16); + switch (rdev->num_gb_pipes) { + case 2: + gb_tile_config |= R300_PIPE_COUNT_R300; + break; + case 3: + gb_tile_config |= R300_PIPE_COUNT_R420_3P; + break; + case 4: + gb_tile_config |= R300_PIPE_COUNT_R420; + break; + default: + case 1: + gb_tile_config |= R300_PIPE_COUNT_RV350; + break; + } + WREG32(R300_GB_TILE_CONFIG, gb_tile_config); + + if (r100_gui_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait GUI idle while " + "programming pipes. Bad things might happen.\n"); + } + + tmp = RREG32(0x170C); + WREG32(0x170C, tmp | (1 << 31)); + + WREG32(R300_RB2D_DSTCACHE_MODE, + R300_DC_AUTOFLUSH_ENABLE | + R300_DC_DC_DISABLE_IGNORE_PE); + + if (r100_gui_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait GUI idle while " + "programming pipes. Bad things might happen.\n"); + } + if (r300_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait MC idle while " + "programming pipes. Bad things might happen.\n"); + } + DRM_INFO("radeon: %d pipes initialized.\n", rdev->num_gb_pipes); +} + +int r300_ga_reset(struct radeon_device *rdev) +{ + uint32_t tmp; + bool reinit_cp; + int i; + + reinit_cp = rdev->cp.ready; + rdev->cp.ready = false; + for (i = 0; i < rdev->usec_timeout; i++) { + WREG32(RADEON_CP_CSQ_MODE, 0); + WREG32(RADEON_CP_CSQ_CNTL, 0); + WREG32(RADEON_RBBM_SOFT_RESET, 0x32005); + (void)RREG32(RADEON_RBBM_SOFT_RESET); + udelay(200); + WREG32(RADEON_RBBM_SOFT_RESET, 0); + /* Wait to prevent race in RBBM_STATUS */ + mdelay(1); + tmp = RREG32(RADEON_RBBM_STATUS); + if (tmp & ((1 << 20) | (1 << 26))) { + DRM_ERROR("VAP & CP still busy (RBBM_STATUS=0x%08X)", tmp); + /* GA still busy soft reset it */ + WREG32(0x429C, 0x200); + WREG32(R300_VAP_PVS_STATE_FLUSH_REG, 0); + WREG32(0x43E0, 0); + WREG32(0x43E4, 0); + WREG32(0x24AC, 0); + } + /* Wait to prevent race in RBBM_STATUS */ + mdelay(1); + tmp = RREG32(RADEON_RBBM_STATUS); + if (!(tmp & ((1 << 20) | (1 << 26)))) { + break; + } + } + for (i = 0; i < rdev->usec_timeout; i++) { + tmp = RREG32(RADEON_RBBM_STATUS); + if (!(tmp & ((1 << 20) | (1 << 26)))) { + DRM_INFO("GA reset succeed (RBBM_STATUS=0x%08X)\n", + tmp); + if (reinit_cp) { + return r100_cp_init(rdev, rdev->cp.ring_size); + } + return 0; + } + DRM_UDELAY(1); + } + tmp = RREG32(RADEON_RBBM_STATUS); + DRM_ERROR("Failed to reset GA ! (RBBM_STATUS=0x%08X)\n", tmp); + return -1; +} + +int r300_gpu_reset(struct radeon_device *rdev) +{ + uint32_t status; + + /* reset order likely matter */ + status = RREG32(RADEON_RBBM_STATUS); + /* reset HDP */ + r100_hdp_reset(rdev); + /* reset rb2d */ + if (status & ((1 << 17) | (1 << 18) | (1 << 27))) { + r100_rb2d_reset(rdev); + } + /* reset GA */ + if (status & ((1 << 20) | (1 << 26))) { + r300_ga_reset(rdev); + } + /* reset CP */ + status = RREG32(RADEON_RBBM_STATUS); + if (status & (1 << 16)) { + r100_cp_reset(rdev); + } + /* Check if GPU is idle */ + status = RREG32(RADEON_RBBM_STATUS); + if (status & (1 << 31)) { + DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status); + return -1; + } + DRM_INFO("GPU reset succeed (RBBM_STATUS=0x%08X)\n", status); + return 0; +} + + +/* + * r300,r350,rv350,rv380 VRAM info + */ +void r300_vram_info(struct radeon_device *rdev) +{ + uint32_t tmp; + + /* DDR for all card after R300 & IGP */ + rdev->mc.vram_is_ddr = true; + tmp = RREG32(RADEON_MEM_CNTL); + if (tmp & R300_MEM_NUM_CHANNELS_MASK) { + rdev->mc.vram_width = 128; + } else { + rdev->mc.vram_width = 64; + } + rdev->mc.vram_size = RREG32(RADEON_CONFIG_MEMSIZE); + + rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); + rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); +} + + +/* + * Indirect registers accessor + */ +uint32_t rv370_pcie_rreg(struct radeon_device *rdev, uint32_t reg) +{ + uint32_t r; + + WREG8(RADEON_PCIE_INDEX, ((reg) & 0xff)); + (void)RREG32(RADEON_PCIE_INDEX); + r = RREG32(RADEON_PCIE_DATA); + return r; +} + +void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) +{ + WREG8(RADEON_PCIE_INDEX, ((reg) & 0xff)); + (void)RREG32(RADEON_PCIE_INDEX); + WREG32(RADEON_PCIE_DATA, (v)); + (void)RREG32(RADEON_PCIE_DATA); +} + +/* + * PCIE Lanes + */ + +void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes) +{ + uint32_t link_width_cntl, mask; + + if (rdev->flags & RADEON_IS_IGP) + return; + + if (!(rdev->flags & RADEON_IS_PCIE)) + return; + + /* FIXME wait for idle */ + + switch (lanes) { + case 0: + mask = RADEON_PCIE_LC_LINK_WIDTH_X0; + break; + case 1: + mask = RADEON_PCIE_LC_LINK_WIDTH_X1; + break; + case 2: + mask = RADEON_PCIE_LC_LINK_WIDTH_X2; + break; + case 4: + mask = RADEON_PCIE_LC_LINK_WIDTH_X4; + break; + case 8: + mask = RADEON_PCIE_LC_LINK_WIDTH_X8; + break; + case 12: + mask = RADEON_PCIE_LC_LINK_WIDTH_X12; + break; + case 16: + default: + mask = RADEON_PCIE_LC_LINK_WIDTH_X16; + break; + } + + link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL); + + if ((link_width_cntl & RADEON_PCIE_LC_LINK_WIDTH_RD_MASK) == + (mask << RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT)) + return; + + link_width_cntl &= ~(RADEON_PCIE_LC_LINK_WIDTH_MASK | + RADEON_PCIE_LC_RECONFIG_NOW | + RADEON_PCIE_LC_RECONFIG_LATER | + RADEON_PCIE_LC_SHORT_RECONFIG_EN); + link_width_cntl |= mask; + WREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + WREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL, (link_width_cntl | + RADEON_PCIE_LC_RECONFIG_NOW)); + + /* wait for lane set to complete */ + link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL); + while (link_width_cntl == 0xffffffff) + link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL); + +} + + +/* + * Debugfs info + */ +#if defined(CONFIG_DEBUG_FS) +static int rv370_debugfs_pcie_gart_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t tmp; + + tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); + seq_printf(m, "PCIE_TX_GART_CNTL 0x%08x\n", tmp); + tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_BASE); + seq_printf(m, "PCIE_TX_GART_BASE 0x%08x\n", tmp); + tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_START_LO); + seq_printf(m, "PCIE_TX_GART_START_LO 0x%08x\n", tmp); + tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_START_HI); + seq_printf(m, "PCIE_TX_GART_START_HI 0x%08x\n", tmp); + tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_END_LO); + seq_printf(m, "PCIE_TX_GART_END_LO 0x%08x\n", tmp); + tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_END_HI); + seq_printf(m, "PCIE_TX_GART_END_HI 0x%08x\n", tmp); + tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_ERROR); + seq_printf(m, "PCIE_TX_GART_ERROR 0x%08x\n", tmp); + return 0; +} + +static struct drm_info_list rv370_pcie_gart_info_list[] = { + {"rv370_pcie_gart_info", rv370_debugfs_pcie_gart_info, 0, NULL}, +}; +#endif + +int rv370_debugfs_pcie_gart_info_init(struct radeon_device *rdev) +{ +#if defined(CONFIG_DEBUG_FS) + return radeon_debugfs_add_files(rdev, rv370_pcie_gart_info_list, 1); +#else + return 0; +#endif +} + + +/* + * CS functions + */ +struct r300_cs_track_cb { + struct radeon_object *robj; + unsigned pitch; + unsigned cpp; + unsigned offset; +}; + +struct r300_cs_track_array { + struct radeon_object *robj; + unsigned esize; +}; + +struct r300_cs_track_texture { + struct radeon_object *robj; + unsigned pitch; + unsigned width; + unsigned height; + unsigned num_levels; + unsigned cpp; + unsigned tex_coord_type; + unsigned txdepth; + unsigned width_11; + unsigned height_11; + bool use_pitch; + bool enabled; + bool roundup_w; + bool roundup_h; +}; + +struct r300_cs_track { + unsigned num_cb; + unsigned maxy; + unsigned vtx_size; + unsigned vap_vf_cntl; + unsigned immd_dwords; + unsigned num_arrays; + unsigned max_indx; + struct r300_cs_track_array arrays[11]; + struct r300_cs_track_cb cb[4]; + struct r300_cs_track_cb zb; + struct r300_cs_track_texture textures[16]; + bool z_enabled; +}; + +static inline void r300_cs_track_texture_print(struct r300_cs_track_texture *t) +{ + DRM_ERROR("pitch %d\n", t->pitch); + DRM_ERROR("width %d\n", t->width); + DRM_ERROR("height %d\n", t->height); + DRM_ERROR("num levels %d\n", t->num_levels); + DRM_ERROR("depth %d\n", t->txdepth); + DRM_ERROR("bpp %d\n", t->cpp); + DRM_ERROR("coordinate type %d\n", t->tex_coord_type); + DRM_ERROR("width round to power of 2 %d\n", t->roundup_w); + DRM_ERROR("height round to power of 2 %d\n", t->roundup_h); +} + +static inline int r300_cs_track_texture_check(struct radeon_device *rdev, + struct r300_cs_track *track) +{ + struct radeon_object *robj; + unsigned long size; + unsigned u, i, w, h; + + for (u = 0; u < 16; u++) { + if (!track->textures[u].enabled) + continue; + robj = track->textures[u].robj; + if (robj == NULL) { + DRM_ERROR("No texture bound to unit %u\n", u); + return -EINVAL; + } + size = 0; + for (i = 0; i <= track->textures[u].num_levels; i++) { + if (track->textures[u].use_pitch) { + w = track->textures[u].pitch / (1 << i); + } else { + w = track->textures[u].width / (1 << i); + if (rdev->family >= CHIP_RV515) + w |= track->textures[u].width_11; + if (track->textures[u].roundup_w) + w = roundup_pow_of_two(w); + } + h = track->textures[u].height / (1 << i); + if (rdev->family >= CHIP_RV515) + h |= track->textures[u].height_11; + if (track->textures[u].roundup_h) + h = roundup_pow_of_two(h); + size += w * h; + } + size *= track->textures[u].cpp; + switch (track->textures[u].tex_coord_type) { + case 0: + break; + case 1: + size *= (1 << track->textures[u].txdepth); + break; + case 2: + size *= 6; + break; + default: + DRM_ERROR("Invalid texture coordinate type %u for unit " + "%u\n", track->textures[u].tex_coord_type, u); + return -EINVAL; + } + if (size > radeon_object_size(robj)) { + DRM_ERROR("Texture of unit %u needs %lu bytes but is " + "%lu\n", u, size, radeon_object_size(robj)); + r300_cs_track_texture_print(&track->textures[u]); + return -EINVAL; + } + } + return 0; +} + +int r300_cs_track_check(struct radeon_device *rdev, struct r300_cs_track *track) +{ + unsigned i; + unsigned long size; + unsigned prim_walk; + unsigned nverts; + + for (i = 0; i < track->num_cb; i++) { + if (track->cb[i].robj == NULL) { + DRM_ERROR("[drm] No buffer for color buffer %d !\n", i); + return -EINVAL; + } + size = track->cb[i].pitch * track->cb[i].cpp * track->maxy; + size += track->cb[i].offset; + if (size > radeon_object_size(track->cb[i].robj)) { + DRM_ERROR("[drm] Buffer too small for color buffer %d " + "(need %lu have %lu) !\n", i, size, + radeon_object_size(track->cb[i].robj)); + DRM_ERROR("[drm] color buffer %d (%u %u %u %u)\n", + i, track->cb[i].pitch, track->cb[i].cpp, + track->cb[i].offset, track->maxy); + return -EINVAL; + } + } + if (track->z_enabled) { + if (track->zb.robj == NULL) { + DRM_ERROR("[drm] No buffer for z buffer !\n"); + return -EINVAL; + } + size = track->zb.pitch * track->zb.cpp * track->maxy; + size += track->zb.offset; + if (size > radeon_object_size(track->zb.robj)) { + DRM_ERROR("[drm] Buffer too small for z buffer " + "(need %lu have %lu) !\n", size, + radeon_object_size(track->zb.robj)); + return -EINVAL; + } + } + prim_walk = (track->vap_vf_cntl >> 4) & 0x3; + nverts = (track->vap_vf_cntl >> 16) & 0xFFFF; + switch (prim_walk) { + case 1: + for (i = 0; i < track->num_arrays; i++) { + size = track->arrays[i].esize * track->max_indx * 4; + if (track->arrays[i].robj == NULL) { + DRM_ERROR("(PW %u) Vertex array %u no buffer " + "bound\n", prim_walk, i); + return -EINVAL; + } + if (size > radeon_object_size(track->arrays[i].robj)) { + DRM_ERROR("(PW %u) Vertex array %u need %lu dwords " + "have %lu dwords\n", prim_walk, i, + size >> 2, + radeon_object_size(track->arrays[i].robj) >> 2); + DRM_ERROR("Max indices %u\n", track->max_indx); + return -EINVAL; + } + } + break; + case 2: + for (i = 0; i < track->num_arrays; i++) { + size = track->arrays[i].esize * (nverts - 1) * 4; + if (track->arrays[i].robj == NULL) { + DRM_ERROR("(PW %u) Vertex array %u no buffer " + "bound\n", prim_walk, i); + return -EINVAL; + } + if (size > radeon_object_size(track->arrays[i].robj)) { + DRM_ERROR("(PW %u) Vertex array %u need %lu dwords " + "have %lu dwords\n", prim_walk, i, size >> 2, + radeon_object_size(track->arrays[i].robj) >> 2); + return -EINVAL; + } + } + break; + case 3: + size = track->vtx_size * nverts; + if (size != track->immd_dwords) { + DRM_ERROR("IMMD draw %u dwors but needs %lu dwords\n", + track->immd_dwords, size); + DRM_ERROR("VAP_VF_CNTL.NUM_VERTICES %u, VTX_SIZE %u\n", + nverts, track->vtx_size); + return -EINVAL; + } + break; + default: + DRM_ERROR("[drm] Invalid primitive walk %d for VAP_VF_CNTL\n", + prim_walk); + return -EINVAL; + } + return r300_cs_track_texture_check(rdev, track); +} + +static inline void r300_cs_track_clear(struct r300_cs_track *track) +{ + unsigned i; + + track->num_cb = 4; + track->maxy = 4096; + for (i = 0; i < track->num_cb; i++) { + track->cb[i].robj = NULL; + track->cb[i].pitch = 8192; + track->cb[i].cpp = 16; + track->cb[i].offset = 0; + } + track->z_enabled = true; + track->zb.robj = NULL; + track->zb.pitch = 8192; + track->zb.cpp = 4; + track->zb.offset = 0; + track->vtx_size = 0x7F; + track->immd_dwords = 0xFFFFFFFFUL; + track->num_arrays = 11; + track->max_indx = 0x00FFFFFFUL; + for (i = 0; i < track->num_arrays; i++) { + track->arrays[i].robj = NULL; + track->arrays[i].esize = 0x7F; + } + for (i = 0; i < 16; i++) { + track->textures[i].pitch = 16536; + track->textures[i].width = 16536; + track->textures[i].height = 16536; + track->textures[i].width_11 = 1 << 11; + track->textures[i].height_11 = 1 << 11; + track->textures[i].num_levels = 12; + track->textures[i].txdepth = 16; + track->textures[i].cpp = 64; + track->textures[i].tex_coord_type = 1; + track->textures[i].robj = NULL; + /* CS IB emission code makes sure texture unit are disabled */ + track->textures[i].enabled = false; + track->textures[i].roundup_w = true; + track->textures[i].roundup_h = true; + } +} + +static const unsigned r300_reg_safe_bm[159] = { + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFBF, 0xFFFFFFFF, 0xFFFFFFBF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x17FF1FFF, 0xFFFFFFFC, 0xFFFFFFFF, 0xFF30FFBF, + 0xFFFFFFF8, 0xC3E6FFFF, 0xFFFFF6DF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFF03F, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFEFCE, 0xF00EBFFF, 0x007C0000, + 0xF0000078, 0xFF000009, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFF7FF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFC78, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, + 0x38FF8F50, 0xFFF88082, 0xF000000C, 0xFAE009FF, + 0x0000FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0x0000C100, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0xFFFF0000, 0xFFFFFFFF, 0xFF80FFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0003FC01, 0xFFFFFFF8, 0xFE800B19, +}; + +static int r300_packet0_check(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt, + unsigned idx, unsigned reg) +{ + struct radeon_cs_chunk *ib_chunk; + struct radeon_cs_reloc *reloc; + struct r300_cs_track *track; + volatile uint32_t *ib; + uint32_t tmp; + unsigned i; + int r; + + ib = p->ib->ptr; + ib_chunk = &p->chunks[p->chunk_ib_idx]; + track = (struct r300_cs_track*)p->track; + switch(reg) { + case RADEON_DST_PITCH_OFFSET: + case RADEON_SRC_PITCH_OFFSET: + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for ib[%d]=0x%04X\n", + idx, reg); + r100_cs_dump_packet(p, pkt); + return r; + } + tmp = ib_chunk->kdata[idx] & 0x003fffff; + tmp += (((u32)reloc->lobj.gpu_offset) >> 10); + ib[idx] = (ib_chunk->kdata[idx] & 0xffc00000) | tmp; + break; + case R300_RB3D_COLOROFFSET0: + case R300_RB3D_COLOROFFSET1: + case R300_RB3D_COLOROFFSET2: + case R300_RB3D_COLOROFFSET3: + i = (reg - R300_RB3D_COLOROFFSET0) >> 2; + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for ib[%d]=0x%04X\n", + idx, reg); + r100_cs_dump_packet(p, pkt); + return r; + } + track->cb[i].robj = reloc->robj; + track->cb[i].offset = ib_chunk->kdata[idx]; + ib[idx] = ib_chunk->kdata[idx] + ((u32)reloc->lobj.gpu_offset); + break; + case R300_ZB_DEPTHOFFSET: + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for ib[%d]=0x%04X\n", + idx, reg); + r100_cs_dump_packet(p, pkt); + return r; + } + track->zb.robj = reloc->robj; + track->zb.offset = ib_chunk->kdata[idx]; + ib[idx] = ib_chunk->kdata[idx] + ((u32)reloc->lobj.gpu_offset); + break; + case R300_TX_OFFSET_0: + case R300_TX_OFFSET_0+4: + case R300_TX_OFFSET_0+8: + case R300_TX_OFFSET_0+12: + case R300_TX_OFFSET_0+16: + case R300_TX_OFFSET_0+20: + case R300_TX_OFFSET_0+24: + case R300_TX_OFFSET_0+28: + case R300_TX_OFFSET_0+32: + case R300_TX_OFFSET_0+36: + case R300_TX_OFFSET_0+40: + case R300_TX_OFFSET_0+44: + case R300_TX_OFFSET_0+48: + case R300_TX_OFFSET_0+52: + case R300_TX_OFFSET_0+56: + case R300_TX_OFFSET_0+60: + i = (reg - R300_TX_OFFSET_0) >> 2; + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for ib[%d]=0x%04X\n", + idx, reg); + r100_cs_dump_packet(p, pkt); + return r; + } + ib[idx] = ib_chunk->kdata[idx] + ((u32)reloc->lobj.gpu_offset); + track->textures[i].robj = reloc->robj; + break; + /* Tracked registers */ + case 0x2084: + /* VAP_VF_CNTL */ + track->vap_vf_cntl = ib_chunk->kdata[idx]; + break; + case 0x20B4: + /* VAP_VTX_SIZE */ + track->vtx_size = ib_chunk->kdata[idx] & 0x7F; + break; + case 0x2134: + /* VAP_VF_MAX_VTX_INDX */ + track->max_indx = ib_chunk->kdata[idx] & 0x00FFFFFFUL; + break; + case 0x43E4: + /* SC_SCISSOR1 */ + track->maxy = ((ib_chunk->kdata[idx] >> 13) & 0x1FFF) + 1; + if (p->rdev->family < CHIP_RV515) { + track->maxy -= 1440; + } + break; + case 0x4E00: + /* RB3D_CCTL */ + track->num_cb = ((ib_chunk->kdata[idx] >> 5) & 0x3) + 1; + break; + case 0x4E38: + case 0x4E3C: + case 0x4E40: + case 0x4E44: + /* RB3D_COLORPITCH0 */ + /* RB3D_COLORPITCH1 */ + /* RB3D_COLORPITCH2 */ + /* RB3D_COLORPITCH3 */ + i = (reg - 0x4E38) >> 2; + track->cb[i].pitch = ib_chunk->kdata[idx] & 0x3FFE; + switch (((ib_chunk->kdata[idx] >> 21) & 0xF)) { + case 9: + case 11: + case 12: + track->cb[i].cpp = 1; + break; + case 3: + case 4: + case 13: + case 15: + track->cb[i].cpp = 2; + break; + case 6: + track->cb[i].cpp = 4; + break; + case 10: + track->cb[i].cpp = 8; + break; + case 7: + track->cb[i].cpp = 16; + break; + default: + DRM_ERROR("Invalid color buffer format (%d) !\n", + ((ib_chunk->kdata[idx] >> 21) & 0xF)); + return -EINVAL; + } + break; + case 0x4F00: + /* ZB_CNTL */ + if (ib_chunk->kdata[idx] & 2) { + track->z_enabled = true; + } else { + track->z_enabled = false; + } + break; + case 0x4F10: + /* ZB_FORMAT */ + switch ((ib_chunk->kdata[idx] & 0xF)) { + case 0: + case 1: + track->zb.cpp = 2; + break; + case 2: + track->zb.cpp = 4; + break; + default: + DRM_ERROR("Invalid z buffer format (%d) !\n", + (ib_chunk->kdata[idx] & 0xF)); + return -EINVAL; + } + break; + case 0x4F24: + /* ZB_DEPTHPITCH */ + track->zb.pitch = ib_chunk->kdata[idx] & 0x3FFC; + break; + case 0x4104: + for (i = 0; i < 16; i++) { + bool enabled; + + enabled = !!(ib_chunk->kdata[idx] & (1 << i)); + track->textures[i].enabled = enabled; + } + break; + case 0x44C0: + case 0x44C4: + case 0x44C8: + case 0x44CC: + case 0x44D0: + case 0x44D4: + case 0x44D8: + case 0x44DC: + case 0x44E0: + case 0x44E4: + case 0x44E8: + case 0x44EC: + case 0x44F0: + case 0x44F4: + case 0x44F8: + case 0x44FC: + /* TX_FORMAT1_[0-15] */ + i = (reg - 0x44C0) >> 2; + tmp = (ib_chunk->kdata[idx] >> 25) & 0x3; + track->textures[i].tex_coord_type = tmp; + switch ((ib_chunk->kdata[idx] & 0x1F)) { + case 0: + case 2: + case 5: + case 18: + case 20: + case 21: + track->textures[i].cpp = 1; + break; + case 1: + case 3: + case 6: + case 7: + case 10: + case 11: + case 19: + case 22: + case 24: + track->textures[i].cpp = 2; + break; + case 4: + case 8: + case 9: + case 12: + case 13: + case 23: + case 25: + case 27: + case 30: + track->textures[i].cpp = 4; + break; + case 14: + case 26: + case 28: + track->textures[i].cpp = 8; + break; + case 29: + track->textures[i].cpp = 16; + break; + default: + DRM_ERROR("Invalid texture format %u\n", + (ib_chunk->kdata[idx] & 0x1F)); + return -EINVAL; + break; + } + break; + case 0x4400: + case 0x4404: + case 0x4408: + case 0x440C: + case 0x4410: + case 0x4414: + case 0x4418: + case 0x441C: + case 0x4420: + case 0x4424: + case 0x4428: + case 0x442C: + case 0x4430: + case 0x4434: + case 0x4438: + case 0x443C: + /* TX_FILTER0_[0-15] */ + i = (reg - 0x4400) >> 2; + tmp = ib_chunk->kdata[idx] & 0x7;; + if (tmp == 2 || tmp == 4 || tmp == 6) { + track->textures[i].roundup_w = false; + } + tmp = (ib_chunk->kdata[idx] >> 3) & 0x7;; + if (tmp == 2 || tmp == 4 || tmp == 6) { + track->textures[i].roundup_h = false; + } + break; + case 0x4500: + case 0x4504: + case 0x4508: + case 0x450C: + case 0x4510: + case 0x4514: + case 0x4518: + case 0x451C: + case 0x4520: + case 0x4524: + case 0x4528: + case 0x452C: + case 0x4530: + case 0x4534: + case 0x4538: + case 0x453C: + /* TX_FORMAT2_[0-15] */ + i = (reg - 0x4500) >> 2; + tmp = ib_chunk->kdata[idx] & 0x3FFF; + track->textures[i].pitch = tmp + 1; + if (p->rdev->family >= CHIP_RV515) { + tmp = ((ib_chunk->kdata[idx] >> 15) & 1) << 11; + track->textures[i].width_11 = tmp; + tmp = ((ib_chunk->kdata[idx] >> 16) & 1) << 11; + track->textures[i].height_11 = tmp; + } + break; + case 0x4480: + case 0x4484: + case 0x4488: + case 0x448C: + case 0x4490: + case 0x4494: + case 0x4498: + case 0x449C: + case 0x44A0: + case 0x44A4: + case 0x44A8: + case 0x44AC: + case 0x44B0: + case 0x44B4: + case 0x44B8: + case 0x44BC: + /* TX_FORMAT0_[0-15] */ + i = (reg - 0x4480) >> 2; + tmp = ib_chunk->kdata[idx] & 0x7FF; + track->textures[i].width = tmp + 1; + tmp = (ib_chunk->kdata[idx] >> 11) & 0x7FF; + track->textures[i].height = tmp + 1; + tmp = (ib_chunk->kdata[idx] >> 26) & 0xF; + track->textures[i].num_levels = tmp; + tmp = ib_chunk->kdata[idx] & (1 << 31); + track->textures[i].use_pitch = !!tmp; + tmp = (ib_chunk->kdata[idx] >> 22) & 0xF; + track->textures[i].txdepth = tmp; + break; + default: + printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n", + reg, idx); + return -EINVAL; + } + return 0; +} + +static int r300_packet3_check(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt) +{ + struct radeon_cs_chunk *ib_chunk; + struct radeon_cs_reloc *reloc; + struct r300_cs_track *track; + volatile uint32_t *ib; + unsigned idx; + unsigned i, c; + int r; + + ib = p->ib->ptr; + ib_chunk = &p->chunks[p->chunk_ib_idx]; + idx = pkt->idx + 1; + track = (struct r300_cs_track*)p->track; + switch(pkt->opcode) { + case PACKET3_3D_LOAD_VBPNTR: + c = ib_chunk->kdata[idx++] & 0x1F; + track->num_arrays = c; + for (i = 0; i < (c - 1); i+=2, idx+=3) { + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for packet3 %d\n", + pkt->opcode); + r100_cs_dump_packet(p, pkt); + return r; + } + ib[idx+1] = ib_chunk->kdata[idx+1] + ((u32)reloc->lobj.gpu_offset); + track->arrays[i + 0].robj = reloc->robj; + track->arrays[i + 0].esize = ib_chunk->kdata[idx] >> 8; + track->arrays[i + 0].esize &= 0x7F; + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for packet3 %d\n", + pkt->opcode); + r100_cs_dump_packet(p, pkt); + return r; + } + ib[idx+2] = ib_chunk->kdata[idx+2] + ((u32)reloc->lobj.gpu_offset); + track->arrays[i + 1].robj = reloc->robj; + track->arrays[i + 1].esize = ib_chunk->kdata[idx] >> 24; + track->arrays[i + 1].esize &= 0x7F; + } + if (c & 1) { + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for packet3 %d\n", + pkt->opcode); + r100_cs_dump_packet(p, pkt); + return r; + } + ib[idx+1] = ib_chunk->kdata[idx+1] + ((u32)reloc->lobj.gpu_offset); + track->arrays[i + 0].robj = reloc->robj; + track->arrays[i + 0].esize = ib_chunk->kdata[idx] >> 8; + track->arrays[i + 0].esize &= 0x7F; + } + break; + case PACKET3_INDX_BUFFER: + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for packet3 %d\n", pkt->opcode); + r100_cs_dump_packet(p, pkt); + return r; + } + ib[idx+1] = ib_chunk->kdata[idx+1] + ((u32)reloc->lobj.gpu_offset); + r = r100_cs_track_check_pkt3_indx_buffer(p, pkt, reloc->robj); + if (r) { + return r; + } + break; + /* Draw packet */ + case PACKET3_3D_DRAW_IMMD: + /* Number of dwords is vtx_size * (num_vertices - 1) + * PRIM_WALK must be equal to 3 vertex data in embedded + * in cmd stream */ + if (((ib_chunk->kdata[idx+1] >> 4) & 0x3) != 3) { + DRM_ERROR("PRIM_WALK must be 3 for IMMD draw\n"); + return -EINVAL; + } + track->vap_vf_cntl = ib_chunk->kdata[idx+1]; + track->immd_dwords = pkt->count - 1; + r = r300_cs_track_check(p->rdev, track); + if (r) { + return r; + } + break; + case PACKET3_3D_DRAW_IMMD_2: + /* Number of dwords is vtx_size * (num_vertices - 1) + * PRIM_WALK must be equal to 3 vertex data in embedded + * in cmd stream */ + if (((ib_chunk->kdata[idx] >> 4) & 0x3) != 3) { + DRM_ERROR("PRIM_WALK must be 3 for IMMD draw\n"); + return -EINVAL; + } + track->vap_vf_cntl = ib_chunk->kdata[idx]; + track->immd_dwords = pkt->count; + r = r300_cs_track_check(p->rdev, track); + if (r) { + return r; + } + break; + case PACKET3_3D_DRAW_VBUF: + track->vap_vf_cntl = ib_chunk->kdata[idx + 1]; + r = r300_cs_track_check(p->rdev, track); + if (r) { + return r; + } + break; + case PACKET3_3D_DRAW_VBUF_2: + track->vap_vf_cntl = ib_chunk->kdata[idx]; + r = r300_cs_track_check(p->rdev, track); + if (r) { + return r; + } + break; + case PACKET3_3D_DRAW_INDX: + track->vap_vf_cntl = ib_chunk->kdata[idx + 1]; + r = r300_cs_track_check(p->rdev, track); + if (r) { + return r; + } + break; + case PACKET3_3D_DRAW_INDX_2: + track->vap_vf_cntl = ib_chunk->kdata[idx]; + r = r300_cs_track_check(p->rdev, track); + if (r) { + return r; + } + break; + case PACKET3_NOP: + break; + default: + DRM_ERROR("Packet3 opcode %x not supported\n", pkt->opcode); + return -EINVAL; + } + return 0; +} + +int r300_cs_parse(struct radeon_cs_parser *p) +{ + struct radeon_cs_packet pkt; + struct r300_cs_track track; + int r; + + r300_cs_track_clear(&track); + p->track = &track; + do { + r = r100_cs_packet_parse(p, &pkt, p->idx); + if (r) { + return r; + } + p->idx += pkt.count + 2; + switch (pkt.type) { + case PACKET_TYPE0: + r = r100_cs_parse_packet0(p, &pkt, + p->rdev->config.r300.reg_safe_bm, + p->rdev->config.r300.reg_safe_bm_size, + &r300_packet0_check); + break; + case PACKET_TYPE2: + break; + case PACKET_TYPE3: + r = r300_packet3_check(p, &pkt); + break; + default: + DRM_ERROR("Unknown packet type %d !\n", pkt.type); + return -EINVAL; + } + if (r) { + return r; + } + } while (p->idx < p->chunks[p->chunk_ib_idx].length_dw); + return 0; +} + +int r300_init(struct radeon_device *rdev) +{ + rdev->config.r300.reg_safe_bm = r300_reg_safe_bm; + rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(r300_reg_safe_bm); + return 0; +} + + +#endif diff --git a/drivers/video/drm/radeon/r520.c b/drivers/video/drm/radeon/r520.c index 7cdac7ed94..463eadaa3c 100644 --- a/drivers/video/drm/radeon/r520.c +++ b/drivers/video/drm/radeon/r520.c @@ -155,7 +155,7 @@ int r520_mc_wait_for_idle(struct radeon_device *rdev) void r520_gpu_init(struct radeon_device *rdev) { unsigned pipe_select_current, gb_pipe_select, tmp; - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); r100_hdp_reset(rdev); rs600_disable_vga(rdev); @@ -204,7 +204,7 @@ void r520_gpu_init(struct radeon_device *rdev) static void r520_vram_get_type(struct radeon_device *rdev) { uint32_t tmp; - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); rdev->mc.vram_width = 128; rdev->mc.vram_is_ddr = true; @@ -245,7 +245,7 @@ void r520_vram_info(struct radeon_device *rdev) void rs600_disable_vga(struct radeon_device *rdev) { unsigned tmp; - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); WREG32(0x330, 0); WREG32(0x338, 0); @@ -264,7 +264,7 @@ void r420_pipes_init(struct radeon_device *rdev) unsigned gb_pipe_select; unsigned num_pipes; - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); /* GA_ENHANCE workaround TCL deadlock issue */ WREG32(0x4274, (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)); @@ -314,83 +314,11 @@ void r420_pipes_init(struct radeon_device *rdev) DRM_INFO("radeon: %d pipes initialized.\n", rdev->num_gb_pipes); } -void rv370_pcie_gart_disable(struct radeon_device *rdev) -{ - uint32_t tmp; - dbgprintf("%s\n\r",__FUNCTION__); - - tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); - tmp |= RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; - WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp & ~RADEON_PCIE_TX_GART_EN); - if (rdev->gart.table.vram.robj) { -// radeon_object_kunmap(rdev->gart.table.vram.robj); -// radeon_object_unpin(rdev->gart.table.vram.robj); - } -} - -void radeon_gart_table_vram_free(struct radeon_device *rdev) -{ - if (rdev->gart.table.vram.robj == NULL) { - return; - } -// radeon_object_kunmap(rdev->gart.table.vram.robj); -// radeon_object_unpin(rdev->gart.table.vram.robj); -// radeon_object_unref(&rdev->gart.table.vram.robj); -} - -/* - * Common gart functions. - */ -void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, - int pages) -{ - unsigned t; - unsigned p; - int i, j; - dbgprintf("%s\n\r",__FUNCTION__); - - if (!rdev->gart.ready) { - dbgprintf("trying to unbind memory to unitialized GART !\n"); - return; - } - t = offset / 4096; - p = t / (PAGE_SIZE / 4096); - for (i = 0; i < pages; i++, p++) { - if (rdev->gart.pages[p]) { -// pci_unmap_page(rdev->pdev, rdev->gart.pages_addr[p], -// PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); - rdev->gart.pages[p] = NULL; - rdev->gart.pages_addr[p] = 0; - for (j = 0; j < (PAGE_SIZE / 4096); j++, t++) { - radeon_gart_set_page(rdev, t, 0); - } - } - } - mb(); - radeon_gart_tlb_flush(rdev); -} - - - -void radeon_gart_fini(struct radeon_device *rdev) -{ - if (rdev->gart.pages && rdev->gart.pages_addr && rdev->gart.ready) { - /* unbind pages */ - radeon_gart_unbind(rdev, 0, rdev->gart.num_cpu_pages); - } - rdev->gart.ready = false; -// kfree(rdev->gart.pages); -// kfree(rdev->gart.pages_addr); - rdev->gart.pages = NULL; - rdev->gart.pages_addr = NULL; -} - - int radeon_agp_init(struct radeon_device *rdev) { - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); #if __OS_HAS_AGP struct radeon_agpmode_quirk *p = radeon_agpmode_quirk_list; @@ -535,182 +463,11 @@ void rs600_mc_disable_clients(struct radeon_device *rdev) } -int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) -{ - void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; - - if (i < 0 || i > rdev->gart.num_gpu_pages) { - return -EINVAL; - } - addr = (((u32_t)addr) >> 8) | ((upper_32_bits(addr) & 0xff) << 4) | 0xC; - writel(cpu_to_le32(addr), ((void __iomem *)ptr) + (i * 4)); - return 0; -} -int radeon_gart_init(struct radeon_device *rdev) -{ - - dbgprintf("%s\n",__FUNCTION__); - - if (rdev->gart.pages) { - return 0; - } - /* We need PAGE_SIZE >= 4096 */ - if (PAGE_SIZE < 4096) { - DRM_ERROR("Page size is smaller than GPU page size!\n"); - return -EINVAL; - } - /* Compute table size */ - rdev->gart.num_cpu_pages = rdev->mc.gtt_size / PAGE_SIZE; - rdev->gart.num_gpu_pages = rdev->mc.gtt_size / 4096; - DRM_INFO("GART: num cpu pages %u, num gpu pages %u\n", - rdev->gart.num_cpu_pages, rdev->gart.num_gpu_pages); - /* Allocate pages table */ - rdev->gart.pages = kzalloc(sizeof(void *) * rdev->gart.num_cpu_pages, - GFP_KERNEL); - if (rdev->gart.pages == NULL) { -// radeon_gart_fini(rdev); - return -ENOMEM; - } - rdev->gart.pages_addr = kzalloc(sizeof(u32_t) * - rdev->gart.num_cpu_pages, GFP_KERNEL); - if (rdev->gart.pages_addr == NULL) { -// radeon_gart_fini(rdev); - return -ENOMEM; - } - return 0; -} - -int radeon_gart_table_vram_alloc(struct radeon_device *rdev) -{ - uint32_t gpu_addr; - int r; - -// if (rdev->gart.table.vram.robj == NULL) { -// r = radeon_object_create(rdev, NULL, -// rdev->gart.table_size, -// true, -// RADEON_GEM_DOMAIN_VRAM, -// false, &rdev->gart.table.vram.robj); -// if (r) { -// return r; -// } -// } -// r = radeon_object_pin(rdev->gart.table.vram.robj, -// RADEON_GEM_DOMAIN_VRAM, &gpu_addr); -// if (r) { -// radeon_object_unref(&rdev->gart.table.vram.robj); -// return r; -// } -// r = radeon_object_kmap(rdev->gart.table.vram.robj, -// (void **)&rdev->gart.table.vram.ptr); -// if (r) { -// radeon_object_unpin(rdev->gart.table.vram.robj); -// radeon_object_unref(&rdev->gart.table.vram.robj); -// DRM_ERROR("radeon: failed to map gart vram table.\n"); -// return r; -// } - - gpu_addr = 0x800000; - - u32_t pci_addr = rdev->mc.aper_base + gpu_addr; - - rdev->gart.table.vram.ptr = (void*)MapIoMem(pci_addr, rdev->gart.table_size, PG_SW); - - rdev->gart.table_addr = gpu_addr; - - dbgprintf("alloc gart vram:\n gpu_base %x pci_base %x lin_addr %x", - gpu_addr, pci_addr, rdev->gart.table.vram.ptr); - - return 0; -} void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev); -int rv370_pcie_gart_enable(struct radeon_device *rdev) -{ - uint32_t table_addr; - uint32_t tmp; - int r; - - dbgprintf("%s\n",__FUNCTION__); - - /* Initialize common gart structure */ - r = radeon_gart_init(rdev); - if (r) { - return r; - } - // r = rv370_debugfs_pcie_gart_info_init(rdev); - // if (r) { - // DRM_ERROR("Failed to register debugfs file for PCIE gart !\n"); - // } - rdev->gart.table_size = rdev->gart.num_gpu_pages * 4; - r = radeon_gart_table_vram_alloc(rdev); - if (r) { - return r; - } - /* discard memory request outside of configured range */ - tmp = RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; - WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); - WREG32_PCIE(RADEON_PCIE_TX_GART_START_LO, rdev->mc.gtt_location); - tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 4096; - WREG32_PCIE(RADEON_PCIE_TX_GART_END_LO, tmp); - WREG32_PCIE(RADEON_PCIE_TX_GART_START_HI, 0); - WREG32_PCIE(RADEON_PCIE_TX_GART_END_HI, 0); - table_addr = rdev->gart.table_addr; - WREG32_PCIE(RADEON_PCIE_TX_GART_BASE, table_addr); - /* FIXME: setup default page */ - WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_LO, rdev->mc.vram_location); - WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_HI, 0); - /* Clear error */ - WREG32_PCIE(0x18, 0); - tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); - tmp |= RADEON_PCIE_TX_GART_EN; - tmp |= RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; - WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); - rv370_pcie_gart_tlb_flush(rdev); - DRM_INFO("PCIE GART of %uM enabled (table at 0x%08X).\n", - rdev->mc.gtt_size >> 20, table_addr); - rdev->gart.ready = true; - return 0; -} - -void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev) -{ - uint32_t tmp; - int i; - - /* Workaround HW bug do flush 2 times */ - for (i = 0; i < 2; i++) { - tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); - WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp | RADEON_PCIE_TX_GART_INVALIDATE_TLB); - (void)RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); - WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); - mb(); - } -} - -int r300_gart_enable(struct radeon_device *rdev) -{ -#if __OS_HAS_AGP - if (rdev->flags & RADEON_IS_AGP) { - if (rdev->family > CHIP_RV350) { - rv370_pcie_gart_disable(rdev); - } else { - r100_pci_gart_disable(rdev); - } - return 0; - } -#endif - if (rdev->flags & RADEON_IS_PCIE) { - rdev->asic->gart_disable = &rv370_pcie_gart_disable; - rdev->asic->gart_tlb_flush = &rv370_pcie_gart_tlb_flush; - rdev->asic->gart_set_page = &rv370_pcie_gart_set_page; - return rv370_pcie_gart_enable(rdev); - } - // return r100_pci_gart_enable(rdev); -} @@ -741,49 +498,7 @@ int radeon_fence_driver_init(struct radeon_device *rdev) } -int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, - int pages, u32_t *pagelist) -{ - unsigned t; - unsigned p; - uint64_t page_base; - int i, j; - - dbgprintf("%s\n\r",__FUNCTION__); - - - if (!rdev->gart.ready) { - DRM_ERROR("trying to bind memory to unitialized GART !\n"); - return -EINVAL; - } - t = offset / 4096; - p = t / (PAGE_SIZE / 4096); - - for (i = 0; i < pages; i++, p++) { - /* we need to support large memory configurations */ - /* assume that unbind have already been call on the range */ - - rdev->gart.pages_addr[p] = pagelist[i] & ~4095; - - //if (pci_dma_mapping_error(rdev->pdev, rdev->gart.pages_addr[p])) { - // /* FIXME: failed to map page (return -ENOMEM?) */ - // radeon_gart_unbind(rdev, offset, pages); - // return -ENOMEM; - //} - rdev->gart.pages[p] = pagelist[i]; - page_base = (uint32_t)rdev->gart.pages_addr[p]; - for (j = 0; j < (PAGE_SIZE / 4096); j++, t++) { - radeon_gart_set_page(rdev, t, page_base); - page_base += 4096; - } - } - mb(); - radeon_gart_tlb_flush(rdev); - - dbgprintf("done %s\n",__FUNCTION__); - - return 0; -} + diff --git a/drivers/video/drm/radeon/radeon.h b/drivers/video/drm/radeon/radeon.h index 228a129942..fb121dc44e 100644 --- a/drivers/video/drm/radeon/radeon.h +++ b/drivers/video/drm/radeon/radeon.h @@ -44,10 +44,12 @@ * - TESTING, TESTING, TESTING */ -#include "types.h" -#include "pci.h" +#include +#include -#include "errno-base.h" +#include + +#include #include "radeon_mode.h" #include "radeon_reg.h" @@ -60,15 +62,14 @@ extern int radeon_gart_size; extern int radeon_r4xx_atom; - /* * Copy from radeon_drv.h so we don't have to include both and have conflicting * symbol; */ -#define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */ -#define RADEON_IB_POOL_SIZE 16 +#define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */ +#define RADEON_IB_POOL_SIZE 16 #define RADEON_DEBUGFS_MAX_NUM_FILES 32 -#define RADEONFB_CONN_LIMIT 4 +#define RADEONFB_CONN_LIMIT 4 enum radeon_family { CHIP_R100, @@ -169,15 +170,15 @@ struct radeon_fence_driver { unsigned long count_timeout; // wait_queue_head_t queue; // rwlock_t lock; -// struct list_head created; -// struct list_head emited; -// struct list_head signaled; + struct list_head created; + struct list_head emited; + struct list_head signaled; }; struct radeon_fence { struct radeon_device *rdev; // struct kref kref; -// struct list_head list; + struct list_head list; /* protected by radeon_fence.lock */ uint32_t seq; unsigned long timeout; @@ -204,7 +205,7 @@ void radeon_fence_unref(struct radeon_fence **fence); struct radeon_object; struct radeon_object_list { -// struct list_head list; + struct list_head list; struct radeon_object *robj; uint64_t gpu_offset; unsigned rdomain; @@ -216,7 +217,6 @@ struct radeon_object_list { - /* * GART structures, functions & helpers */ @@ -255,8 +255,8 @@ int radeon_gart_init(struct radeon_device *rdev); void radeon_gart_fini(struct radeon_device *rdev); void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, int pages); -//int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, -// int pages, struct page **pagelist); +int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, + int pages, u32_t *pagelist); /* @@ -309,7 +309,7 @@ void radeon_irq_kms_fini(struct radeon_device *rdev); * CP & ring. */ struct radeon_ib { -// struct list_head list; + struct list_head list; unsigned long idx; uint64_t gpu_addr; struct radeon_fence *fence; @@ -320,10 +320,10 @@ struct radeon_ib { struct radeon_ib_pool { // struct mutex mutex; struct radeon_object *robj; -// struct list_head scheduled_ibs; + struct list_head scheduled_ibs; struct radeon_ib ibs[RADEON_IB_POOL_SIZE]; bool ready; -// DECLARE_BITMAP(alloc_bm, RADEON_IB_POOL_SIZE); + DECLARE_BITMAP(alloc_bm, RADEON_IB_POOL_SIZE); }; struct radeon_cp { @@ -364,7 +364,7 @@ void radeon_ring_fini(struct radeon_device *rdev); struct radeon_cs_reloc { // struct drm_gem_object *gobj; struct radeon_object *robj; -// struct radeon_object_list lobj; + struct radeon_object_list lobj; uint32_t handle; uint32_t flags; }; @@ -388,7 +388,7 @@ struct radeon_cs_parser { unsigned nrelocs; struct radeon_cs_reloc *relocs; struct radeon_cs_reloc **relocs_ptr; -// struct list_head validated; + struct list_head validated; /* indices of various chunks */ int chunk_ib_idx; int chunk_relocs_idx; @@ -512,24 +512,24 @@ struct radeon_device { unsigned long rmmio_size; void *rmmio; - radeon_rreg_t mm_rreg; - radeon_wreg_t mm_wreg; - radeon_rreg_t mc_rreg; - radeon_wreg_t mc_wreg; - radeon_rreg_t pll_rreg; - radeon_wreg_t pll_wreg; - radeon_rreg_t pcie_rreg; - radeon_wreg_t pcie_wreg; - radeon_rreg_t pciep_rreg; - radeon_wreg_t pciep_wreg; - struct radeon_clock clock; + radeon_rreg_t mm_rreg; + radeon_wreg_t mm_wreg; + radeon_rreg_t mc_rreg; + radeon_wreg_t mc_wreg; + radeon_rreg_t pll_rreg; + radeon_wreg_t pll_wreg; + radeon_rreg_t pcie_rreg; + radeon_wreg_t pcie_wreg; + radeon_rreg_t pciep_rreg; + radeon_wreg_t pciep_wreg; + struct radeon_clock clock; struct radeon_mc mc; struct radeon_gart gart; struct radeon_mode_info mode_info; struct radeon_scratch scratch; - // struct radeon_mman mman; +// struct radeon_mman mman; struct radeon_fence_driver fence_drv; - struct radeon_cp cp; + struct radeon_cp cp; struct radeon_ib_pool ib_pool; // struct radeon_irq irq; struct radeon_asic *asic; diff --git a/drivers/video/drm/radeon/radeon_asic.h b/drivers/video/drm/radeon/radeon_asic.h index 7133463722..dc8f096c4b 100644 --- a/drivers/video/drm/radeon/radeon_asic.h +++ b/drivers/video/drm/radeon/radeon_asic.h @@ -403,8 +403,8 @@ static struct radeon_asic r520_asic = { .gpu_reset = &rv515_gpu_reset, .mc_init = &r520_mc_init, .mc_fini = &r520_mc_fini, -// .wb_init = &r100_wb_init, -// .wb_fini = &r100_wb_fini, + .wb_init = &r100_wb_init, + .wb_fini = &r100_wb_fini, .gart_enable = &r300_gart_enable, .gart_disable = &rv370_pcie_gart_disable, .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, diff --git a/drivers/video/drm/radeon/radeon_atombios.c b/drivers/video/drm/radeon/radeon_atombios.c index e87c62e0ab..ea0bfa1a2d 100644 --- a/drivers/video/drm/radeon/radeon_atombios.c +++ b/drivers/video/drm/radeon/radeon_atombios.c @@ -944,7 +944,7 @@ void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev) struct radeon_device *rdev = dev->dev_private; uint32_t bios_2_scratch, bios_6_scratch; - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); if (rdev->family >= CHIP_R600) { bios_2_scratch = RREG32(R600_BIOS_0_SCRATCH); diff --git a/drivers/video/drm/radeon/radeon_bios.c b/drivers/video/drm/radeon/radeon_bios.c index 5e4802d384..9013ee81d3 100644 --- a/drivers/video/drm/radeon/radeon_bios.c +++ b/drivers/video/drm/radeon/radeon_bios.c @@ -39,7 +39,7 @@ static bool radeon_read_bios(struct radeon_device *rdev) size_t size; rdev->bios = NULL; - bios = pci_map_rom(rdev->pdev, &size); + bios = (uint8_t*)pci_map_rom(rdev->pdev, &size); if (!bios) { return false; } diff --git a/drivers/video/drm/radeon/radeon_device.c b/drivers/video/drm/radeon/radeon_device.c index d058aadac8..be61008e9c 100644 --- a/drivers/video/drm/radeon/radeon_device.c +++ b/drivers/video/drm/radeon/radeon_device.c @@ -46,7 +46,7 @@ int radeon_gart_size = 512; /* default gart size */ */ static void radeon_surface_init(struct radeon_device *rdev) { - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); /* FIXME: check this out */ if (rdev->family < CHIP_R600) { @@ -180,7 +180,7 @@ static bool radeon_card_posted(struct radeon_device *rdev) { uint32_t reg; - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); /* first check CRTCs */ if (ASIC_IS_AVIVO(rdev)) { @@ -231,7 +231,7 @@ void radeon_invalid_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) void radeon_register_accessor_init(struct radeon_device *rdev) { - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); rdev->mm_rreg = &r100_mm_rreg; rdev->mm_wreg = &r100_mm_wreg; @@ -288,7 +288,7 @@ void radeon_register_accessor_init(struct radeon_device *rdev) int radeon_asic_init(struct radeon_device *rdev) { - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); radeon_register_accessor_init(rdev); switch (rdev->family) { @@ -360,7 +360,7 @@ int radeon_clocks_init(struct radeon_device *rdev) { int r; - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); radeon_get_clock_info(rdev->ddev); r = radeon_static_clocks_init(rdev->ddev); @@ -436,7 +436,7 @@ static struct card_info atom_card_info = { int radeon_atombios_init(struct radeon_device *rdev) { - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); atom_card_info.dev = rdev->ddev; rdev->mode_info.atom_context = atom_parse(&atom_card_info, rdev->bios); @@ -462,7 +462,6 @@ void radeon_combios_fini(struct radeon_device *rdev) int radeon_modeset_init(struct radeon_device *rdev); void radeon_modeset_fini(struct radeon_device *rdev); -void *ring_buffer; /* * Radeon device. */ @@ -473,7 +472,7 @@ int radeon_device_init(struct radeon_device *rdev, { int r, ret = -1; - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); DRM_INFO("radeon: Initializing kernel modesetting.\n"); rdev->shutdown = false; @@ -492,7 +491,6 @@ int radeon_device_init(struct radeon_device *rdev, // mutex_init(&rdev->cp.mutex); // rwlock_init(&rdev->fence_drv.lock); - ring_buffer = CreateRingBuffer( 1024*1024, PG_SW ); if (radeon_agpmode == -1) { rdev->flags &= ~RADEON_IS_AGP; @@ -620,10 +618,10 @@ int radeon_device_init(struct radeon_device *rdev, // return r; // } /* Memory manager */ -// r = radeon_object_init(rdev); -// if (r) { -// return r; -// } + r = radeon_object_init(rdev); + if (r) { + return r; + } /* Initialize GART (initialize after TTM so we can allocate * memory through TTM but finalize after TTM) */ r = radeon_gart_enable(rdev); @@ -635,15 +633,14 @@ int radeon_device_init(struct radeon_device *rdev, if (!r) { r = radeon_cp_init(rdev, 1024 * 1024); } -// if (!r) { -// r = radeon_wb_init(rdev); -// if (r) { -// DRM_ERROR("radeon: failled initializing WB (%d).\n", r); -// return r; -// } -// } + if (!r) { + r = radeon_wb_init(rdev); + if (r) { + DRM_ERROR("radeon: failled initializing WB (%d).\n", r); + return r; + } + } -#if 0 if (!r) { r = radeon_ib_pool_init(rdev); if (r) { @@ -651,6 +648,8 @@ int radeon_device_init(struct radeon_device *rdev, return r; } } +#if 0 + if (!r) { r = radeon_ib_test(rdev); if (r) { @@ -694,9 +693,9 @@ u32_t __stdcall drvEntry(int action) if(action != 1) return 0; - if(!dbg_open("/rd/1/drivers/atikms.log")) + if(!dbg_open("/hd0/2/atikms.log")) { - printf("Can't open /rd/1/drivers/ati2d.log\nExit\n"); + printf("Can't open /hd0/2/atikms.log\nExit\n"); return 0; } @@ -793,9 +792,9 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) struct radeon_device *rdev; int r; - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); - rdev = malloc(sizeof(struct radeon_device)); + rdev = kzalloc(sizeof(struct radeon_device), GFP_KERNEL); if (rdev == NULL) { return -ENOMEM; }; @@ -825,7 +824,7 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent) struct drm_device *dev; int ret; - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); dev = malloc(sizeof(*dev)); if (!dev) diff --git a/drivers/video/drm/radeon/radeon_gart.c b/drivers/video/drm/radeon/radeon_gart.c new file mode 100644 index 0000000000..81a6107016 --- /dev/null +++ b/drivers/video/drm/radeon/radeon_gart.c @@ -0,0 +1,261 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +//#include "drmP.h" +#include "radeon_drm.h" +#include "radeon.h" +#include "radeon_reg.h" + +#if 0 +/* + * Common GART table functions. + */ +int radeon_gart_table_ram_alloc(struct radeon_device *rdev) +{ + void *ptr; + + ptr = pci_alloc_consistent(rdev->pdev, rdev->gart.table_size, + &rdev->gart.table_addr); + if (ptr == NULL) { + return -ENOMEM; + } +#ifdef CONFIG_X86 + if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 || + rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) { + set_memory_uc((unsigned long)ptr, + rdev->gart.table_size >> PAGE_SHIFT); + } +#endif + rdev->gart.table.ram.ptr = ptr; + memset((void *)rdev->gart.table.ram.ptr, 0, rdev->gart.table_size); + return 0; +} + +void radeon_gart_table_ram_free(struct radeon_device *rdev) +{ + if (rdev->gart.table.ram.ptr == NULL) { + return; + } +#ifdef CONFIG_X86 + if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 || + rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) { + set_memory_wb((unsigned long)rdev->gart.table.ram.ptr, + rdev->gart.table_size >> PAGE_SHIFT); + } +#endif + pci_free_consistent(rdev->pdev, rdev->gart.table_size, + (void *)rdev->gart.table.ram.ptr, + rdev->gart.table_addr); + rdev->gart.table.ram.ptr = NULL; + rdev->gart.table_addr = 0; +} +#endif + +int radeon_gart_table_vram_alloc(struct radeon_device *rdev) +{ + uint32_t gpu_addr; + int r; + + + if (rdev->gart.table.vram.robj == NULL) { + r = radeon_object_create(rdev, NULL, + rdev->gart.table_size, + true, + RADEON_GEM_DOMAIN_VRAM, + false, &rdev->gart.table.vram.robj); + if (r) { + return r; + } + } + r = radeon_object_pin(rdev->gart.table.vram.robj, + RADEON_GEM_DOMAIN_VRAM, &gpu_addr); + if (r) { +// radeon_object_unref(&rdev->gart.table.vram.robj); + return r; + } + r = radeon_object_kmap(rdev->gart.table.vram.robj, + (void **)&rdev->gart.table.vram.ptr); + if (r) { +// radeon_object_unpin(rdev->gart.table.vram.robj); +// radeon_object_unref(&rdev->gart.table.vram.robj); + DRM_ERROR("radeon: failed to map gart vram table.\n"); + return r; + } + + rdev->gart.table_addr = gpu_addr; + + dbgprintf("alloc gart vram: gpu_base %x lin_addr %x\n", + rdev->gart.table_addr, rdev->gart.table.vram.ptr); + +// gpu_addr = 0x800000; + +// u32_t pci_addr = rdev->mc.aper_base + gpu_addr; + +// rdev->gart.table.vram.ptr = (void*)MapIoMem(pci_addr, rdev->gart.table_size, PG_SW); + + +// dbgprintf("alloc gart vram:\n gpu_base %x pci_base %x lin_addr %x", +// gpu_addr, pci_addr, rdev->gart.table.vram.ptr); + + return 0; +} + +void radeon_gart_table_vram_free(struct radeon_device *rdev) +{ + if (rdev->gart.table.vram.robj == NULL) { + return; + } +// radeon_object_kunmap(rdev->gart.table.vram.robj); +// radeon_object_unpin(rdev->gart.table.vram.robj); +// radeon_object_unref(&rdev->gart.table.vram.robj); +} + + + + +/* + * Common gart functions. + */ +void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, + int pages) +{ + unsigned t; + unsigned p; + int i, j; + + if (!rdev->gart.ready) { +// WARN(1, "trying to unbind memory to unitialized GART !\n"); + return; + } + t = offset / 4096; + p = t / (PAGE_SIZE / 4096); + for (i = 0; i < pages; i++, p++) { + if (rdev->gart.pages[p]) { +// pci_unmap_page(rdev->pdev, rdev->gart.pages_addr[p], +// PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + rdev->gart.pages[p] = NULL; + rdev->gart.pages_addr[p] = 0; + for (j = 0; j < (PAGE_SIZE / 4096); j++, t++) { + radeon_gart_set_page(rdev, t, 0); + } + } + } + mb(); + radeon_gart_tlb_flush(rdev); +} + +int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, + int pages, u32_t *pagelist) +{ + unsigned t; + unsigned p; + uint64_t page_base; + int i, j; + + dbgprintf("%s ",__FUNCTION__); + dbgprintf("offset %x pages %x list %x\n", + offset, pages, pagelist); + + if (!rdev->gart.ready) { + DRM_ERROR("trying to bind memory to unitialized GART !\n"); + return -EINVAL; + } + t = offset / 4096; + p = t / (PAGE_SIZE / 4096); + + for (i = 0; i < pages; i++, p++) { + /* we need to support large memory configurations */ + /* assume that unbind have already been call on the range */ + + rdev->gart.pages_addr[p] = pagelist[i] & ~4095; + + //if (pci_dma_mapping_error(rdev->pdev, rdev->gart.pages_addr[p])) { + // /* FIXME: failed to map page (return -ENOMEM?) */ + // radeon_gart_unbind(rdev, offset, pages); + // return -ENOMEM; + //} + rdev->gart.pages[p] = pagelist[i]; + page_base = (uint32_t)rdev->gart.pages_addr[p]; + for (j = 0; j < (PAGE_SIZE / 4096); j++, t++) { + radeon_gart_set_page(rdev, t, page_base); + page_base += 4096; + } + } + mb(); + radeon_gart_tlb_flush(rdev); + + dbgprintf("done %s\n",__FUNCTION__); + + return 0; +} + +int radeon_gart_init(struct radeon_device *rdev) +{ + + dbgprintf("%s\n",__FUNCTION__); + + if (rdev->gart.pages) { + return 0; + } + /* We need PAGE_SIZE >= 4096 */ + if (PAGE_SIZE < 4096) { + DRM_ERROR("Page size is smaller than GPU page size!\n"); + return -EINVAL; + } + /* Compute table size */ + rdev->gart.num_cpu_pages = rdev->mc.gtt_size / PAGE_SIZE; + rdev->gart.num_gpu_pages = rdev->mc.gtt_size / 4096; + DRM_INFO("GART: num cpu pages %u, num gpu pages %u\n", + rdev->gart.num_cpu_pages, rdev->gart.num_gpu_pages); + /* Allocate pages table */ + rdev->gart.pages = kzalloc(sizeof(void *) * rdev->gart.num_cpu_pages, + GFP_KERNEL); + if (rdev->gart.pages == NULL) { +// radeon_gart_fini(rdev); + return -ENOMEM; + } + rdev->gart.pages_addr = kzalloc(sizeof(u32_t) * + rdev->gart.num_cpu_pages, GFP_KERNEL); + if (rdev->gart.pages_addr == NULL) { +// radeon_gart_fini(rdev); + return -ENOMEM; + } + return 0; +} + +void radeon_gart_fini(struct radeon_device *rdev) +{ + if (rdev->gart.pages && rdev->gart.pages_addr && rdev->gart.ready) { + /* unbind pages */ + radeon_gart_unbind(rdev, 0, rdev->gart.num_cpu_pages); + } + rdev->gart.ready = false; + kfree(rdev->gart.pages); + kfree(rdev->gart.pages_addr); + rdev->gart.pages = NULL; + rdev->gart.pages_addr = NULL; +} diff --git a/drivers/video/drm/radeon/radeon_object.c b/drivers/video/drm/radeon/radeon_object.c new file mode 100644 index 0000000000..ca6902801a --- /dev/null +++ b/drivers/video/drm/radeon/radeon_object.c @@ -0,0 +1,1084 @@ +/* + * Copyright 2009 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, 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. + * + */ +/* + * Authors: + * Jerome Glisse + * Thomas Hellstrom + * Dave Airlie + */ +//#include +//#include + +#include "radeon_drm.h" +#include "radeon.h" +#include + +int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, + int pages, u32_t *pagelist); + + +#define TTM_PL_SYSTEM 0 +#define TTM_PL_TT 1 +#define TTM_PL_VRAM 2 +#define TTM_PL_PRIV0 3 +#define TTM_PL_PRIV1 4 +#define TTM_PL_PRIV2 5 +#define TTM_PL_PRIV3 6 +#define TTM_PL_PRIV4 7 +#define TTM_PL_PRIV5 8 +#define TTM_PL_SWAPPED 15 + +#define TTM_PL_FLAG_SYSTEM (1 << TTM_PL_SYSTEM) +#define TTM_PL_FLAG_TT (1 << TTM_PL_TT) +#define TTM_PL_FLAG_VRAM (1 << TTM_PL_VRAM) +#define TTM_PL_FLAG_PRIV0 (1 << TTM_PL_PRIV0) +#define TTM_PL_FLAG_PRIV1 (1 << TTM_PL_PRIV1) +#define TTM_PL_FLAG_PRIV2 (1 << TTM_PL_PRIV2) +#define TTM_PL_FLAG_PRIV3 (1 << TTM_PL_PRIV3) +#define TTM_PL_FLAG_PRIV4 (1 << TTM_PL_PRIV4) +#define TTM_PL_FLAG_PRIV5 (1 << TTM_PL_PRIV5) +#define TTM_PL_FLAG_SWAPPED (1 << TTM_PL_SWAPPED) +#define TTM_PL_MASK_MEM 0x0000FFFF + + +struct ttm_mem_type_manager { + + /* + * No protection. Constant from start. + */ + + bool has_type; + bool use_type; + uint32_t flags; + unsigned long gpu_offset; + unsigned long io_offset; + unsigned long io_size; + void *io_addr; + uint64_t size; + uint32_t available_caching; + uint32_t default_caching; + + /* + * Protected by the bdev->lru_lock. + * TODO: Consider one lru_lock per ttm_mem_type_manager. + * Plays ill with list removal, though. + */ + + struct drm_mm manager; + struct list_head lru; +}; + +struct ttm_bo_driver { + const uint32_t *mem_type_prio; + const uint32_t *mem_busy_prio; + uint32_t num_mem_type_prio; + uint32_t num_mem_busy_prio; + + /** + * struct ttm_bo_driver member create_ttm_backend_entry + * + * @bdev: The buffer object device. + * + * Create a driver specific struct ttm_backend. + */ + +// struct ttm_backend *(*create_ttm_backend_entry)(struct ttm_bo_device *bdev); + + /** + * struct ttm_bo_driver member invalidate_caches + * + * @bdev: the buffer object device. + * @flags: new placement of the rebound buffer object. + * + * A previosly evicted buffer has been rebound in a + * potentially new location. Tell the driver that it might + * consider invalidating read (texture) caches on the next command + * submission as a consequence. + */ + +// int (*invalidate_caches) (struct ttm_bo_device *bdev, uint32_t flags); +// int (*init_mem_type) (struct ttm_bo_device *bdev, uint32_t type, +// struct ttm_mem_type_manager *man); + /** + * struct ttm_bo_driver member evict_flags: + * + * @bo: the buffer object to be evicted + * + * Return the bo flags for a buffer which is not mapped to the hardware. + * These will be placed in proposed_flags so that when the move is + * finished, they'll end up in bo->mem.flags + */ + +// uint32_t(*evict_flags) (struct ttm_buffer_object *bo); + /** + * struct ttm_bo_driver member move: + * + * @bo: the buffer to move + * @evict: whether this motion is evicting the buffer from + * the graphics address space + * @interruptible: Use interruptible sleeps if possible when sleeping. + * @no_wait: whether this should give up and return -EBUSY + * if this move would require sleeping + * @new_mem: the new memory region receiving the buffer + * + * Move a buffer between two memory regions. + */ +// int (*move) (struct ttm_buffer_object *bo, +// bool evict, bool interruptible, +// bool no_wait, struct ttm_mem_reg *new_mem); + + /** + * struct ttm_bo_driver_member verify_access + * + * @bo: Pointer to a buffer object. + * @filp: Pointer to a struct file trying to access the object. + * + * Called from the map / write / read methods to verify that the + * caller is permitted to access the buffer object. + * This member may be set to NULL, which will refuse this kind of + * access for all buffer objects. + * This function should return 0 if access is granted, -EPERM otherwise. + */ +// int (*verify_access) (struct ttm_buffer_object *bo, +// struct file *filp); + + /** + * In case a driver writer dislikes the TTM fence objects, + * the driver writer can replace those with sync objects of + * his / her own. If it turns out that no driver writer is + * using these. I suggest we remove these hooks and plug in + * fences directly. The bo driver needs the following functionality: + * See the corresponding functions in the fence object API + * documentation. + */ + +// bool (*sync_obj_signaled) (void *sync_obj, void *sync_arg); +// int (*sync_obj_wait) (void *sync_obj, void *sync_arg, +// bool lazy, bool interruptible); +// int (*sync_obj_flush) (void *sync_obj, void *sync_arg); +// void (*sync_obj_unref) (void **sync_obj); +// void *(*sync_obj_ref) (void *sync_obj); +}; + +#define TTM_NUM_MEM_TYPES 8 + + +struct ttm_bo_device { + + /* + * Constant after bo device init / atomic. + */ + +// struct ttm_mem_global *mem_glob; + struct ttm_bo_driver *driver; +// struct page *dummy_read_page; +// struct ttm_mem_shrink shrink; + + size_t ttm_bo_extra_size; + size_t ttm_bo_size; + +// rwlock_t vm_lock; + /* + * Protected by the vm lock. + */ + struct ttm_mem_type_manager man[TTM_NUM_MEM_TYPES]; +// struct rb_root addr_space_rb; + struct drm_mm addr_space_mm; + + /* + * Might want to change this to one lock per manager. + */ +// spinlock_t lru_lock; + /* + * Protected by the lru lock. + */ + struct list_head ddestroy; + struct list_head swap_lru; + + /* + * Protected by load / firstopen / lastclose /unload sync. + */ + + bool nice_mode; +// struct address_space *dev_mapping; + + /* + * Internal protection. + */ + +// struct delayed_work wq; +}; + +struct ttm_mem_reg { + struct drm_mm_node *mm_node; + unsigned long size; + unsigned long num_pages; + uint32_t page_alignment; + uint32_t mem_type; + uint32_t placement; +}; + +enum ttm_bo_type { + ttm_bo_type_device, + ttm_bo_type_user, + ttm_bo_type_kernel +}; + +struct ttm_buffer_object { + /** + * Members constant at init. + */ + + struct ttm_bo_device *bdev; + unsigned long buffer_start; + enum ttm_bo_type type; + void (*destroy) (struct ttm_buffer_object *); + unsigned long num_pages; + uint64_t addr_space_offset; + size_t acc_size; + + /** + * Members not needing protection. + */ + +// struct kref kref; +// struct kref list_kref; +// wait_queue_head_t event_queue; +// spinlock_t lock; + + /** + * Members protected by the bo::reserved lock. + */ + + uint32_t proposed_placement; + struct ttm_mem_reg mem; +// struct file *persistant_swap_storage; +// struct ttm_tt *ttm; + bool evicted; + + /** + * Members protected by the bo::reserved lock only when written to. + */ + +// atomic_t cpu_writers; + + /** + * Members protected by the bdev::lru_lock. + */ + + struct list_head lru; + struct list_head ddestroy; + struct list_head swap; + uint32_t val_seq; + bool seq_valid; + + /** + * Members protected by the bdev::lru_lock + * only when written to. + */ + +// atomic_t reserved; + + + /** + * Members protected by the bo::lock + */ + + void *sync_obj_arg; + void *sync_obj; + unsigned long priv_flags; + + /** + * Members protected by the bdev::vm_lock + */ + +// struct rb_node vm_rb; + struct drm_mm_node *vm_node; + + + /** + * Special members that are protected by the reserve lock + * and the bo::lock when written to. Can be read with + * either of these locks held. + */ + + unsigned long offset; + uint32_t cur_placement; +}; + +struct radeon_object +{ + struct ttm_buffer_object tobj; + struct list_head list; + struct radeon_device *rdev; +// struct drm_gem_object *gobj; +// struct ttm_bo_kmap_obj kmap; + + unsigned pin_count; + uint64_t gpu_addr; + void *kptr; + bool is_iomem; + + struct drm_mm_node *mm_node; + u32_t vm_addr; + u32_t cpu_addr; + u32_t flags; +}; + + + + +static struct drm_mm mm_gtt; +static struct drm_mm mm_vram; + + +int radeon_object_init(struct radeon_device *rdev) +{ + int r = 0; + + r = drm_mm_init(&mm_vram, 0x800000 >> PAGE_SHIFT, + ((rdev->mc.aper_size - 0x800000) >> PAGE_SHIFT)); + if (r) { + DRM_ERROR("Failed initializing VRAM heap.\n"); + return r; + }; + + r = drm_mm_init(&mm_gtt, 0, ((rdev->mc.gtt_size) >> PAGE_SHIFT)); + if (r) { + DRM_ERROR("Failed initializing GTT heap.\n"); + return r; + } + + return r; + // return radeon_ttm_init(rdev); +} + +static inline uint32_t radeon_object_flags_from_domain(uint32_t domain) +{ + uint32_t flags = 0; + if (domain & RADEON_GEM_DOMAIN_VRAM) { + flags |= TTM_PL_FLAG_VRAM; + } + if (domain & RADEON_GEM_DOMAIN_GTT) { + flags |= TTM_PL_FLAG_TT; + } + if (domain & RADEON_GEM_DOMAIN_CPU) { + flags |= TTM_PL_FLAG_SYSTEM; + } + if (!flags) { + flags |= TTM_PL_FLAG_SYSTEM; + } + return flags; +} + + +int radeon_object_create(struct radeon_device *rdev, + struct drm_gem_object *gobj, + unsigned long size, + bool kernel, + uint32_t domain, + bool interruptible, + struct radeon_object **robj_ptr) +{ + struct radeon_object *robj; + enum ttm_bo_type type; + uint32_t flags; + int r; + + dbgprintf("%s\n",__FUNCTION__); + + if (kernel) { + type = ttm_bo_type_kernel; + } else { + type = ttm_bo_type_device; + } + *robj_ptr = NULL; + robj = kzalloc(sizeof(struct radeon_object), GFP_KERNEL); + if (robj == NULL) { + return -ENOMEM; + } + robj->rdev = rdev; +// robj->gobj = gobj; + INIT_LIST_HEAD(&robj->list); + + flags = radeon_object_flags_from_domain(domain); + + robj->flags = flags; + + dbgprintf("robj flags %x\n", robj->flags); + + if( flags & TTM_PL_FLAG_VRAM) + { + size_t num_pages; + + struct drm_mm_node *vm_node; + + num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + + if (num_pages == 0) { + printk("Illegal buffer object size.\n"); + return -EINVAL; + } +retry_pre_get: + r = drm_mm_pre_get(&mm_vram); + + if (unlikely(r != 0)) + return r; + + vm_node = drm_mm_search_free(&mm_vram, num_pages, 0, 0); + + if (unlikely(vm_node == NULL)) { + r = -ENOMEM; + return r; + } + + robj->mm_node = drm_mm_get_block_atomic(vm_node, num_pages, 0); + + if (unlikely(robj->mm_node == NULL)) { + goto retry_pre_get; + } + + robj->vm_addr = ((uint32_t)robj->mm_node->start); + + dbgprintf("alloc vram: base %x size %x\n", + robj->vm_addr << PAGE_SHIFT, num_pages << PAGE_SHIFT); + + }; + + if( flags & TTM_PL_FLAG_TT) + { + size_t num_pages; + + struct drm_mm_node *vm_node; + + num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + + if (num_pages == 0) { + printk("Illegal buffer object size.\n"); + return -EINVAL; + } +retry_pre_get1: + r = drm_mm_pre_get(&mm_gtt); + + if (unlikely(r != 0)) + return r; + + vm_node = drm_mm_search_free(&mm_gtt, num_pages, 0, 0); + + if (unlikely(vm_node == NULL)) { + r = -ENOMEM; + return r; + } + + robj->mm_node = drm_mm_get_block_atomic(vm_node, num_pages, 0); + + if (unlikely(robj->mm_node == NULL)) { + goto retry_pre_get1; + } + + robj->vm_addr = ((uint32_t)robj->mm_node->start) ; + + dbgprintf("alloc gtt: base %x size %x\n", + robj->vm_addr << PAGE_SHIFT, num_pages << PAGE_SHIFT); + }; + +// r = ttm_buffer_object_init(&rdev->mman.bdev, &robj->tobj, size, type, flags, +// 0, 0, false, NULL, size, +// &radeon_ttm_object_object_destroy); + if (unlikely(r != 0)) { + /* ttm call radeon_ttm_object_object_destroy if error happen */ + DRM_ERROR("Failed to allocate TTM object (%ld, 0x%08X, %u)\n", + size, flags, 0); + return r; + } + *robj_ptr = robj; +// if (gobj) { +// list_add_tail(&robj->list, &rdev->gem.objects); +// } + return 0; +} + +#define page_tabs 0xFDC00000 + +int radeon_object_pin(struct radeon_object *robj, uint32_t domain, + uint64_t *gpu_addr) +{ + uint32_t flags; + uint32_t tmp; + int r = 0; + + dbgprintf("%s\n",__FUNCTION__); + +// flags = radeon_object_flags_from_domain(domain); +// spin_lock(&robj->tobj.lock); + if (robj->pin_count) { + robj->pin_count++; + if (gpu_addr != NULL) { + *gpu_addr = robj->gpu_addr; + } +// spin_unlock(&robj->tobj.lock); + return 0; + } +// spin_unlock(&robj->tobj.lock); +// r = radeon_object_reserve(robj, false); +// if (unlikely(r != 0)) { +// DRM_ERROR("radeon: failed to reserve object for pinning it.\n"); +// return r; +// } +// tmp = robj->tobj.mem.placement; +// ttm_flag_masked(&tmp, flags, TTM_PL_MASK_MEM); +// robj->tobj.proposed_placement = tmp | TTM_PL_FLAG_NO_EVICT | TTM_PL_MASK_CACHING; +// r = ttm_buffer_object_validate(&robj->tobj, +// robj->tobj.proposed_placement, +// false, false); + + robj->gpu_addr = ((u64)robj->vm_addr) << PAGE_SHIFT; + + if(robj->flags & TTM_PL_FLAG_VRAM) + robj->gpu_addr += (u64)robj->rdev->mc.vram_location; + else if (robj->flags & TTM_PL_FLAG_TT) + { + u32_t *pagelist; + robj->kptr = KernelAlloc( robj->mm_node->size << PAGE_SHIFT ); + dbgprintf("kernel alloc %x\n", robj->kptr ); + + pagelist = &((u32_t*)page_tabs)[(u32_t)robj->kptr >> 12]; + dbgprintf("pagelist %x\n", pagelist); + radeon_gart_bind(robj->rdev, robj->gpu_addr, + robj->mm_node->size, pagelist); + robj->gpu_addr += (u64)robj->rdev->mc.gtt_location; + } + else + { + DRM_ERROR("Unknown placement %d\n", robj->flags); + robj->gpu_addr = 0xFFFFFFFFFFFFFFFFULL; + r = -1; + }; + +// flags & TTM_PL_FLAG_VRAM + if (gpu_addr != NULL) { + *gpu_addr = robj->gpu_addr; + } + robj->pin_count = 1; + if (unlikely(r != 0)) { + DRM_ERROR("radeon: failed to pin object.\n"); + } + + dbgprintf("done %s\n",__FUNCTION__); + + return r; +} + +int radeon_object_kmap(struct radeon_object *robj, void **ptr) +{ + int r = 0; + + dbgprintf("%s\n",__FUNCTION__); + +// spin_lock(&robj->tobj.lock); + if (robj->kptr) { + if (ptr) { + *ptr = robj->kptr; + } +// spin_unlock(&robj->tobj.lock); + return 0; + } +// spin_unlock(&robj->tobj.lock); + + if(robj->flags & TTM_PL_FLAG_VRAM) + { + robj->cpu_addr = robj->rdev->mc.aper_base + + (robj->vm_addr << PAGE_SHIFT); + robj->kptr = (void*)MapIoMem(robj->cpu_addr, + robj->mm_node->size << 12, PG_SW); + dbgprintf("map io mem %x at %x\n", robj->cpu_addr, robj->kptr); + + } + else + { + return -1; + } + + if (ptr) { + *ptr = robj->kptr; + } + + dbgprintf("done %s\n",__FUNCTION__); + + return 0; +} + + +#if 0 + +void radeon_object_unpin(struct radeon_object *robj) +{ + uint32_t flags; + int r; + +// spin_lock(&robj->tobj.lock); + if (!robj->pin_count) { +// spin_unlock(&robj->tobj.lock); + printk(KERN_WARNING "Unpin not necessary for %p !\n", robj); + return; + } + robj->pin_count--; + if (robj->pin_count) { +// spin_unlock(&robj->tobj.lock); + return; + } +// spin_unlock(&robj->tobj.lock); + r = radeon_object_reserve(robj, false); + if (unlikely(r != 0)) { + DRM_ERROR("radeon: failed to reserve object for unpinning it.\n"); + return; + } + flags = robj->tobj.mem.placement; + robj->tobj.proposed_placement = flags & ~TTM_PL_FLAG_NO_EVICT; + r = ttm_buffer_object_validate(&robj->tobj, + robj->tobj.proposed_placement, + false, false); + if (unlikely(r != 0)) { + DRM_ERROR("radeon: failed to unpin buffer.\n"); + } + radeon_object_unreserve(robj); +} + + + + + +/* + * To exclude mutual BO access we rely on bo_reserve exclusion, as all + * function are calling it. + */ + +static int radeon_object_reserve(struct radeon_object *robj, bool interruptible) +{ + return ttm_bo_reserve(&robj->tobj, interruptible, false, false, 0); +} + +static void radeon_object_unreserve(struct radeon_object *robj) +{ + ttm_bo_unreserve(&robj->tobj); +} + +static void radeon_ttm_object_object_destroy(struct ttm_buffer_object *tobj) +{ + struct radeon_object *robj; + + robj = container_of(tobj, struct radeon_object, tobj); +// list_del_init(&robj->list); + kfree(robj); +} + +static inline void radeon_object_gpu_addr(struct radeon_object *robj) +{ + /* Default gpu address */ + robj->gpu_addr = 0xFFFFFFFFFFFFFFFFULL; + if (robj->tobj.mem.mm_node == NULL) { + return; + } + robj->gpu_addr = ((u64)robj->tobj.mem.mm_node->start) << PAGE_SHIFT; + switch (robj->tobj.mem.mem_type) { + case TTM_PL_VRAM: + robj->gpu_addr += (u64)robj->rdev->mc.vram_location; + break; + case TTM_PL_TT: + robj->gpu_addr += (u64)robj->rdev->mc.gtt_location; + break; + default: + DRM_ERROR("Unknown placement %d\n", robj->tobj.mem.mem_type); + robj->gpu_addr = 0xFFFFFFFFFFFFFFFFULL; + return; + } +} + + +int radeon_object_create(struct radeon_device *rdev, + struct drm_gem_object *gobj, + unsigned long size, + bool kernel, + uint32_t domain, + bool interruptible, + struct radeon_object **robj_ptr) +{ + struct radeon_object *robj; + enum ttm_bo_type type; + uint32_t flags; + int r; + +// if (unlikely(rdev->mman.bdev.dev_mapping == NULL)) { +// rdev->mman.bdev.dev_mapping = rdev->ddev->dev_mapping; +// } + if (kernel) { + type = ttm_bo_type_kernel; + } else { + type = ttm_bo_type_device; + } + *robj_ptr = NULL; + robj = kzalloc(sizeof(struct radeon_object), GFP_KERNEL); + if (robj == NULL) { + return -ENOMEM; + } + robj->rdev = rdev; + robj->gobj = gobj; +// INIT_LIST_HEAD(&robj->list); + + flags = radeon_object_flags_from_domain(domain); +// r = ttm_buffer_object_init(&rdev->mman.bdev, &robj->tobj, size, type, flags, +// 0, 0, false, NULL, size, +// &radeon_ttm_object_object_destroy); + if (unlikely(r != 0)) { + /* ttm call radeon_ttm_object_object_destroy if error happen */ + DRM_ERROR("Failed to allocate TTM object (%ld, 0x%08X, %u)\n", + size, flags, 0); + return r; + } + *robj_ptr = robj; +// if (gobj) { +// list_add_tail(&robj->list, &rdev->gem.objects); +// } + return 0; +} + +int radeon_object_kmap(struct radeon_object *robj, void **ptr) +{ + int r; + +// spin_lock(&robj->tobj.lock); + if (robj->kptr) { + if (ptr) { + *ptr = robj->kptr; + } +// spin_unlock(&robj->tobj.lock); + return 0; + } +// spin_unlock(&robj->tobj.lock); + r = ttm_bo_kmap(&robj->tobj, 0, robj->tobj.num_pages, &robj->kmap); + if (r) { + return r; + } +// spin_lock(&robj->tobj.lock); + robj->kptr = ttm_kmap_obj_virtual(&robj->kmap, &robj->is_iomem); +// spin_unlock(&robj->tobj.lock); + if (ptr) { + *ptr = robj->kptr; + } + return 0; +} + +void radeon_object_kunmap(struct radeon_object *robj) +{ +// spin_lock(&robj->tobj.lock); + if (robj->kptr == NULL) { +// spin_unlock(&robj->tobj.lock); + return; + } + robj->kptr = NULL; +// spin_unlock(&robj->tobj.lock); + ttm_bo_kunmap(&robj->kmap); +} + +void radeon_object_unref(struct radeon_object **robj) +{ + struct ttm_buffer_object *tobj; + + if ((*robj) == NULL) { + return; + } + tobj = &((*robj)->tobj); + ttm_bo_unref(&tobj); + if (tobj == NULL) { + *robj = NULL; + } +} + +int radeon_object_mmap(struct radeon_object *robj, uint64_t *offset) +{ + *offset = robj->tobj.addr_space_offset; + return 0; +} + +int radeon_object_pin(struct radeon_object *robj, uint32_t domain, + uint64_t *gpu_addr) +{ + uint32_t flags; + uint32_t tmp; + int r; + + flags = radeon_object_flags_from_domain(domain); +// spin_lock(&robj->tobj.lock); + if (robj->pin_count) { + robj->pin_count++; + if (gpu_addr != NULL) { + *gpu_addr = robj->gpu_addr; + } +// spin_unlock(&robj->tobj.lock); + return 0; + } +// spin_unlock(&robj->tobj.lock); + r = radeon_object_reserve(robj, false); + if (unlikely(r != 0)) { + DRM_ERROR("radeon: failed to reserve object for pinning it.\n"); + return r; + } + tmp = robj->tobj.mem.placement; + ttm_flag_masked(&tmp, flags, TTM_PL_MASK_MEM); + robj->tobj.proposed_placement = tmp | TTM_PL_FLAG_NO_EVICT | TTM_PL_MASK_CACHING; + r = ttm_buffer_object_validate(&robj->tobj, + robj->tobj.proposed_placement, + false, false); + radeon_object_gpu_addr(robj); + if (gpu_addr != NULL) { + *gpu_addr = robj->gpu_addr; + } + robj->pin_count = 1; + if (unlikely(r != 0)) { + DRM_ERROR("radeon: failed to pin object.\n"); + } + radeon_object_unreserve(robj); + return r; +} + +void radeon_object_unpin(struct radeon_object *robj) +{ + uint32_t flags; + int r; + +// spin_lock(&robj->tobj.lock); + if (!robj->pin_count) { +// spin_unlock(&robj->tobj.lock); + printk(KERN_WARNING "Unpin not necessary for %p !\n", robj); + return; + } + robj->pin_count--; + if (robj->pin_count) { +// spin_unlock(&robj->tobj.lock); + return; + } +// spin_unlock(&robj->tobj.lock); + r = radeon_object_reserve(robj, false); + if (unlikely(r != 0)) { + DRM_ERROR("radeon: failed to reserve object for unpinning it.\n"); + return; + } + flags = robj->tobj.mem.placement; + robj->tobj.proposed_placement = flags & ~TTM_PL_FLAG_NO_EVICT; + r = ttm_buffer_object_validate(&robj->tobj, + robj->tobj.proposed_placement, + false, false); + if (unlikely(r != 0)) { + DRM_ERROR("radeon: failed to unpin buffer.\n"); + } + radeon_object_unreserve(robj); +} + +int radeon_object_wait(struct radeon_object *robj) +{ + int r = 0; + + /* FIXME: should use block reservation instead */ + r = radeon_object_reserve(robj, true); + if (unlikely(r != 0)) { + DRM_ERROR("radeon: failed to reserve object for waiting.\n"); + return r; + } +// spin_lock(&robj->tobj.lock); + if (robj->tobj.sync_obj) { + r = ttm_bo_wait(&robj->tobj, true, false, false); + } +// spin_unlock(&robj->tobj.lock); + radeon_object_unreserve(robj); + return r; +} + +int radeon_object_evict_vram(struct radeon_device *rdev) +{ + if (rdev->flags & RADEON_IS_IGP) { + /* Useless to evict on IGP chips */ + return 0; + } + return ttm_bo_evict_mm(&rdev->mman.bdev, TTM_PL_VRAM); +} + +void radeon_object_force_delete(struct radeon_device *rdev) +{ + struct radeon_object *robj, *n; + struct drm_gem_object *gobj; + + if (list_empty(&rdev->gem.objects)) { + return; + } + DRM_ERROR("Userspace still has active objects !\n"); + list_for_each_entry_safe(robj, n, &rdev->gem.objects, list) { + mutex_lock(&rdev->ddev->struct_mutex); + gobj = robj->gobj; + DRM_ERROR("Force free for (%p,%p,%lu,%lu)\n", + gobj, robj, (unsigned long)gobj->size, + *((unsigned long *)&gobj->refcount)); + list_del_init(&robj->list); + radeon_object_unref(&robj); + gobj->driver_private = NULL; + drm_gem_object_unreference(gobj); + mutex_unlock(&rdev->ddev->struct_mutex); + } +} + +void radeon_object_fini(struct radeon_device *rdev) +{ + radeon_ttm_fini(rdev); +} + +void radeon_object_list_add_object(struct radeon_object_list *lobj, + struct list_head *head) +{ + if (lobj->wdomain) { + list_add(&lobj->list, head); + } else { + list_add_tail(&lobj->list, head); + } +} + +int radeon_object_list_reserve(struct list_head *head) +{ + struct radeon_object_list *lobj; + struct list_head *i; + int r; + + list_for_each(i, head) { + lobj = list_entry(i, struct radeon_object_list, list); + if (!lobj->robj->pin_count) { + r = radeon_object_reserve(lobj->robj, true); + if (unlikely(r != 0)) { + DRM_ERROR("radeon: failed to reserve object.\n"); + return r; + } + } else { + } + } + return 0; +} + +void radeon_object_list_unreserve(struct list_head *head) +{ + struct radeon_object_list *lobj; + struct list_head *i; + + list_for_each(i, head) { + lobj = list_entry(i, struct radeon_object_list, list); + if (!lobj->robj->pin_count) { + radeon_object_unreserve(lobj->robj); + } else { + } + } +} + +int radeon_object_list_validate(struct list_head *head, void *fence) +{ + struct radeon_object_list *lobj; + struct radeon_object *robj; + struct radeon_fence *old_fence = NULL; + struct list_head *i; + uint32_t flags; + int r; + + r = radeon_object_list_reserve(head); + if (unlikely(r != 0)) { + radeon_object_list_unreserve(head); + return r; + } + list_for_each(i, head) { + lobj = list_entry(i, struct radeon_object_list, list); + robj = lobj->robj; + if (lobj->wdomain) { + flags = radeon_object_flags_from_domain(lobj->wdomain); + flags |= TTM_PL_FLAG_TT; + } else { + flags = radeon_object_flags_from_domain(lobj->rdomain); + flags |= TTM_PL_FLAG_TT; + flags |= TTM_PL_FLAG_VRAM; + } + if (!robj->pin_count) { + robj->tobj.proposed_placement = flags | TTM_PL_MASK_CACHING; + r = ttm_buffer_object_validate(&robj->tobj, + robj->tobj.proposed_placement, + true, false); + if (unlikely(r)) { + radeon_object_list_unreserve(head); + DRM_ERROR("radeon: failed to validate.\n"); + return r; + } + radeon_object_gpu_addr(robj); + } + lobj->gpu_offset = robj->gpu_addr; + if (fence) { + old_fence = (struct radeon_fence *)robj->tobj.sync_obj; + robj->tobj.sync_obj = radeon_fence_ref(fence); + robj->tobj.sync_obj_arg = NULL; + } + if (old_fence) { + radeon_fence_unref(&old_fence); + } + } + return 0; +} + +void radeon_object_list_unvalidate(struct list_head *head) +{ + struct radeon_object_list *lobj; + struct radeon_fence *old_fence = NULL; + struct list_head *i; + + list_for_each(i, head) { + lobj = list_entry(i, struct radeon_object_list, list); + old_fence = (struct radeon_fence *)lobj->robj->tobj.sync_obj; + lobj->robj->tobj.sync_obj = NULL; + if (old_fence) { + radeon_fence_unref(&old_fence); + } + } + radeon_object_list_unreserve(head); +} + +void radeon_object_list_clean(struct list_head *head) +{ + radeon_object_list_unreserve(head); +} + +int radeon_object_fbdev_mmap(struct radeon_object *robj, + struct vm_area_struct *vma) +{ + return ttm_fbdev_mmap(vma, &robj->tobj); +} + +unsigned long radeon_object_size(struct radeon_object *robj) +{ + return robj->tobj.num_pages << PAGE_SHIFT; +} + + +#endif diff --git a/drivers/video/drm/radeon/radeon_ring.c b/drivers/video/drm/radeon/radeon_ring.c index 5335bc9f62..1597c2429d 100644 --- a/drivers/video/drm/radeon/radeon_ring.c +++ b/drivers/video/drm/radeon/radeon_ring.c @@ -32,14 +32,15 @@ #include "radeon.h" #include "atom.h" -extern void * ring_buffer; -#if 0 int radeon_debugfs_ib_init(struct radeon_device *rdev); /* * IB. */ + +#if 0 + int radeon_ib_get(struct radeon_device *rdev, struct radeon_ib **ib) { struct radeon_fence *fence; @@ -98,6 +99,7 @@ out: return r; } + void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib) { struct radeon_ib *tmp = *ib; @@ -170,6 +172,7 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib) mutex_unlock(&rdev->ib_pool.mutex); return 0; } +#endif int radeon_ib_pool_init(struct radeon_device *rdev) { @@ -210,9 +213,9 @@ int radeon_ib_pool_init(struct radeon_device *rdev) bitmap_zero(rdev->ib_pool.alloc_bm, RADEON_IB_POOL_SIZE); rdev->ib_pool.ready = true; DRM_INFO("radeon: ib pool ready.\n"); - if (radeon_debugfs_ib_init(rdev)) { - DRM_ERROR("Failed to register debugfs file for IB !\n"); - } +// if (radeon_debugfs_ib_init(rdev)) { +// DRM_ERROR("Failed to register debugfs file for IB !\n"); +// } return r; } @@ -221,16 +224,18 @@ void radeon_ib_pool_fini(struct radeon_device *rdev) if (!rdev->ib_pool.ready) { return; } - mutex_lock(&rdev->ib_pool.mutex); +// mutex_lock(&rdev->ib_pool.mutex); bitmap_zero(rdev->ib_pool.alloc_bm, RADEON_IB_POOL_SIZE); if (rdev->ib_pool.robj) { - radeon_object_kunmap(rdev->ib_pool.robj); - radeon_object_unref(&rdev->ib_pool.robj); +// radeon_object_kunmap(rdev->ib_pool.robj); +// radeon_object_unref(&rdev->ib_pool.robj); rdev->ib_pool.robj = NULL; } - mutex_unlock(&rdev->ib_pool.mutex); +// mutex_unlock(&rdev->ib_pool.mutex); } +#if 0 + int radeon_ib_test(struct radeon_device *rdev) { struct radeon_ib *ib; @@ -402,7 +407,6 @@ int radeon_ring_test(struct radeon_device *rdev) int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, int pages, u32_t *pagelist); -#define page_tabs 0xFDC00000 int radeon_ring_init(struct radeon_device *rdev, unsigned ring_size) @@ -413,8 +417,7 @@ int radeon_ring_init(struct radeon_device *rdev, unsigned ring_size) rdev->cp.ring_size = ring_size; -#if 0 - /* Allocate ring buffer */ + /* Allocate ring buffer */ if (rdev->cp.ring_obj == NULL) { r = radeon_object_create(rdev, NULL, rdev->cp.ring_size, true, @@ -442,23 +445,19 @@ int radeon_ring_init(struct radeon_device *rdev, unsigned ring_size) return r; } } -#endif - dbgprintf("ring size %x\n", ring_size); + +// rdev->cp.ring = CreateRingBuffer( ring_size, PG_SW ); dbgprintf("ring buffer %x\n", rdev->cp.ring ); - rdev->cp.ring = ring_buffer; //CreateRingBuffer( ring_size, PG_SW ); +// rdev->cp.gpu_addr = rdev->mc.gtt_location; - dbgprintf("ring buffer %x\n", rdev->cp.ring ); + // u32_t *pagelist = &((u32_t*)page_tabs)[(u32_t)rdev->cp.ring >> 12]; - rdev->cp.gpu_addr = rdev->mc.gtt_location; + // dbgprintf("pagelist %x\n", pagelist); - u32_t *pagelist = &((u32_t*)page_tabs)[(u32_t)rdev->cp.ring >> 12]; - - dbgprintf("pagelist %x\n", pagelist); - - radeon_gart_bind(rdev, 0, ring_size / 4096, pagelist); + // radeon_gart_bind(rdev, 0, ring_size / 4096, pagelist); rdev->cp.ptr_mask = (rdev->cp.ring_size / 4) - 1; rdev->cp.ring_free_dw = rdev->cp.ring_size / 4; diff --git a/drivers/video/drm/radeon/rv515.c b/drivers/video/drm/radeon/rv515.c index 3f9f39cb70..61892102dc 100644 --- a/drivers/video/drm/radeon/rv515.c +++ b/drivers/video/drm/radeon/rv515.c @@ -140,7 +140,7 @@ void rv515_ring_start(struct radeon_device *rdev) unsigned gb_tile_config; int r; - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); /* Sub pixel 1/12 so we can have 4K rendering according to doc */ gb_tile_config = R300_ENABLE_TILING | R300_TILE_SIZE_16; switch (rdev->num_gb_pipes) { @@ -231,7 +231,7 @@ void rv515_ring_start(struct radeon_device *rdev) radeon_ring_write(rdev, 0); radeon_ring_unlock_commit(rdev); - dbgprintf("done %s\n\r",__FUNCTION__); + dbgprintf("done %s\n",__FUNCTION__); } @@ -296,7 +296,7 @@ int rv515_ga_reset(struct radeon_device *rdev) bool reinit_cp; int i; - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); reinit_cp = rdev->cp.ready; rdev->cp.ready = false; @@ -350,7 +350,7 @@ int rv515_gpu_reset(struct radeon_device *rdev) { uint32_t status; - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); /* reset order likely matter */ status = RREG32(RADEON_RBBM_STATUS); @@ -569,7 +569,7 @@ static const unsigned r500_reg_safe_bm[159] = { int rv515_init(struct radeon_device *rdev) { - dbgprintf("%s\n\r",__FUNCTION__); + dbgprintf("%s\n",__FUNCTION__); rdev->config.r300.reg_safe_bm = r500_reg_safe_bm; rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(r500_reg_safe_bm);