/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 <thomas-at-tungstengraphics-dot-com> |
*/ |
#ifndef _DRM_MM_H_ |
#define _DRM_MM_H_ |
/* |
* Generic range manager structs |
*/ |
#include <types.h> |
#include <list.h> |
#include <errno-base.h> |
#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 |
/drivers/video/drm/include/list.h |
---|
0,0 → 1,703 |
#ifndef _LINUX_LIST_H |
#define _LINUX_LIST_H |
//#include <linux/stddef.h> |
//#include <linux/poison.h> |
//#include <linux/prefetch.h> |
//#include <asm/system.h> |
/* |
* 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 |
/drivers/video/drm/radeon/atom.c |
---|
1165,7 → 1165,7 |
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]; |
/drivers/video/drm/radeon/pci.c |
---|
3,7 → 3,7 |
#include <errno-base.h> |
#include <syscall.h> |
link_t devices; |
static LIST_HEAD(devices); |
static dev_t* pci_scan_device(u32_t bus, int devfn); |
346,7 → 346,7 |
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 |
dev = pci_scan_device(bus, devfn); |
if( dev ) |
{ |
list_append(&dev->link, &devices); |
list_add(&dev->link, &devices); |
nr++; |
420,7 → 420,7 |
u32_t last_bus; |
u32_t bus = 0 , devfn = 0; |
list_initialize(&devices); |
// list_initialize(&devices); |
last_bus = PciApi(1); |
/drivers/video/drm/radeon/r100.c |
---|
268,6 → 268,7 |
radeon_ring_write(rdev, RADEON_SW_INT_FIRE); |
} |
#endif |
/* |
* Writeback |
307,14 → 308,16 |
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 |
{ |
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 |
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 |
bool reinit_cp; |
int i; |
dbgprintf("%s\n\r",__FUNCTION__); |
dbgprintf("%s\n",__FUNCTION__); |
reinit_cp = rdev->cp.ready; |
1170,7 → 1173,7 |
{ |
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 |
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); |
/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 <linux/seq_file.h> |
//#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 |
/drivers/video/drm/radeon/r520.c |
---|
155,7 → 155,7 |
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 |
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 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 |
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 |
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,185 → 463,14 |
} |
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); |
} |
int radeon_fence_driver_init(struct radeon_device *rdev) |
{ |
unsigned long irq_flags; |
741,49 → 498,7 |
} |
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; |
} |
/drivers/video/drm/radeon/radeon.h |
---|
44,11 → 44,13 |
* - TESTING, TESTING, TESTING |
*/ |
#include "types.h" |
#include "pci.h" |
#include <types.h> |
#include <list.h> |
#include "errno-base.h" |
#include <pci.h> |
#include <errno-base.h> |
#include "radeon_mode.h" |
#include "radeon_reg.h" |
#include "r300.h" |
60,7 → 62,6 |
extern int radeon_r4xx_atom; |
/* |
* Copy from radeon_drv.h so we don't have to include both and have conflicting |
* symbol; |
169,15 → 170,15 |
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 |
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 |
/* |
* GART structures, functions & helpers |
*/ |
255,8 → 255,8 |
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 |
* 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_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 |
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 |
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; |
/drivers/video/drm/radeon/radeon_asic.h |
---|
403,8 → 403,8 |
.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, |
/drivers/video/drm/radeon/radeon_atombios.c |
---|
944,7 → 944,7 |
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); |
/drivers/video/drm/radeon/radeon_bios.c |
---|
39,7 → 39,7 |
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; |
} |
/drivers/video/drm/radeon/radeon_device.c |
---|
46,7 → 46,7 |
*/ |
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 |
{ |
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_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 |
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 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 |
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 |
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 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 |
// 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 |
// 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 |
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 |
return r; |
} |
} |
#if 0 |
if (!r) { |
r = radeon_ib_test(rdev); |
if (r) { |
694,9 → 693,9 |
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 |
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 |
struct drm_device *dev; |
int ret; |
dbgprintf("%s\n\r",__FUNCTION__); |
dbgprintf("%s\n",__FUNCTION__); |
dev = malloc(sizeof(*dev)); |
if (!dev) |
/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; |
} |
/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 <glisse@freedesktop.org> |
* Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> |
* Dave Airlie |
*/ |
//#include <linux/list.h> |
//#include <drm/drmP.h> |
#include "radeon_drm.h" |
#include "radeon.h" |
#include <drm_mm.h> |
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 |
/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 |
return r; |
} |
void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib) |
{ |
struct radeon_ib *tmp = *ib; |
170,6 → 172,7 |
mutex_unlock(&rdev->ib_pool.mutex); |
return 0; |
} |
#endif |
int radeon_ib_pool_init(struct radeon_device *rdev) |
{ |
210,9 → 213,9 |
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 |
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_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,7 → 417,6 |
rdev->cp.ring_size = ring_size; |
#if 0 |
/* Allocate ring buffer */ |
if (rdev->cp.ring_obj == NULL) { |
r = radeon_object_create(rdev, NULL, rdev->cp.ring_size, |
442,23 → 445,19 |
return r; |
} |
} |
#endif |
dbgprintf("ring size %x\n", ring_size); |
dbgprintf("ring buffer %x\n", rdev->cp.ring ); |
// rdev->cp.ring = CreateRingBuffer( ring_size, PG_SW ); |
rdev->cp.ring = ring_buffer; //CreateRingBuffer( ring_size, PG_SW ); |
dbgprintf("ring buffer %x\n", rdev->cp.ring ); |
rdev->cp.gpu_addr = rdev->mc.gtt_location; |
// rdev->cp.gpu_addr = rdev->mc.gtt_location; |
u32_t *pagelist = &((u32_t*)page_tabs)[(u32_t)rdev->cp.ring >> 12]; |
// u32_t *pagelist = &((u32_t*)page_tabs)[(u32_t)rdev->cp.ring >> 12]; |
dbgprintf("pagelist %x\n", pagelist); |
// 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; |
/drivers/video/drm/radeon/rv515.c |
---|
140,7 → 140,7 |
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 |
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 |
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 |
{ |
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 |
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); |