diff options
author | Thomas Hellstrom <unichrome@shipmail.org> | 2006-02-01 17:06:11 +0000 |
---|---|---|
committer | Thomas Hellstrom <unichrome@shipmail.org> | 2006-02-01 17:06:11 +0000 |
commit | 7e3599548935f50e654db2b05c498ede37d8a9fd (patch) | |
tree | a2625eee8e25ed7ff8da4d2e21a90297e14ec15c | |
parent | 631ac0b2ad0fd6d08c8a617039209d5e675d2954 (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.h | 2 | ||||
-rw-r--r-- | linux-core/drm_fops.c | 2 | ||||
-rw-r--r-- | linux-core/drm_irq.c | 1 | ||||
-rw-r--r-- | linux-core/drm_mm.c | 7 | ||||
-rw-r--r-- | linux-core/drm_ttm.c | 151 | ||||
-rw-r--r-- | linux-core/drm_ttm.h | 14 | ||||
-rw-r--r-- | linux-core/i915_drv.c | 1 | ||||
-rw-r--r-- | shared-core/i915_dma.c | 7 | ||||
-rw-r--r-- | shared-core/i915_drv.h | 8 | ||||
-rw-r--r-- | shared-core/i915_irq.c | 23 |
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(¤t->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; +} + |