summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Hellstrom <unichrome@shipmail.org>2006-02-23 12:06:50 +0000
committerThomas Hellstrom <unichrome@shipmail.org>2006-02-23 12:06:50 +0000
commitb41b2055035bb33ebfd239ca8885084b0cdfd911 (patch)
tree760f786b7de22b490ea811107d3d63348a3ffa05
parentb0f15444a780f549a71c143d7f3957571afbb6f5 (diff)
ttm: Bugfixes
-rw-r--r--linux-core/drm_bufs.c1
-rw-r--r--linux-core/drm_fops.c2
-rw-r--r--linux-core/drm_hashtab.c3
-rw-r--r--linux-core/drm_mm.c16
-rw-r--r--linux-core/drm_ttm.c177
-rw-r--r--linux-core/drm_ttm.h3
-rw-r--r--linux-core/drm_vm.c2
-rw-r--r--linux-core/i915_ttm.c4
8 files changed, 113 insertions, 95 deletions
diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c
index f1176f16..d04233a1 100644
--- a/linux-core/drm_bufs.c
+++ b/linux-core/drm_bufs.c
@@ -387,7 +387,6 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map)
drm_map_list_t *r_list = NULL;
drm_dma_handle_t dmah;
- DRM_ERROR("rmmap locked called %d\n", map->type);
/* Find the list entry for the map and remove it */
list_for_each_safe(list, next, &dev->maplist->head) {
r_list = list_entry(list, drm_map_list_t, head);
diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c
index 4c1a5f6a..dce7d0e9 100644
--- a/linux-core/drm_fops.c
+++ b/linux-core/drm_fops.c
@@ -451,14 +451,12 @@ int drm_release(struct inode *inode, struct file *filp)
} else {
dev->file_last = priv->prev;
}
-
list_for_each_safe(list, next, &priv->ttms) {
drm_map_list_t *entry = list_entry(list, drm_map_list_t, head);
list_del(list);
if (!drm_find_ht_item(&dev->maphash, entry, &hash)) {
drm_remove_ht_val(&dev->maphash, hash);
}
- DRM_ERROR("About to destroy ttm\n");
if (!drm_destroy_ttm((drm_ttm_t *) entry->map->offset))
drm_free(entry->map, sizeof(*entry->map),
DRM_MEM_MAPS);
diff --git a/linux-core/drm_hashtab.c b/linux-core/drm_hashtab.c
index 93224992..f4ad1916 100644
--- a/linux-core/drm_hashtab.c
+++ b/linux-core/drm_hashtab.c
@@ -36,7 +36,6 @@ int drm_insert_ht_val(drm_closedhash_t * ht, void *item, unsigned int *hash)
tmp_hash = 0;
}
BUG_ON(i == ht->size);
-
*hash = tmp_hash;
return 0;
}
@@ -90,7 +89,7 @@ int drm_remove_ht_val(drm_closedhash_t * ht, unsigned int hash)
return DRM_ERR(EINVAL);
}
ht->table[hash] = NULL;
- ht->fill = 0;
+ ht->fill--;
return 0;
}
diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c
index 82bbf93d..da6ebeef 100644
--- a/linux-core/drm_mm.c
+++ b/linux-core/drm_mm.c
@@ -41,13 +41,12 @@
#include "drmP.h"
drm_mm_node_t *drm_mm_get_block_locked(drm_mm_node_t * parent,
- unsigned long size,
- unsigned alignment)
+ unsigned long size, unsigned alignment)
{
- drm_mm_node_t * child;
+ drm_mm_node_t *child;
- if (alignment)
+ if (alignment)
size += alignment - 1;
if (parent->size == size) {
@@ -122,9 +121,8 @@ void drm_mm_put_block_locked(drm_mm_t * mm, drm_mm_node_t * cur)
}
drm_mm_node_t *drm_mm_search_free_locked(const drm_mm_t * mm,
- unsigned long size,
- unsigned alignment,
- int best_match)
+ unsigned long size,
+ unsigned alignment, int best_match)
{
struct list_head *list;
const struct list_head *free_stack = &mm->root_node.fl_entry;
@@ -135,7 +133,7 @@ drm_mm_node_t *drm_mm_search_free_locked(const drm_mm_t * mm,
best = NULL;
best_size = ~0UL;
- if (alignment)
+ if (alignment)
size += alignment - 1;
list_for_each(list, free_stack) {
@@ -157,7 +155,6 @@ int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
{
drm_mm_node_t *child;
-
INIT_LIST_HEAD(&mm->root_node.ml_entry);
INIT_LIST_HEAD(&mm->root_node.fl_entry);
child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM);
@@ -182,4 +179,5 @@ int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
return 0;
}
+
EXPORT_SYMBOL(drm_mm_init);
diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c
index 03c81bb2..a390c620 100644
--- a/linux-core/drm_ttm.c
+++ b/linux-core/drm_ttm.c
@@ -1,6 +1,6 @@
/**************************************************************************
*
- * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2006 Tungsten Graphics, Inc., Steamboat Springs, CO.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -37,8 +37,7 @@
* DAVE: The below code needs to go to the linux mm subsystem. Most of it is already there.
* Basically stolen from mprotect.c and rmap.c
* 8<----------------------------------------------------------------------------------
- */
-
+ */
#ifdef CONFIG_X86_PAE
#error Cannot compile with CONFIG_X86_PAE. __supported_pte_mask undefined.
@@ -153,8 +152,7 @@ static void drm_change_protection(struct vm_area_struct *vma,
/*
* 8<----------------------------------------------------------------------------------
* End linux mm subsystem code.
- */
-
+ */
/*
* Unmap all vma pages from vmas mapping this ttm.
@@ -217,7 +215,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm)
drm_ttm_backend_list_t *entry =
list_entry(list, drm_ttm_backend_list_t, head);
if (!drm_find_ht_item(&ttm->dev->ttmreghash,
- list, &hash))
+ entry, &hash))
drm_remove_ht_val(&ttm->dev->ttmreghash, hash);
drm_destroy_ttm_region(entry);
}
@@ -228,7 +226,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm)
if (ttm->pages) {
for (i = 0; i < ttm->num_pages; ++i) {
cur_page = ttm->pages + i;
- if (ttm->nocached && ttm->nocached[i] &&
+ if (ttm->page_flags && ttm->page_flags[i] &&
*cur_page && !PageHighMem(*cur_page)) {
change_page_attr(*cur_page, 1, PAGE_KERNEL);
}
@@ -240,8 +238,8 @@ int drm_destroy_ttm(drm_ttm_t * ttm)
global_flush_tlb();
vfree(ttm->pages);
}
- if (ttm->nocached) {
- vfree(ttm->nocached);
+ if (ttm->page_flags) {
+ vfree(ttm->page_flags);
}
if (ttm->vma_list) {
@@ -261,7 +259,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm)
/*
* Initialize a ttm.
- * FIXME: Avoid using vmalloc for the page- and nocached tables?
+ * FIXME: Avoid using vmalloc for the page- and page_flags tables?
*/
drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size)
@@ -280,13 +278,13 @@ drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size)
atomic_set(&ttm->vma_count, 0);
ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
- ttm->nocached = vmalloc(ttm->num_pages * sizeof(*ttm->nocached));
- if (!ttm->nocached) {
+ ttm->page_flags = vmalloc(ttm->num_pages * sizeof(*ttm->page_flags));
+ if (!ttm->page_flags) {
drm_destroy_ttm(ttm);
- DRM_ERROR("Failed allocating nocached table\n");
+ DRM_ERROR("Failed allocating page_flags table\n");
return NULL;
}
- memset(ttm->nocached, 0, ttm->num_pages);
+ memset(ttm->page_flags, 0, ttm->num_pages * sizeof(*ttm->page_flags));
ttm->pages = vmalloc(ttm->num_pages * sizeof(*ttm->pages));
if (!ttm->pages) {
@@ -326,18 +324,18 @@ drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size)
static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset,
unsigned long num_pages, int noncached)
{
- int i, cur;
+ int i, cur;
struct page **cur_page;
pgprot_t attr = (noncached) ? PAGE_KERNEL_NOCACHE : PAGE_KERNEL;
int do_spinlock = atomic_read(&ttm->vma_count) > 0;
- down_write(&current->mm->mmap_sem);
if (do_spinlock) {
+ down_write(&current->mm->mmap_sem);
spin_lock(&current->mm->page_table_lock);
unmap_vma_pages(ttm, page_offset, num_pages);
}
for (i = 0; i < num_pages; ++i) {
- cur = page_offset + i;
+ cur = page_offset + i;
cur_page = ttm->pages + cur;
if (*cur_page) {
if (PageHighMem(*cur_page)) {
@@ -346,20 +344,25 @@ static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset,
DRM_ERROR
("Illegal mapped HighMem Page\n");
up_write(&current->mm->mmap_sem);
- spin_unlock(&current->mm->
- page_table_lock);
+ if (do_spinlock) {
+ spin_unlock(&current->mm->
+ page_table_lock);
+ up_write(&current->mm->
+ mmap_sem);
+ }
return -EINVAL;
}
- } else if (ttm->nocached[cur] != noncached) {
- ttm->nocached[cur] = noncached;
+ } else if (ttm->page_flags[cur] != noncached) {
+ ttm->page_flags[cur] = noncached;
change_page_attr(*cur_page, 1, attr);
}
}
}
global_flush_tlb();
- if (do_spinlock)
+ if (do_spinlock) {
spin_unlock(&current->mm->page_table_lock);
- up_write(&current->mm->mmap_sem);
+ up_write(&current->mm->mmap_sem);
+ }
return 0;
}
@@ -446,7 +449,7 @@ void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry)
/*
* Check for overlapping ttm regions.
- * FIXME: We should implement this as flags in the "nocached" table instead.
+ * FIXME: We should implement this as flags in the "page_flags" table instead.
* At least we should keep the list sorted!
*/
@@ -559,6 +562,8 @@ int drm_bind_ttm_region(drm_ttm_backend_list_t * region,
if (ttm && be->needs_cache_adjust(be)) {
drm_set_caching(ttm, region->page_offset, region->num_pages,
TRUE);
+ } else {
+ flush_cache_all();
}
if ((ret = be->bind(be, aper_offset))) {
@@ -599,10 +604,20 @@ int drm_rebind_ttm_region(drm_ttm_backend_list_t * entry,
{
int ret;
+ drm_ttm_backend_t *be;
+ drm_ttm_t *ttm;
if (!entry || entry->state != ttm_evicted)
return -EINVAL;
- if (0 != (ret = entry->be->bind(entry->be, aper_offset))) {
+
+ be = entry->be;
+ ttm = entry->owner;
+
+ if (!ttm || !be->needs_cache_adjust(be)) {
+ flush_cache_all();
+ }
+
+ if (0 != (ret = be->bind(be, aper_offset))) {
return ret;
}
entry->state = ttm_bound;
@@ -800,8 +815,8 @@ static void drm_ttm_fence_regions(drm_ttm_mm_t * mm, uint32_t fence)
* May sleep while waiting for a fence.
*/
-static int drm_ttm_evict_lru_sl(drm_ttm_backend_list_t * entry,
- int *have_fence, uint32_t *cur_fence)
+static int drm_ttm_evict_lru_sl(drm_ttm_backend_list_t * entry,
+ int *have_fence, uint32_t * cur_fence)
{
struct list_head *list;
drm_ttm_mm_t *mm = entry->mm;
@@ -813,44 +828,40 @@ static int drm_ttm_evict_lru_sl(drm_ttm_backend_list_t * entry,
do {
list = entry->mm->lru_head.next;
-
+
if (list == &entry->mm->lru_head) {
- spin_unlock(mm_lock);
DRM_ERROR("Out of aperture space\n");
return -ENOMEM;
}
evict_priv = list_entry(list, drm_ttm_mm_priv_t, lru);
-
+
if (!evict_priv->fence_valid) {
- spin_unlock(mm_lock);
DRM_ERROR("Out of aperture space\n");
return -ENOMEM;
}
-
+
evict_fence = evict_priv->fence;
if (*have_fence && ((*cur_fence - evict_fence) < (1 << 23)))
break;
spin_unlock(mm_lock);
up(&dev->struct_sem);
- dev->driver->ttm_driver->wait_fence(dev,evict_fence);
+ dev->driver->ttm_driver->wait_fence(dev, evict_fence);
down(&dev->struct_sem);
spin_lock(mm_lock);
*cur_fence = evict_fence;
*have_fence = TRUE;
} while (TRUE);
-
+
evict_node = evict_priv->region->mm_node;
drm_evict_ttm_region(evict_priv->region);
- list_del(list);
+ list_del_init(list);
evict_node->private = NULL;
drm_mm_put_block_locked(&mm->mm, evict_node);
+ evict_priv->region->mm_node = NULL;
drm_free(evict_priv, sizeof(*evict_priv), DRM_MEM_MM);
return 0;
}
-
-
-
/*
* Make sure a backend entry is present in the TT. If it is not, try to allocate
* TT space and put it in there. If we're out of space, start evicting old entries
@@ -859,7 +870,6 @@ static int drm_ttm_evict_lru_sl(drm_ttm_backend_list_t * entry,
* the lru list.
*/
-
static int drm_validate_ttm_region(drm_ttm_backend_list_t * entry,
unsigned *aper_offset)
{
@@ -876,6 +886,7 @@ static int drm_validate_ttm_region(drm_ttm_backend_list_t * entry,
mm_priv = drm_alloc(sizeof(*mm_priv), DRM_MEM_MM);
if (!mm_priv)
return -ENOMEM;
+ INIT_LIST_HEAD(&mm_priv->lru);
} else {
mm_priv = mm_node->private;
}
@@ -884,12 +895,15 @@ static int drm_validate_ttm_region(drm_ttm_backend_list_t * entry,
spin_lock(mm_lock);
while (!mm_node) {
mm_node =
- drm_mm_search_free_locked(&entry->mm->mm, num_pages,
- 0, 0);
+ drm_mm_search_free_locked(&entry->mm->mm, num_pages, 0, 0);
if (!mm_node) {
- ret = drm_ttm_evict_lru_sl(entry, &have_fence, &cur_fence);
- if (ret)
+ ret =
+ drm_ttm_evict_lru_sl(entry, &have_fence,
+ &cur_fence);
+ if (ret) {
+ spin_unlock(mm_lock);
return ret;
+ }
}
}
@@ -1071,7 +1085,7 @@ static void drm_ttm_handle_buf(drm_file_t * priv, drm_ttm_buf_arg_t * buf_p)
drm_ttm_create_user_buf(buf_p, buf_p->user_addr,
buf_p->user_size, priv, &entry);
if (buf_p->ret)
- break;
+ break;
ttm_mm = entry->mm;
buf_p->ret =
drm_validate_ttm_region(entry, &buf_p->aper_offset);
@@ -1141,60 +1155,68 @@ int drm_ttm_handle_bufs(drm_file_t * priv, drm_ttm_arg_t * ttm_arg)
{
drm_device_t *dev = priv->head->dev;
drm_ttm_driver_t *ttm_driver = dev->driver->ttm_driver;
- drm_ttm_buf_arg_t *bufs, *next, *buf_p;
+ drm_ttm_buf_arg_t *bufs = NULL, *next, *buf_p;
int i;
- if (!ttm_arg->num_bufs || ttm_arg->num_bufs > DRM_TTM_MAX_BUF_BATCH) {
+ if (ttm_arg->num_bufs > DRM_TTM_MAX_BUF_BATCH) {
DRM_ERROR("Invalid number of TTM buffers.\n");
return -EINVAL;
}
- bufs = drm_calloc(ttm_arg->num_bufs, sizeof(*bufs), DRM_MEM_TTM);
+ if (ttm_arg->num_bufs) {
- if (!bufs) {
- DRM_ERROR("Out of kernel memory for buffers.\n");
- return -ENOMEM;
- }
+ bufs =
+ drm_calloc(ttm_arg->num_bufs, sizeof(*bufs), DRM_MEM_TTM);
- next = ttm_arg->first;
- buf_p = bufs;
+ if (!bufs) {
+ DRM_ERROR("Out of kernel memory for buffers.\n");
+ return -ENOMEM;
+ }
- for (i = 0; i < ttm_arg->num_bufs; ++i) {
- if (DRM_COPY_FROM_USER
- (buf_p, (void __user *)next, sizeof(*bufs)))
- break;
- next = buf_p->next;
- buf_p++;
- }
- if (i != ttm_arg->num_bufs) {
- drm_free(bufs, ttm_arg->num_bufs * sizeof(*bufs), DRM_MEM_TTM);
- DRM_ERROR("Error copying buffer data\n");
- return -EFAULT;
- }
+ next = ttm_arg->first;
+ buf_p = bufs;
+ for (i = 0; i < ttm_arg->num_bufs; ++i) {
+ if (DRM_COPY_FROM_USER
+ (buf_p, (void __user *)next, sizeof(*bufs)))
+ break;
+ next = buf_p->next;
+ buf_p++;
+ }
+ if (i != ttm_arg->num_bufs) {
+ drm_free(bufs, ttm_arg->num_bufs * sizeof(*bufs),
+ DRM_MEM_TTM);
+ DRM_ERROR("Error copying buffer data\n");
+ return -EFAULT;
+ }
+ }
buf_p = bufs;
+
down(&dev->struct_sem);
if (ttm_arg->do_fence)
drm_ttm_fence_regions(ttm_driver->ttm_mm(dev),
ttm_driver->emit_fence(dev));
-
+
for (i = 0; i < ttm_arg->num_bufs; ++i) {
drm_ttm_handle_buf(priv, buf_p);
buf_p++;
}
up(&dev->struct_sem);
- next = ttm_arg->first;
- buf_p = bufs;
- for (i = 0; i < ttm_arg->num_bufs; ++i) {
- if (DRM_COPY_TO_USER((void __user *)next, buf_p, sizeof(*bufs)))
- break;
- next = buf_p->next;
- buf_p++;
- }
+ if (ttm_arg->num_bufs) {
- drm_free(bufs, ttm_arg->num_bufs * sizeof(*bufs), DRM_MEM_TTM);
+ next = ttm_arg->first;
+ buf_p = bufs;
+ for (i = 0; i < ttm_arg->num_bufs; ++i) {
+ if (DRM_COPY_TO_USER
+ ((void __user *)next, buf_p, sizeof(*bufs)))
+ break;
+ next = buf_p->next;
+ buf_p++;
+ }
+ drm_free(bufs, ttm_arg->num_bufs * sizeof(*bufs), DRM_MEM_TTM);
+ }
return 0;
}
@@ -1234,7 +1256,8 @@ static int drm_ttm_handle_remove(drm_file_t * priv, drm_handle_t handle)
}
ret = drm_destroy_ttm(ttm);
list_del(&map_list->head);
- drm_remove_ht_val(&dev->maphash, handle);
+ drm_remove_ht_val(&dev->maphash,
+ (handle - DRM_MAP_HASH_OFFSET) >> PAGE_SHIFT);
up(&dev->struct_sem);
if (!ret) {
@@ -1249,7 +1272,7 @@ static int drm_ttm_handle_remove(drm_file_t * priv, drm_handle_t handle)
}
/*
- * FIXME: Require lock only for validate, but not for evict, unbind or desroy.
+ * FIXME: Require lock only for validate, but not for evict, unbind or destroy.
*/
int drm_ttm_ioctl(DRM_IOCTL_ARGS)
diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h
index 6237f95e..8c91f0a8 100644
--- a/linux-core/drm_ttm.h
+++ b/linux-core/drm_ttm.h
@@ -26,6 +26,7 @@ typedef struct drm_ttm_backend {
#define DRM_FLUSH_READ (0x01)
#define DRM_FLUSH_WRITE (0x02)
+#define DRM_FLUSH_EXE (0x04)
typedef struct drm_ttm_backend_list {
struct list_head head;
@@ -55,7 +56,7 @@ typedef struct drm_ttm_vma_list {
typedef struct drm_ttm {
struct page **pages;
- int8_t *nocached;
+ uint32_t *page_flags;
unsigned long lhandle;
unsigned long num_pages;
drm_ttm_vma_list_t *vma_list;
diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c
index 0010e1e5..05988367 100644
--- a/linux-core/drm_vm.c
+++ b/linux-core/drm_vm.c
@@ -234,7 +234,7 @@ static __inline__ struct page *drm_do_vm_ttm_nopage(struct vm_area_struct *vma,
*/
default_prot = drm_prot_map[vma->vm_flags & 0x0f];
- vma->vm_page_prot = ttm->nocached[page_offset] ?
+ vma->vm_page_prot = ttm->page_flags[page_offset] ?
pgprot_noncached(default_prot):
default_prot;
diff --git a/linux-core/i915_ttm.c b/linux-core/i915_ttm.c
index 52405fa1..593bd9c8 100644
--- a/linux-core/i915_ttm.c
+++ b/linux-core/i915_ttm.c
@@ -1,3 +1,4 @@
+
#include "drmP.h"
#include "drm.h"
#include "i915_drm.h"
@@ -23,8 +24,7 @@ static drm_ttm_mm_t *i915_ttm_mm(drm_device_t * dev)
void i915_init_ttm(drm_device_t * dev, drm_i915_private_t * dev_priv)
{
drm_ttm_driver_t *ttm_driver = &dev_priv->ttm_driver;
-
- drm_ttm_mm_init(dev, &dev_priv->ttm_mm, 51200, 1536);
+ drm_ttm_mm_init(dev, &dev_priv->ttm_mm, 32768, 10240);
ttm_driver->emit_fence = i915_emit_fence;
ttm_driver->wait_fence = i915_wait_fence;
ttm_driver->test_fence = i915_test_fence;