summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Hellstrom <unichrome@shipmail.org>2006-02-01 17:06:11 +0000
committerThomas Hellstrom <unichrome@shipmail.org>2006-02-01 17:06:11 +0000
commit7e3599548935f50e654db2b05c498ede37d8a9fd (patch)
treea2625eee8e25ed7ff8da4d2e21a90297e14ec15c
parent631ac0b2ad0fd6d08c8a617039209d5e675d2954 (diff)
ttm: More mm infrastructure. Separate create-bind and unbind-destroy for
ttm regions. Fill in fence and ttm_mm fields for i915 driver.
-rw-r--r--linux-core/drmP.h2
-rw-r--r--linux-core/drm_fops.c2
-rw-r--r--linux-core/drm_irq.c1
-rw-r--r--linux-core/drm_mm.c7
-rw-r--r--linux-core/drm_ttm.c151
-rw-r--r--linux-core/drm_ttm.h14
-rw-r--r--linux-core/i915_drv.c1
-rw-r--r--shared-core/i915_dma.c7
-rw-r--r--shared-core/i915_drv.h8
-rw-r--r--shared-core/i915_irq.c23
10 files changed, 163 insertions, 53 deletions
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index 29c184a9..95f011a1 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -612,7 +612,7 @@ struct drm_driver {
unsigned long (*get_reg_ofs) (struct drm_device * dev);
void (*set_version) (struct drm_device * dev, drm_set_version_t * sv);
drm_ttm_backend_t * (*create_ttm_backend_entry) (struct drm_device *dev);
- drm_mm_t * (*ttm_mm) (struct drm_device *dev);
+ drm_ttm_mm_t * (*ttm_mm) (struct drm_device *dev);
int major;
int minor;
diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c
index 2bc76187..4c1a5f6a 100644
--- a/linux-core/drm_fops.c
+++ b/linux-core/drm_fops.c
@@ -473,7 +473,7 @@ int drm_release(struct inode *inode, struct file *filp)
if (!drm_find_ht_item(&dev->ttmreghash, entry, &hash)) {
drm_remove_ht_val(&dev->ttmreghash, hash);
}
- drm_user_unbind_region(entry);
+ drm_user_destroy_region(entry);
}
up(&dev->struct_sem);
diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index 7f21205d..ae064e2c 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -368,3 +368,4 @@ void drm_vbl_send_signals(drm_device_t * dev)
spin_unlock_irqrestore(&dev->vbl_lock, flags);
}
EXPORT_SYMBOL(drm_vbl_send_signals);
+
diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c
index 7e284689..96bc95c1 100644
--- a/linux-core/drm_mm.c
+++ b/linux-core/drm_mm.c
@@ -82,6 +82,7 @@ void drm_mm_put_block_locked(drm_mm_t * mm, drm_mm_node_t * cur)
if (cur_head->prev != root_head) {
prev_node = list_entry(cur_head->prev, drm_mm_node_t, ml_entry);
if (prev_node->free) {
+ DRM_ERROR("Merging with free block ahead\n");
prev_node->size += cur->size;
merged = TRUE;
}
@@ -90,12 +91,14 @@ void drm_mm_put_block_locked(drm_mm_t * mm, drm_mm_node_t * cur)
next_node = list_entry(cur_head->next, drm_mm_node_t, ml_entry);
if (next_node->free) {
if (merged) {
+ DRM_ERROR("Merging also with free block aft.\n");
prev_node->size += next_node->size;
list_del(&next_node->ml_entry);
list_del(&next_node->fl_entry);
drm_free(next_node, sizeof(*next_node),
DRM_MEM_MM);
} else {
+ DRM_ERROR("Merging with block aft.\n");
next_node->size += cur->size;
next_node->start = cur->start;
merged = TRUE;
@@ -105,9 +108,12 @@ void drm_mm_put_block_locked(drm_mm_t * mm, drm_mm_node_t * cur)
if (!merged) {
cur->free = TRUE;
list_add(&cur->fl_entry, &list_root->fl_entry);
+ DRM_ERROR("Adding myself to free list.\n");
+
} else {
list_del(&cur->ml_entry);
drm_free(cur, sizeof(*cur), DRM_MEM_MM);
+ DRM_ERROR("Deleting myself.\n");
}
}
@@ -164,3 +170,4 @@ 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 ed3c1bb8..d95a3dfd 100644
--- a/linux-core/drm_ttm.c
+++ b/linux-core/drm_ttm.c
@@ -166,7 +166,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm)
if (!drm_find_ht_item(&ttm->dev->ttmreghash,
list, &hash))
drm_remove_ht_val(&ttm->dev->ttmreghash, hash);
- drm_unbind_ttm_region(entry);
+ drm_destroy_ttm_region(entry);
}
drm_free(ttm->be_list, sizeof(*ttm->be_list), DRM_MEM_MAPS);
@@ -309,7 +309,54 @@ void drm_unbind_ttm_region(drm_ttm_backend_list_t * entry)
drm_ttm_backend_t *be = entry->be;
drm_ttm_t *ttm = entry->owner;
+ if (be) {
+ switch(entry->state) {
+ case ttm_bound:
+ be->unbind(entry->be);
+ case ttm_evicted:
+ if (ttm && be->needs_cache_adjust(be)) {
+ drm_set_caching(ttm, entry->page_offset,
+ entry->num_pages, FALSE);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ entry->state = ttm_unbound;
+}
+
+static void remove_ttm_region(drm_ttm_backend_list_t * entry) {
+
+ drm_mm_node_t *mm_node = entry->mm_node;
+ drm_ttm_mm_priv_t *mm_priv;
+ drm_ttm_mm_t *mm = entry->mm;
+
+ if (!mm_node)
+ return;
+
+ entry->mm_node = NULL;
+ mm_priv = (drm_ttm_mm_priv_t *)mm_node->private;
+ if (!mm_priv)
+ return;
+
+ mm->wait_fence(mm->dev, mm_priv->fence);
+ mm_node->private = NULL;
+ spin_lock(&mm->mm.mm_lock);
+ list_del(&mm_priv->lru);
+ drm_mm_put_block_locked(&mm->mm, mm_node);
+ spin_unlock(&mm->mm.mm_lock);
+ drm_free(mm_priv, sizeof(*mm_priv), DRM_MEM_MM);
+}
+
+
+void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry)
+{
+ drm_ttm_backend_t *be = entry->be;
+ drm_ttm_t *ttm = entry->owner;
+
list_del(&entry->head);
+ remove_ttm_region(entry);
if (be) {
be->clear(entry->be);
@@ -332,6 +379,8 @@ int drm_search_ttm_region(unsigned long pg_offset, unsigned long n_pages,
list_for_each(list, be) {
drm_ttm_backend_list_t *entry =
list_entry(list, drm_ttm_backend_list_t, head);
+ DRM_ERROR("%lu %lu %u %u\n", pg_offset, n_pages,
+ entry->page_offset, entry->num_pages);
if ((pg_offset <= entry->page_offset &&
end_offset >= entry->page_offset) ||
(entry->page_offset <= pg_offset &&
@@ -344,11 +393,9 @@ int drm_search_ttm_region(unsigned long pg_offset, unsigned long n_pages,
return 0;
}
-int drm_bind_ttm_region(drm_ttm_t * ttm, unsigned long page_offset,
- unsigned long n_pages, unsigned long aper_offset,
- drm_ttm_backend_list_t ** region)
+int drm_create_ttm_region(drm_ttm_t *ttm, unsigned long page_offset,
+ unsigned long n_pages, drm_ttm_backend_list_t **region)
{
-
struct page **cur_page;
drm_ttm_backend_list_t *entry;
drm_ttm_backend_t *be;
@@ -373,7 +420,7 @@ int drm_bind_ttm_region(drm_ttm_t * ttm, unsigned long page_offset,
DRM_ERROR("Couldn't create backend.\n");
return -EINVAL;
}
- entry->bound = FALSE;
+ entry->state = ttm_unbound;
entry->page_offset = page_offset;
entry->num_pages = n_pages;
entry->be = be;
@@ -388,31 +435,42 @@ int drm_bind_ttm_region(drm_ttm_t * ttm, unsigned long page_offset,
*cur_page = alloc_page(GFP_USER);
if (!*cur_page) {
DRM_ERROR("Page allocation failed\n");
- drm_unbind_ttm_region(entry);
+ drm_destroy_ttm_region(entry);
return -ENOMEM;
}
SetPageLocked(*cur_page);
}
}
- if (be->needs_cache_adjust(be)) {
- drm_set_caching(ttm, page_offset, n_pages, TRUE);
- }
-
if ((ret = be->populate(be, n_pages, ttm->pages + page_offset))) {
- drm_unbind_ttm_region(entry);
+ drm_destroy_ttm_region(entry);
DRM_ERROR("Couldn't populate backend.\n");
return ret;
}
+ entry->mm_node = NULL;
+ entry->mm = ttm->dev->driver->ttm_mm(ttm->dev);
+ *region = entry;
+ return 0;
+}
+
+
+int drm_bind_ttm_region(drm_ttm_backend_list_t * region, unsigned long aper_offset)
+{
+
+ drm_ttm_backend_t *be = region->be;
+ drm_ttm_t *ttm = region->owner;
+ int ret;
+
+ if (ttm && be->needs_cache_adjust(be)) {
+ drm_set_caching(ttm, region->page_offset, region->num_pages, TRUE);
+ }
if ((ret = be->bind(be, aper_offset))) {
- drm_unbind_ttm_region(entry);
+ drm_unbind_ttm_region(region);
DRM_ERROR("Couldn't bind backend.\n");
return ret;
}
- entry->bound = TRUE;
- *region = entry;
-
+ region->state = ttm_bound;
return 0;
}
@@ -421,14 +479,14 @@ int drm_evict_ttm_region(drm_ttm_backend_list_t * entry)
int ret;
- if (!entry || !entry->bound)
+ if (!entry || entry->state != ttm_bound)
return -EINVAL;
if (0 != (ret = entry->be->unbind(entry->be))) {
return ret;
}
- entry->bound = FALSE;
+ entry->state = ttm_evicted;
return 0;
}
@@ -438,16 +496,16 @@ int drm_rebind_ttm_region(drm_ttm_backend_list_t * entry,
int ret;
- if (!entry || entry->bound)
+ if (!entry || entry->state == ttm_bound)
return -EINVAL;
if (0 != (ret = entry->be->bind(entry->be, aper_offset))) {
return ret;
}
- entry->bound = TRUE;
+ entry->state = ttm_bound;
return 0;
}
-void drm_user_unbind_region(drm_ttm_backend_list_t * entry)
+void drm_user_destroy_region(drm_ttm_backend_list_t * entry)
{
drm_ttm_backend_t *be;
struct page **cur_page;
@@ -462,9 +520,7 @@ void drm_user_unbind_region(drm_ttm_backend_list_t * entry)
return;
}
- if (entry->bound) {
- be->unbind(be);
- }
+ be->unbind(be);
if (entry->anon_pages) {
cur_page = entry->anon_pages;
@@ -481,8 +537,7 @@ void drm_user_unbind_region(drm_ttm_backend_list_t * entry)
drm_free(entry, sizeof(*entry), DRM_MEM_MAPS);
}
-int drm_user_bind_region(drm_device_t * dev, unsigned long start, int len,
- unsigned long aper_offset,
+int drm_user_create_region(drm_device_t * dev, unsigned long start, int len,
drm_ttm_backend_list_t ** entry)
{
drm_ttm_backend_list_t *tmp;
@@ -502,18 +557,18 @@ int drm_user_bind_region(drm_device_t * dev, unsigned long start, int len,
tmp->be = be;
if (!be) {
- drm_user_unbind_region(tmp);
+ drm_user_destroy_region(tmp);
return -ENOMEM;
}
if (be->needs_cache_adjust(be)) {
- drm_user_unbind_region(tmp);
+ drm_user_destroy_region(tmp);
return -EFAULT;
}
tmp->anon_pages = vmalloc(sizeof(*(tmp->anon_pages)) * len);
if (!tmp->anon_pages) {
- drm_user_unbind_region(tmp);
+ drm_user_destroy_region(tmp);
return -ENOMEM;
}
@@ -523,7 +578,7 @@ int drm_user_bind_region(drm_device_t * dev, unsigned long start, int len,
up_read(&current->mm->mmap_sem);
if (ret != len) {
- drm_user_unbind_region(tmp);
+ drm_user_destroy_region(tmp);
DRM_ERROR("Could not lock %d pages. Return code was %d\n",
len, ret);
return -EPERM;
@@ -532,15 +587,12 @@ int drm_user_bind_region(drm_device_t * dev, unsigned long start, int len,
ret = be->populate(be, len, tmp->anon_pages);
- if (!ret)
- ret = be->bind(be, aper_offset);
-
if (ret) {
- drm_user_unbind_region(tmp);
+ drm_user_destroy_region(tmp);
return ret;
}
- tmp->bound = TRUE;
+ tmp->state = ttm_unbound;
*entry = tmp;
return 0;
@@ -686,16 +738,20 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS)
return -EINVAL;
}
- if ((ret = drm_bind_ttm_region(ttm, ttm_arg.page_offset,
- ttm_arg.num_pages,
- ttm_arg.aper_offset, &entry))) {
+ if ((ret = drm_create_ttm_region(ttm, ttm_arg.page_offset,
+ ttm_arg.num_pages, &entry))) {
up(&dev->struct_sem);
return ret;
}
if ((ret =
drm_insert_ht_val(&dev->ttmreghash, entry,
&ttm_arg.region))) {
- drm_unbind_ttm_region(entry);
+ drm_destroy_ttm_region(entry);
+ up(&dev->struct_sem);
+ return ret;
+ }
+ if ((ret = drm_bind_ttm_region(entry, ttm_arg.aper_offset))) {
+ drm_destroy_ttm_region(entry);
up(&dev->struct_sem);
return ret;
}
@@ -714,16 +770,20 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS)
down(&dev->struct_sem);
ret =
- drm_user_bind_region(dev, start, len, ttm_arg.aper_offset,
- &entry);
+ drm_user_create_region(dev, start, len, &entry);
if (ret) {
up(&dev->struct_sem);
return ret;
}
+ if ((ret = drm_bind_ttm_region(entry, ttm_arg.aper_offset))) {
+ drm_destroy_ttm_region(entry);
+ up(&dev->struct_sem);
+ return ret;
+ }
entry->anon_owner = priv;
if ((ret = drm_insert_ht_val(&dev->ttmreghash, entry,
&ttm_arg.region))) {
- drm_user_unbind_region(entry);
+ drm_user_destroy_region(entry);
up(&dev->struct_sem);
return ret;
}
@@ -753,7 +813,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS)
} else {
if (entry->anon_owner == priv) {
list_del(&entry->head);
- drm_user_unbind_region(entry);
+ drm_user_destroy_region(entry);
} else {
up(&dev->struct_sem);
return -EPERM;
@@ -836,7 +896,7 @@ static int validate_ttm_region(drm_ttm_backend_list_t * entry,
drm_ttm_mm_t *mm = entry->mm;
spinlock_t *mm_lock = &mm->mm.mm_lock;
uint32_t evict_fence;
- uint32_t cur_fence;
+ uint32_t cur_fence = 0;
int have_fence = FALSE;
struct list_head *list;
drm_ttm_mm_priv_t *evict_priv;
@@ -912,7 +972,7 @@ static int validate_ttm_region(drm_ttm_backend_list_t * entry,
break;
case ttm_unbound:
default:
-/* drm_bind_ttm_region(entry); */
+ drm_bind_ttm_region(entry, mm_node->start);
break;
}
@@ -920,3 +980,4 @@ static int validate_ttm_region(drm_ttm_backend_list_t * entry,
*aper_offset = mm_node->start;
return 0;
}
+
diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h
index ec98bffd..3473bdad 100644
--- a/linux-core/drm_ttm.h
+++ b/linux-core/drm_ttm.h
@@ -1,5 +1,6 @@
#ifndef _DRM_TTM_H
#define _DRM_TTM_H
+#define DRM_HAS_TTM
/*
* The backend GART interface. (In our case AGP). Any similar type of device (PCIE?)
@@ -30,7 +31,6 @@ typedef struct drm_ttm_backend_list {
drm_ttm_backend_t *be;
unsigned page_offset;
unsigned num_pages;
- int bound;
struct drm_ttm *owner;
drm_file_t *anon_owner;
struct page **anon_pages;
@@ -74,8 +74,8 @@ typedef struct drm_ttm_mm {
struct drm_device *dev;
drm_mm_t mm;
struct list_head lru_head;
- uint32_t(*emit_fence) (struct drm_device * dev);
- void (*wait_fence) (struct drm_device * dev, uint32_t fence);
+ uint32_t(*emit_fence) (struct drm_device * dev);
+ int (*wait_fence) (struct drm_device * dev, uint32_t fence);
int (*test_fence) (struct drm_device * dev, uint32_t fence);
} drm_ttm_mm_t;
@@ -95,16 +95,18 @@ drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size);
* This function sets all affected pages as noncacheable and flushes cashes and TLB.
*/
-int drm_bind_ttm_region(drm_ttm_t * ttm, unsigned long page_offset,
+int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset,
unsigned long n_pages,
- unsigned long aper_offset,
drm_ttm_backend_list_t ** region);
+int drm_bind_ttm_region(drm_ttm_backend_list_t * region, unsigned long aper_offset);
+
/*
* Unbind a ttm region. Restores caching policy. Flushes caches and TLB.
*/
void drm_unbind_ttm_region(drm_ttm_backend_list_t * entry);
+void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry);
/*
* Evict a ttm region. Keeps Aperture caching policy.
@@ -126,7 +128,7 @@ int drm_rebind_ttm_region(drm_ttm_backend_list_t * entry,
*/
int drm_destroy_ttm(drm_ttm_t * ttm);
-void drm_user_unbind_region(drm_ttm_backend_list_t * entry);
+void drm_user_destroy_region(drm_ttm_backend_list_t * entry);
int drm_ttm_ioctl(DRM_IOCTL_ARGS);
diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c
index fd36d4cd..ea5253e5 100644
--- a/linux-core/i915_drv.c
+++ b/linux-core/i915_drv.c
@@ -59,6 +59,7 @@ static struct drm_driver driver = {
.get_map_ofs = drm_core_get_map_ofs,
.get_reg_ofs = drm_core_get_reg_ofs,
.create_ttm_backend_entry = drm_agp_init_ttm_cached,
+ .ttm_mm = i915_ttm_mm,
.ioctls = i915_ioctls,
.fops = {
.owner = THIS_MODULE,
diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c
index 5418819a..a4c1cd41 100644
--- a/shared-core/i915_dma.c
+++ b/shared-core/i915_dma.c
@@ -31,6 +31,7 @@
#include "i915_drm.h"
#include "i915_drv.h"
+
/* Really want an OS-independent resettable timer. Would like to have
* this loop run for (eg) 3 sec, but have the timer reset every time
* the head pointer changes, so that EBUSY only happens if the ring
@@ -190,6 +191,12 @@ static int i915_initialize(drm_device_t * dev,
I915_WRITE(0x02080, dev_priv->dma_status_page);
DRM_DEBUG("Enabled hardware status page\n");
+#ifdef DRM_HAS_TTM
+ drm_mm_init(&dev_priv->ttm_mm.mm, 51200, 14336);
+ dev_priv->ttm_mm.emit_fence = i915_emit_fence;
+ dev_priv->ttm_mm.wait_fence = i915_wait_fence;
+ dev_priv->ttm_mm.test_fence = i915_test_fence;
+#endif
dev->dev_private = (void *)dev_priv;
return 0;
diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h
index cb86932a..f91c61dd 100644
--- a/shared-core/i915_drv.h
+++ b/shared-core/i915_drv.h
@@ -96,6 +96,9 @@ typedef struct drm_i915_private {
int allow_batchbuffer;
struct mem_block *agp_heap;
unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
+#ifdef DRM_HAS_TTM
+ drm_ttm_mm_t ttm_mm;
+#endif
} drm_i915_private_t;
extern drm_ioctl_desc_t i915_ioctls[];
@@ -120,6 +123,11 @@ extern void i915_driver_irq_preinstall(drm_device_t * dev);
extern void i915_driver_irq_postinstall(drm_device_t * dev);
extern void i915_driver_irq_uninstall(drm_device_t * dev);
+extern uint32_t i915_emit_fence(drm_device_t * dev);
+extern int i915_wait_fence(drm_device_t * dev, uint32_t fence);
+extern int i915_test_fence(drm_device_t * dev, uint32_t fence);
+extern drm_ttm_mm_t *i915_ttm_mm(drm_device_t *dev);
+
/* i915_mem.c */
extern int i915_mem_alloc(DRM_IOCTL_ARGS);
extern int i915_mem_free(DRM_IOCTL_ARGS);
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index d5780d58..31a0cdda 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -209,3 +209,26 @@ void i915_driver_irq_uninstall(drm_device_t * dev)
I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
}
+
+uint32_t i915_emit_fence(drm_device_t * dev)
+{
+ return i915_emit_irq(dev);
+}
+
+int i915_wait_fence(drm_device_t * dev, uint32_t fence)
+{
+ return i915_wait_irq(dev, fence);
+}
+
+extern int i915_test_fence(drm_device_t * dev, uint32_t fence)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ return ((((uint32_t)(READ_BREADCRUMB(dev_priv))) - fence) < (1 << 23));
+}
+
+drm_ttm_mm_t *i915_ttm_mm(drm_device_t *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ return &dev_priv->ttm_mm;
+}
+