From 700bf80ca9fadf2c1404c220addebd92d9ad799d Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 22 Aug 2006 09:47:33 +0200 Subject: Bring in stripped TTM functionality. --- linux-core/drm_ttm.c | 813 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 813 insertions(+) create mode 100644 linux-core/drm_ttm.c (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c new file mode 100644 index 00000000..b3ea7c9b --- /dev/null +++ b/linux-core/drm_ttm.c @@ -0,0 +1,813 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Steamboat Springs, CO. + * 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. + * + * + **************************************************************************/ + +#include "drmP.h" +#include + +typedef struct p_mm_entry { + struct list_head head; + struct mm_struct *mm; + atomic_t refcount; +} p_mm_entry_t; + +typedef struct drm_val_action { + int needs_rx_flush; + int evicted_tt; + int evicted_vram; + int validated; +} drm_val_action_t; + +/* + * We may be manipulating other processes page tables, so for each TTM, keep track of + * which mm_structs are currently mapping the ttm so that we can take the appropriate + * locks when we modify their page tables. A typical application is when we evict another + * process' buffers. + */ + +int drm_ttm_add_mm_to_list(drm_ttm_t * ttm, struct mm_struct *mm) +{ + p_mm_entry_t *entry, *n_entry; + + list_for_each_entry(entry, &ttm->p_mm_list, head) { + if (mm == entry->mm) { + atomic_inc(&entry->refcount); + return 0; + } else if ((unsigned long)mm < (unsigned long)entry->mm) ; + } + + n_entry = drm_alloc(sizeof(*n_entry), DRM_MEM_MM); + if (!entry) { + DRM_ERROR("Allocation of process mm pointer entry failed\n"); + return -ENOMEM; + } + INIT_LIST_HEAD(&n_entry->head); + n_entry->mm = mm; + atomic_set(&n_entry->refcount, 0); + atomic_inc(&ttm->shared_count); + ttm->mm_list_seq++; + + list_add_tail(&n_entry->head, &entry->head); + + return 0; +} + +void drm_ttm_delete_mm(drm_ttm_t * ttm, struct mm_struct *mm) +{ + p_mm_entry_t *entry, *n; + list_for_each_entry_safe(entry, n, &ttm->p_mm_list, head) { + if (mm == entry->mm) { + if (atomic_add_negative(-1, &entry->refcount)) { + list_del(&entry->head); + drm_free(entry, sizeof(*entry), DRM_MEM_MM); + atomic_dec(&ttm->shared_count); + ttm->mm_list_seq++; + } + return; + } + } + BUG_ON(TRUE); +} + +static void drm_ttm_lock_mm(drm_ttm_t * ttm, int mm_sem, int page_table) +{ + p_mm_entry_t *entry; + + list_for_each_entry(entry, &ttm->p_mm_list, head) { + if (mm_sem) { + down_write(&entry->mm->mmap_sem); + } + if (page_table) { + spin_lock(&entry->mm->page_table_lock); + } + } +} + +static void drm_ttm_unlock_mm(drm_ttm_t * ttm, int mm_sem, int page_table) +{ + p_mm_entry_t *entry; + + list_for_each_entry(entry, &ttm->p_mm_list, head) { + if (page_table) { + spin_unlock(&entry->mm->page_table_lock); + } + if (mm_sem) { + up_write(&entry->mm->mmap_sem); + } + } +} + +static int ioremap_vmas(drm_ttm_t * ttm, unsigned long page_offset, + unsigned long num_pages, unsigned long aper_offset) +{ + struct list_head *list; + int ret = 0; + + list_for_each(list, &ttm->vma_list->head) { + drm_ttm_vma_list_t *entry = + list_entry(list, drm_ttm_vma_list_t, head); + + ret = io_remap_pfn_range(entry->vma, + entry->vma->vm_start + + (page_offset << PAGE_SHIFT), + (ttm->aperture_base >> PAGE_SHIFT) + + aper_offset, num_pages << PAGE_SHIFT, + drm_io_prot(_DRM_AGP, entry->vma)); + if (ret) + break; + } + global_flush_tlb(); + return ret; +} + +/* + * Unmap all vma pages from vmas mapping this ttm. + */ + +static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset, + unsigned long num_pages) +{ + struct list_head *list; + struct page **first_page = ttm->pages + page_offset; + struct page **last_page = ttm->pages + (page_offset + num_pages); + struct page **cur_page; + + list_for_each(list, &ttm->vma_list->head) { + drm_ttm_vma_list_t *entry = + list_entry(list, drm_ttm_vma_list_t, head); + drm_clear_vma(entry->vma, + entry->vma->vm_start + + (page_offset << PAGE_SHIFT), + entry->vma->vm_start + + ((page_offset + num_pages) << PAGE_SHIFT)); + } + + for (cur_page = first_page; cur_page != last_page; ++cur_page) { + if (page_mapcount(*cur_page) != 0) { + DRM_ERROR("Mapped page detected. Map count is %d\n", + page_mapcount(*cur_page)); + return -1; + } + } + return 0; +} + +/* + * Free all resources associated with a ttm. + */ + +int drm_destroy_ttm(drm_ttm_t * ttm) +{ + + int i; + struct list_head *list, *next; + struct page **cur_page; + + if (!ttm) + return 0; + + if (atomic_read(&ttm->vma_count) > 0) { + DRM_DEBUG("VMAs are still alive. Skipping destruction.\n"); + return -EBUSY; + } else { + DRM_DEBUG("Checking for busy regions.\n"); + } + + if (ttm->be_list) { + list_for_each_safe(list, next, &ttm->be_list->head) { + drm_ttm_backend_list_t *entry = + list_entry(list, drm_ttm_backend_list_t, head); +#ifdef REMOVED + drm_ht_remove_item(&ttm->dev->ttmreghash, + &entry->hash); +#endif + drm_destroy_ttm_region(entry); + } + + drm_free(ttm->be_list, sizeof(*ttm->be_list), DRM_MEM_MAPS); + ttm->be_list = NULL; + } + + if (atomic_read(&ttm->unfinished_regions) > 0) { + DRM_DEBUG("Regions are still busy. Skipping destruction.\n"); + ttm->destroy = TRUE; + return -EAGAIN; + } else { + DRM_DEBUG("About to really destroy ttm.\n"); + } + + if (ttm->pages) { + for (i = 0; i < ttm->num_pages; ++i) { + cur_page = ttm->pages + i; + if (ttm->page_flags && + (ttm->page_flags[i] & DRM_TTM_PAGE_UNCACHED) && + *cur_page && !PageHighMem(*cur_page)) { + change_page_attr(*cur_page, 1, PAGE_KERNEL); + } + if (*cur_page) { + ClearPageReserved(*cur_page); + __free_page(*cur_page); + } + } + global_flush_tlb(); + vfree(ttm->pages); + ttm->pages = NULL; + } + if (ttm->page_flags) { + vfree(ttm->page_flags); + ttm->page_flags = NULL; + } + + if (ttm->vma_list) { + list_for_each_safe(list, next, &ttm->vma_list->head) { + drm_ttm_vma_list_t *entry = + list_entry(list, drm_ttm_vma_list_t, head); + list_del(list); + entry->vma->vm_private_data = NULL; + drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); + } + drm_free(ttm->vma_list, sizeof(*ttm->vma_list), DRM_MEM_MAPS); + ttm->vma_list = NULL; + } + drm_free(ttm, sizeof(*ttm), DRM_MEM_MAPS); + + return 0; +} + +/* + * Initialize a ttm. + * FIXME: Avoid using vmalloc for the page- and page_flags tables? + */ + +drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size) +{ + + drm_ttm_t *ttm; + + if (!dev->driver->bo_driver) + return NULL; + + ttm = drm_calloc(1, sizeof(*ttm), DRM_MEM_MAPS); + if (!ttm) + return NULL; + + ttm->lhandle = 0; + atomic_set(&ttm->vma_count, 0); + atomic_set(&ttm->unfinished_regions, 0); + ttm->destroy = FALSE; + ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + + ttm->page_flags = vmalloc(ttm->num_pages * sizeof(*ttm->page_flags)); + if (!ttm->page_flags) { + drm_destroy_ttm(ttm); + DRM_ERROR("Failed allocating page_flags table\n"); + return NULL; + } + memset(ttm->page_flags, 0, ttm->num_pages * sizeof(*ttm->page_flags)); + + ttm->pages = vmalloc(ttm->num_pages * sizeof(*ttm->pages)); + if (!ttm->pages) { + drm_destroy_ttm(ttm); + DRM_ERROR("Failed allocating page table\n"); + return NULL; + } + memset(ttm->pages, 0, ttm->num_pages * sizeof(*ttm->pages)); + + ttm->be_list = drm_calloc(1, sizeof(*ttm->be_list), DRM_MEM_MAPS); + if (!ttm->be_list) { + DRM_ERROR("Alloc be regions failed\n"); + drm_destroy_ttm(ttm); + return NULL; + } + + INIT_LIST_HEAD(&ttm->be_list->head); + INIT_LIST_HEAD(&ttm->p_mm_list); + atomic_set(&ttm->shared_count, 0); + ttm->mm_list_seq = 0; + + ttm->vma_list = drm_calloc(1, sizeof(*ttm->vma_list), DRM_MEM_MAPS); + if (!ttm->vma_list) { + DRM_ERROR("Alloc vma list failed\n"); + drm_destroy_ttm(ttm); + return NULL; + } + + INIT_LIST_HEAD(&ttm->vma_list->head); + + ttm->lhandle = (unsigned long)ttm; + ttm->dev = dev; + return ttm; +} + +/* + * Lock the mmap_sems for processes that are mapping this ttm. + * This looks a bit clumsy, since we need to maintain the correct + * locking order + * mm->mmap_sem + * dev->struct_sem; + * and while we release dev->struct_sem to lock the mmap_sems, + * the mmap_sem list may have been updated. We need to revalidate + * it after relocking dev->struc_sem. + */ + +static int drm_ttm_lock_mmap_sem(drm_ttm_t * ttm) +{ + struct mm_struct **mm_list = NULL, **mm_list_p; + uint32_t list_seq; + uint32_t cur_count, shared_count; + p_mm_entry_t *entry; + unsigned i; + + cur_count = 0; + list_seq = ttm->mm_list_seq; + shared_count = atomic_read(&ttm->shared_count); + + do { + if (shared_count > cur_count) { + if (mm_list) + drm_free(mm_list, sizeof(*mm_list) * cur_count, + DRM_MEM_MM); + cur_count = shared_count + 10; + mm_list = + drm_alloc(sizeof(*mm_list) * cur_count, DRM_MEM_MM); + if (!mm_list) + return -ENOMEM; + } + + mm_list_p = mm_list; + list_for_each_entry(entry, &ttm->p_mm_list, head) { + *mm_list_p++ = entry->mm; + } + + mutex_unlock(&ttm->dev->struct_mutex); + mm_list_p = mm_list; + for (i = 0; i < shared_count; ++i, ++mm_list_p) { + down_write(&((*mm_list_p)->mmap_sem)); + } + + mutex_lock(&ttm->dev->struct_mutex); + + if (list_seq != ttm->mm_list_seq) { + mm_list_p = mm_list; + for (i = 0; i < shared_count; ++i, ++mm_list_p) { + up_write(&((*mm_list_p)->mmap_sem)); + } + + } + shared_count = atomic_read(&ttm->shared_count); + + } while (list_seq != ttm->mm_list_seq); + + if (mm_list) + drm_free(mm_list, sizeof(*mm_list) * cur_count, DRM_MEM_MM); + + ttm->mmap_sem_locked = TRUE; + return 0; +} + +/* + * Change caching policy for range of pages in a ttm. + */ + +static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset, + unsigned long num_pages, int noncached, + int do_tlbflush) +{ + int i, cur; + struct page **cur_page; + pgprot_t attr = (noncached) ? PAGE_KERNEL_NOCACHE : PAGE_KERNEL; + + drm_ttm_lock_mm(ttm, FALSE, TRUE); + unmap_vma_pages(ttm, page_offset, num_pages); + + for (i = 0; i < num_pages; ++i) { + cur = page_offset + i; + cur_page = ttm->pages + cur; + if (*cur_page) { + if (PageHighMem(*cur_page)) { + if (noncached + && page_address(*cur_page) != NULL) { + DRM_ERROR + ("Illegal mapped HighMem Page\n"); + drm_ttm_unlock_mm(ttm, FALSE, TRUE); + return -EINVAL; + } + } else if ((ttm->page_flags[cur] & + DRM_TTM_PAGE_UNCACHED) != noncached) { + DRM_MASK_VAL(ttm->page_flags[cur], + DRM_TTM_PAGE_UNCACHED, noncached); + change_page_attr(*cur_page, 1, attr); + } + } + } + if (do_tlbflush) + global_flush_tlb(); + + drm_ttm_unlock_mm(ttm, FALSE, TRUE); + return 0; +} + + +/* + * Unbind a ttm region from the aperture. + */ + +int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) +{ + drm_ttm_backend_t *be = entry->be; + drm_ttm_t *ttm = entry->owner; + int ret; + + if (be) { + switch (entry->state) { + case ttm_bound: + if (ttm && be->needs_cache_adjust(be)) { + ret = drm_ttm_lock_mmap_sem(ttm); + if (ret) + return ret; + drm_ttm_lock_mm(ttm, FALSE, TRUE); + unmap_vma_pages(ttm, entry->page_offset, + entry->num_pages); + global_flush_tlb(); + drm_ttm_unlock_mm(ttm, FALSE, TRUE); + } + be->unbind(entry->be); + if (ttm && be->needs_cache_adjust(be)) { + drm_set_caching(ttm, entry->page_offset, + entry->num_pages, 0, 1); + drm_ttm_unlock_mm(ttm, TRUE, FALSE); + } + break; + default: + break; + } + } + entry->state = ttm_evicted; + return 0; +} + +void drm_unbind_ttm_region(drm_ttm_backend_list_t * entry) +{ + drm_evict_ttm_region(entry); + entry->state = ttm_unbound; +} + +/* + * Destroy and clean up all resources associated with a ttm region. + * FIXME: release pages to OS when doing this operation. + */ + +void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry) +{ + drm_ttm_backend_t *be = entry->be; + drm_ttm_t *ttm = entry->owner; + uint32_t *cur_page_flags; + int i; + + list_del_init(&entry->head); + + drm_unbind_ttm_region(entry); + if (be) { + be->clear(entry->be); + if (be->needs_cache_adjust(be)) { + int ret = drm_ttm_lock_mmap_sem(ttm); + drm_set_caching(ttm, entry->page_offset, + entry->num_pages, 0, 1); + if (!ret) + drm_ttm_unlock_mm(ttm, TRUE, FALSE); + } + be->destroy(be); + } + cur_page_flags = ttm->page_flags + entry->page_offset; + for (i = 0; i < entry->num_pages; ++i) { + DRM_MASK_VAL(*cur_page_flags, DRM_TTM_PAGE_USED, 0); + cur_page_flags++; + } + + drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); +} + +/* + * Create a ttm region from a range of ttm pages. + */ + +int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset, + unsigned long n_pages, int cached, + drm_ttm_backend_list_t ** region) +{ + struct page **cur_page; + uint32_t *cur_page_flags; + drm_ttm_backend_list_t *entry; + drm_ttm_backend_t *be; + int ret, i; + + if ((page_offset + n_pages) > ttm->num_pages || n_pages == 0) { + DRM_ERROR("Region Doesn't fit ttm\n"); + return -EINVAL; + } + + cur_page_flags = ttm->page_flags + page_offset; + for (i = 0; i < n_pages; ++i, ++cur_page_flags) { + if (*cur_page_flags & DRM_TTM_PAGE_USED) { + DRM_ERROR("TTM region overlap\n"); + return -EINVAL; + } else { + DRM_MASK_VAL(*cur_page_flags, DRM_TTM_PAGE_USED, + DRM_TTM_PAGE_USED); + } + } + + entry = drm_calloc(1, sizeof(*entry), DRM_MEM_MAPS); + if (!entry) + return -ENOMEM; + + be = ttm->dev->driver->bo_driver->create_ttm_backend_entry(ttm->dev, cached); + if (!be) { + drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); + DRM_ERROR("Couldn't create backend.\n"); + return -EINVAL; + } + entry->state = ttm_unbound; + entry->page_offset = page_offset; + entry->num_pages = n_pages; + entry->be = be; + entry->owner = ttm; + + INIT_LIST_HEAD(&entry->head); + list_add_tail(&entry->head, &ttm->be_list->head); + + for (i = 0; i < entry->num_pages; ++i) { + cur_page = ttm->pages + (page_offset + i); + if (!*cur_page) { + *cur_page = alloc_page(GFP_KERNEL); + if (!*cur_page) { + DRM_ERROR("Page allocation failed\n"); + drm_destroy_ttm_region(entry); + return -ENOMEM; + } + SetPageReserved(*cur_page); + } + } + + if ((ret = be->populate(be, n_pages, ttm->pages + page_offset))) { + drm_destroy_ttm_region(entry); + DRM_ERROR("Couldn't populate backend.\n"); + return ret; + } + ttm->aperture_base = be->aperture_base; + + *region = entry; + return 0; +} + +/* + * Bind a ttm region. Set correct caching policy. + */ + +int drm_bind_ttm_region(drm_ttm_backend_list_t * region, + unsigned long aper_offset) +{ + + int i; + uint32_t *cur_page_flag; + int ret = 0; + drm_ttm_backend_t *be; + drm_ttm_t *ttm; + + if (!region || region->state == ttm_bound) + return -EINVAL; + + be = region->be; + ttm = region->owner; + + if (ttm && be->needs_cache_adjust(be)) { + ret = drm_ttm_lock_mmap_sem(ttm); + if (ret) + return ret; + drm_set_caching(ttm, region->page_offset, region->num_pages, + DRM_TTM_PAGE_UNCACHED, TRUE); + } else { + DRM_DEBUG("Binding cached\n"); + } + + if ((ret = be->bind(be, aper_offset))) { + if (ttm && be->needs_cache_adjust(be)) + drm_ttm_unlock_mm(ttm, TRUE, FALSE); + drm_unbind_ttm_region(region); + DRM_ERROR("Couldn't bind backend.\n"); + return ret; + } + + cur_page_flag = ttm->page_flags + region->page_offset; + for (i = 0; i < region->num_pages; ++i) { + DRM_MASK_VAL(*cur_page_flag, DRM_TTM_MASK_PFN, + (i + aper_offset) << PAGE_SHIFT); + cur_page_flag++; + } + + if (ttm && be->needs_cache_adjust(be)) { + ioremap_vmas(ttm, region->page_offset, region->num_pages, + aper_offset); + drm_ttm_unlock_mm(ttm, TRUE, FALSE); + } + + region->state = ttm_bound; + return 0; +} + +int drm_rebind_ttm_region(drm_ttm_backend_list_t * entry, + unsigned long aper_offset) +{ + return drm_bind_ttm_region(entry, aper_offset); + +} + +/* + * Destroy an anonymous ttm region. + */ + +void drm_user_destroy_region(drm_ttm_backend_list_t * entry) +{ + drm_ttm_backend_t *be; + struct page **cur_page; + int i; + + if (!entry || entry->owner) + return; + + be = entry->be; + if (!be) { + drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); + return; + } + + be->unbind(be); + + if (entry->anon_pages) { + cur_page = entry->anon_pages; + for (i = 0; i < entry->anon_locked; ++i) { + if (!PageReserved(*cur_page)) + SetPageDirty(*cur_page); + page_cache_release(*cur_page); + cur_page++; + } + vfree(entry->anon_pages); + } + + be->destroy(be); + drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); + return; +} + +/* + * Create a ttm region from an arbitrary region of user pages. + * Since this region has no backing ttm, it's owner is set to + * null, and it is registered with the file of the caller. + * Gets destroyed when the file is closed. We call this an + * anonymous ttm region. + */ + +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; + drm_ttm_backend_t *be; + int ret; + + if (len <= 0) + return -EINVAL; + if (!dev->driver->bo_driver->create_ttm_backend_entry) + return -EFAULT; + + tmp = drm_calloc(1, sizeof(*tmp), DRM_MEM_MAPS); + + if (!tmp) + return -ENOMEM; + + be = dev->driver->bo_driver->create_ttm_backend_entry(dev, 1); + tmp->be = be; + + if (!be) { + drm_user_destroy_region(tmp); + return -ENOMEM; + } + if (be->needs_cache_adjust(be)) { + drm_user_destroy_region(tmp); + return -EFAULT; + } + + tmp->anon_pages = vmalloc(sizeof(*(tmp->anon_pages)) * len); + + if (!tmp->anon_pages) { + drm_user_destroy_region(tmp); + return -ENOMEM; + } + + down_read(¤t->mm->mmap_sem); + ret = get_user_pages(current, current->mm, start, len, 1, 0, + tmp->anon_pages, NULL); + up_read(¤t->mm->mmap_sem); + + if (ret != len) { + drm_user_destroy_region(tmp); + DRM_ERROR("Could not lock %d pages. Return code was %d\n", + len, ret); + return -EPERM; + } + tmp->anon_locked = len; + + ret = be->populate(be, len, tmp->anon_pages); + + if (ret) { + drm_user_destroy_region(tmp); + return ret; + } + + tmp->state = ttm_unbound; +#ifdef REMOVED + tmp->mm = &dev->driver->bo_driver->ttm_mm; +#endif + *entry = tmp; + + return 0; +} + +/* + * Create a ttm and add it to the drm book-keeping. + */ + +int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist) +{ + drm_map_list_t *list; + drm_map_t *map; + drm_ttm_t *ttm; + + map = drm_alloc(sizeof(*map), DRM_MEM_MAPS); + if (!map) + return -ENOMEM; + + ttm = drm_init_ttm(dev, size); + + if (!ttm) { + DRM_ERROR("Could not create ttm\n"); + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + return -ENOMEM; + } + + map->offset = ttm->lhandle; + map->type = _DRM_TTM; + map->flags = _DRM_REMOVABLE; + map->size = size; + + list = drm_calloc(1, sizeof(*list), DRM_MEM_MAPS); + if (!list) { + drm_destroy_ttm(ttm); + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + return -ENOMEM; + } + map->handle = (void *)list; + + +#ifdef REMOVED + if (drm_ht_just_insert_please(&dev->maphash, &list->hash, + (unsigned long) map->handle, + 32 - PAGE_SHIFT)) { + drm_destroy_ttm(ttm); + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + drm_free(list, sizeof(*list), DRM_MEM_MAPS); + return -ENOMEM; + } +#endif + + list->user_token = + (list->hash.key << PAGE_SHIFT) + DRM_MAP_HASH_OFFSET; + list->map = map; + + *maplist = list; + + return 0; +} -- cgit v1.2.3 From ca4e34e532e818921f7b2d36fc6886874b7f7924 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 22 Aug 2006 11:19:53 +0200 Subject: ttm code cleanup. Fix the sleep-in-page-table-spinlock bug discovered by Dave Airlie --- linux-core/drm_ttm.c | 98 ++++++++++++++++++++++------------------------------ 1 file changed, 42 insertions(+), 56 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index b3ea7c9b..493f1465 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright 2006 Tungsten Graphics, Inc., Steamboat Springs, CO. + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -60,7 +60,7 @@ int drm_ttm_add_mm_to_list(drm_ttm_t * ttm, struct mm_struct *mm) } else if ((unsigned long)mm < (unsigned long)entry->mm) ; } - n_entry = drm_alloc(sizeof(*n_entry), DRM_MEM_MM); + n_entry = drm_alloc(sizeof(*n_entry), DRM_MEM_TTM); if (!entry) { DRM_ERROR("Allocation of process mm pointer entry failed\n"); return -ENOMEM; @@ -83,7 +83,7 @@ void drm_ttm_delete_mm(drm_ttm_t * ttm, struct mm_struct *mm) if (mm == entry->mm) { if (atomic_add_negative(-1, &entry->refcount)) { list_del(&entry->head); - drm_free(entry, sizeof(*entry), DRM_MEM_MM); + drm_free(entry, sizeof(*entry), DRM_MEM_TTM); atomic_dec(&ttm->shared_count); ttm->mm_list_seq++; } @@ -155,7 +155,9 @@ static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset, struct page **first_page = ttm->pages + page_offset; struct page **last_page = ttm->pages + (page_offset + num_pages); struct page **cur_page; - +#if !defined(flush_tlb_mm) && defined(MODULE) + int flush_tlb = 0; +#endif list_for_each(list, &ttm->vma_list->head) { drm_ttm_vma_list_t *entry = list_entry(list, drm_ttm_vma_list_t, head); @@ -164,7 +166,14 @@ static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset, (page_offset << PAGE_SHIFT), entry->vma->vm_start + ((page_offset + num_pages) << PAGE_SHIFT)); +#if !defined(flush_tlb_mm) && defined(MODULE) + flush_tlb = 1; +#endif } +#if !defined(flush_tlb_mm) && defined(MODULE) + if (flush_tlb) + global_flush_tlb(); +#endif for (cur_page = first_page; cur_page != last_page; ++cur_page) { if (page_mapcount(*cur_page) != 0) { @@ -193,33 +202,19 @@ int drm_destroy_ttm(drm_ttm_t * ttm) if (atomic_read(&ttm->vma_count) > 0) { DRM_DEBUG("VMAs are still alive. Skipping destruction.\n"); return -EBUSY; - } else { - DRM_DEBUG("Checking for busy regions.\n"); - } + } if (ttm->be_list) { list_for_each_safe(list, next, &ttm->be_list->head) { drm_ttm_backend_list_t *entry = list_entry(list, drm_ttm_backend_list_t, head); -#ifdef REMOVED - drm_ht_remove_item(&ttm->dev->ttmreghash, - &entry->hash); -#endif drm_destroy_ttm_region(entry); } - drm_free(ttm->be_list, sizeof(*ttm->be_list), DRM_MEM_MAPS); + drm_free(ttm->be_list, sizeof(*ttm->be_list), DRM_MEM_TTM); ttm->be_list = NULL; } - if (atomic_read(&ttm->unfinished_regions) > 0) { - DRM_DEBUG("Regions are still busy. Skipping destruction.\n"); - ttm->destroy = TRUE; - return -EAGAIN; - } else { - DRM_DEBUG("About to really destroy ttm.\n"); - } - if (ttm->pages) { for (i = 0; i < ttm->num_pages; ++i) { cur_page = ttm->pages + i; @@ -237,6 +232,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) vfree(ttm->pages); ttm->pages = NULL; } + if (ttm->page_flags) { vfree(ttm->page_flags); ttm->page_flags = NULL; @@ -248,12 +244,13 @@ int drm_destroy_ttm(drm_ttm_t * ttm) list_entry(list, drm_ttm_vma_list_t, head); list_del(list); entry->vma->vm_private_data = NULL; - drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); + drm_free(entry, sizeof(*entry), DRM_MEM_TTM); } - drm_free(ttm->vma_list, sizeof(*ttm->vma_list), DRM_MEM_MAPS); + drm_free(ttm->vma_list, sizeof(*ttm->vma_list), DRM_MEM_TTM); ttm->vma_list = NULL; } - drm_free(ttm, sizeof(*ttm), DRM_MEM_MAPS); + + drm_free(ttm, sizeof(*ttm), DRM_MEM_TTM); return 0; } @@ -271,14 +268,12 @@ drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size) if (!dev->driver->bo_driver) return NULL; - ttm = drm_calloc(1, sizeof(*ttm), DRM_MEM_MAPS); + ttm = drm_calloc(1, sizeof(*ttm), DRM_MEM_TTM); if (!ttm) return NULL; ttm->lhandle = 0; atomic_set(&ttm->vma_count, 0); - atomic_set(&ttm->unfinished_regions, 0); - ttm->destroy = FALSE; ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; ttm->page_flags = vmalloc(ttm->num_pages * sizeof(*ttm->page_flags)); @@ -297,7 +292,7 @@ drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size) } memset(ttm->pages, 0, ttm->num_pages * sizeof(*ttm->pages)); - ttm->be_list = drm_calloc(1, sizeof(*ttm->be_list), DRM_MEM_MAPS); + ttm->be_list = drm_calloc(1, sizeof(*ttm->be_list), DRM_MEM_TTM); if (!ttm->be_list) { DRM_ERROR("Alloc be regions failed\n"); drm_destroy_ttm(ttm); @@ -309,7 +304,7 @@ drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size) atomic_set(&ttm->shared_count, 0); ttm->mm_list_seq = 0; - ttm->vma_list = drm_calloc(1, sizeof(*ttm->vma_list), DRM_MEM_MAPS); + ttm->vma_list = drm_calloc(1, sizeof(*ttm->vma_list), DRM_MEM_TTM); if (!ttm->vma_list) { DRM_ERROR("Alloc vma list failed\n"); drm_destroy_ttm(ttm); @@ -350,10 +345,10 @@ static int drm_ttm_lock_mmap_sem(drm_ttm_t * ttm) if (shared_count > cur_count) { if (mm_list) drm_free(mm_list, sizeof(*mm_list) * cur_count, - DRM_MEM_MM); + DRM_MEM_TTM); cur_count = shared_count + 10; mm_list = - drm_alloc(sizeof(*mm_list) * cur_count, DRM_MEM_MM); + drm_alloc(sizeof(*mm_list) * cur_count, DRM_MEM_TTM); if (!mm_list) return -ENOMEM; } @@ -383,9 +378,8 @@ static int drm_ttm_lock_mmap_sem(drm_ttm_t * ttm) } while (list_seq != ttm->mm_list_seq); if (mm_list) - drm_free(mm_list, sizeof(*mm_list) * cur_count, DRM_MEM_MM); + drm_free(mm_list, sizeof(*mm_list) * cur_count, DRM_MEM_TTM); - ttm->mmap_sem_locked = TRUE; return 0; } @@ -403,6 +397,7 @@ static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset, drm_ttm_lock_mm(ttm, FALSE, TRUE); unmap_vma_pages(ttm, page_offset, num_pages); + drm_ttm_unlock_mm(ttm, FALSE, TRUE); for (i = 0; i < num_pages; ++i) { cur = page_offset + i; @@ -413,7 +408,6 @@ static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset, && page_address(*cur_page) != NULL) { DRM_ERROR ("Illegal mapped HighMem Page\n"); - drm_ttm_unlock_mm(ttm, FALSE, TRUE); return -EINVAL; } } else if ((ttm->page_flags[cur] & @@ -426,12 +420,9 @@ static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset, } if (do_tlbflush) global_flush_tlb(); - - drm_ttm_unlock_mm(ttm, FALSE, TRUE); return 0; } - /* * Unbind a ttm region from the aperture. */ @@ -508,7 +499,7 @@ void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry) cur_page_flags++; } - drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); + drm_free(entry, sizeof(*entry), DRM_MEM_TTM); } /* @@ -541,13 +532,13 @@ int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset, } } - entry = drm_calloc(1, sizeof(*entry), DRM_MEM_MAPS); + entry = drm_calloc(1, sizeof(*entry), DRM_MEM_TTM); if (!entry) return -ENOMEM; be = ttm->dev->driver->bo_driver->create_ttm_backend_entry(ttm->dev, cached); if (!be) { - drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); + drm_free(entry, sizeof(*entry), DRM_MEM_TTM); DRM_ERROR("Couldn't create backend.\n"); return -EINVAL; } @@ -661,7 +652,7 @@ void drm_user_destroy_region(drm_ttm_backend_list_t * entry) be = entry->be; if (!be) { - drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); + drm_free(entry, sizeof(*entry), DRM_MEM_TTM); return; } @@ -679,7 +670,7 @@ void drm_user_destroy_region(drm_ttm_backend_list_t * entry) } be->destroy(be); - drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); + drm_free(entry, sizeof(*entry), DRM_MEM_TTM); return; } @@ -703,7 +694,7 @@ int drm_user_create_region(drm_device_t * dev, unsigned long start, int len, if (!dev->driver->bo_driver->create_ttm_backend_entry) return -EFAULT; - tmp = drm_calloc(1, sizeof(*tmp), DRM_MEM_MAPS); + tmp = drm_calloc(1, sizeof(*tmp), DRM_MEM_TTM); if (!tmp) return -ENOMEM; @@ -748,9 +739,6 @@ int drm_user_create_region(drm_device_t * dev, unsigned long start, int len, } tmp->state = ttm_unbound; -#ifdef REMOVED - tmp->mm = &dev->driver->bo_driver->ttm_mm; -#endif *entry = tmp; return 0; @@ -766,7 +754,7 @@ int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist) drm_map_t *map; drm_ttm_t *ttm; - map = drm_alloc(sizeof(*map), DRM_MEM_MAPS); + map = drm_alloc(sizeof(*map), DRM_MEM_TTM); if (!map) return -ENOMEM; @@ -774,7 +762,7 @@ int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist) if (!ttm) { DRM_ERROR("Could not create ttm\n"); - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + drm_free(map, sizeof(*map), DRM_MEM_TTM); return -ENOMEM; } @@ -783,25 +771,23 @@ int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist) map->flags = _DRM_REMOVABLE; map->size = size; - list = drm_calloc(1, sizeof(*list), DRM_MEM_MAPS); + list = drm_calloc(1, sizeof(*list), DRM_MEM_TTM); if (!list) { drm_destroy_ttm(ttm); - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + drm_free(map, sizeof(*map), DRM_MEM_TTM); return -ENOMEM; } map->handle = (void *)list; - -#ifdef REMOVED - if (drm_ht_just_insert_please(&dev->maphash, &list->hash, + if (drm_ht_just_insert_please(&dev->map_hash, &list->hash, (unsigned long) map->handle, - 32 - PAGE_SHIFT)) { + 32 - PAGE_SHIFT - 3, PAGE_SHIFT, + DRM_MAP_HASH_OFFSET)) { drm_destroy_ttm(ttm); - drm_free(map, sizeof(*map), DRM_MEM_MAPS); - drm_free(list, sizeof(*list), DRM_MEM_MAPS); + drm_free(map, sizeof(*map), DRM_MEM_TTM); + drm_free(list, sizeof(*list), DRM_MEM_TTM); return -ENOMEM; } -#endif list->user_token = (list->hash.key << PAGE_SHIFT) + DRM_MAP_HASH_OFFSET; -- cgit v1.2.3 From e201511a0fbeb177a9ecd7f77d177fc88c1616fb Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 22 Aug 2006 11:57:08 +0200 Subject: More ttm cleanups. --- linux-core/drm_ttm.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 493f1465..df4c312c 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -90,7 +90,7 @@ void drm_ttm_delete_mm(drm_ttm_t * ttm, struct mm_struct *mm) return; } } - BUG_ON(TRUE); + BUG_ON(1); } static void drm_ttm_lock_mm(drm_ttm_t * ttm, int mm_sem, int page_table) @@ -200,6 +200,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) return 0; if (atomic_read(&ttm->vma_count) > 0) { + ttm->destroy = 1; DRM_DEBUG("VMAs are still alive. Skipping destruction.\n"); return -EBUSY; } @@ -260,7 +261,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) * FIXME: Avoid using vmalloc for the page- and page_flags tables? */ -drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size) +static drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size) { drm_ttm_t *ttm; @@ -274,6 +275,7 @@ drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size) ttm->lhandle = 0; atomic_set(&ttm->vma_count, 0); + ttm->destroy = 0; ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; ttm->page_flags = vmalloc(ttm->num_pages * sizeof(*ttm->page_flags)); @@ -315,6 +317,7 @@ drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size) ttm->lhandle = (unsigned long)ttm; ttm->dev = dev; + return ttm; } @@ -395,9 +398,9 @@ static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset, struct page **cur_page; pgprot_t attr = (noncached) ? PAGE_KERNEL_NOCACHE : PAGE_KERNEL; - drm_ttm_lock_mm(ttm, FALSE, TRUE); + drm_ttm_lock_mm(ttm, 0, 1); unmap_vma_pages(ttm, page_offset, num_pages); - drm_ttm_unlock_mm(ttm, FALSE, TRUE); + drm_ttm_unlock_mm(ttm, 0, 1); for (i = 0; i < num_pages; ++i) { cur = page_offset + i; @@ -440,17 +443,17 @@ int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) ret = drm_ttm_lock_mmap_sem(ttm); if (ret) return ret; - drm_ttm_lock_mm(ttm, FALSE, TRUE); + drm_ttm_lock_mm(ttm, 0, 1); unmap_vma_pages(ttm, entry->page_offset, entry->num_pages); global_flush_tlb(); - drm_ttm_unlock_mm(ttm, FALSE, TRUE); + drm_ttm_unlock_mm(ttm, 0, 1); } be->unbind(entry->be); if (ttm && be->needs_cache_adjust(be)) { drm_set_caching(ttm, entry->page_offset, entry->num_pages, 0, 1); - drm_ttm_unlock_mm(ttm, TRUE, FALSE); + drm_ttm_unlock_mm(ttm, 1, 0); } break; default: @@ -489,7 +492,7 @@ void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry) drm_set_caching(ttm, entry->page_offset, entry->num_pages, 0, 1); if (!ret) - drm_ttm_unlock_mm(ttm, TRUE, FALSE); + drm_ttm_unlock_mm(ttm, 1, 0); } be->destroy(be); } @@ -600,14 +603,14 @@ int drm_bind_ttm_region(drm_ttm_backend_list_t * region, if (ret) return ret; drm_set_caching(ttm, region->page_offset, region->num_pages, - DRM_TTM_PAGE_UNCACHED, TRUE); + DRM_TTM_PAGE_UNCACHED, 1); } else { DRM_DEBUG("Binding cached\n"); } if ((ret = be->bind(be, aper_offset))) { if (ttm && be->needs_cache_adjust(be)) - drm_ttm_unlock_mm(ttm, TRUE, FALSE); + drm_ttm_unlock_mm(ttm, 1, 0); drm_unbind_ttm_region(region); DRM_ERROR("Couldn't bind backend.\n"); return ret; @@ -623,7 +626,7 @@ int drm_bind_ttm_region(drm_ttm_backend_list_t * region, if (ttm && be->needs_cache_adjust(be)) { ioremap_vmas(ttm, region->page_offset, region->num_pages, aper_offset); - drm_ttm_unlock_mm(ttm, TRUE, FALSE); + drm_ttm_unlock_mm(ttm, 1, 0); } region->state = ttm_bound; -- cgit v1.2.3 From 4c03030b12bae28dad50d69bd271de632c43ff13 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 25 Aug 2006 18:05:35 +0200 Subject: Checkpoint commit Buffer object code. --- linux-core/drm_ttm.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index df4c312c..806c109b 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -398,10 +398,6 @@ static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset, struct page **cur_page; pgprot_t attr = (noncached) ? PAGE_KERNEL_NOCACHE : PAGE_KERNEL; - drm_ttm_lock_mm(ttm, 0, 1); - unmap_vma_pages(ttm, page_offset, num_pages); - drm_ttm_unlock_mm(ttm, 0, 1); - for (i = 0; i < num_pages; ++i) { cur = page_offset + i; cur_page = ttm->pages + cur; @@ -446,7 +442,6 @@ int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) drm_ttm_lock_mm(ttm, 0, 1); unmap_vma_pages(ttm, entry->page_offset, entry->num_pages); - global_flush_tlb(); drm_ttm_unlock_mm(ttm, 0, 1); } be->unbind(entry->be); @@ -489,6 +484,10 @@ void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry) be->clear(entry->be); if (be->needs_cache_adjust(be)) { int ret = drm_ttm_lock_mmap_sem(ttm); + drm_ttm_lock_mm(ttm, 0, 1); + unmap_vma_pages(ttm, entry->page_offset, + entry->num_pages); + drm_ttm_unlock_mm(ttm, 0, 1); drm_set_caching(ttm, entry->page_offset, entry->num_pages, 0, 1); if (!ret) @@ -792,8 +791,7 @@ int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist) return -ENOMEM; } - list->user_token = - (list->hash.key << PAGE_SHIFT) + DRM_MAP_HASH_OFFSET; + list->user_token = list->hash.key; list->map = map; *maplist = list; -- cgit v1.2.3 From 35c8ce6c2945ff09dc52dbc2a7382798ba64c1da Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 25 Aug 2006 19:03:42 +0200 Subject: ttm and buffer objects ioctl stubs. --- linux-core/drm_ttm.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 806c109b..46878a7d 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -798,3 +798,8 @@ int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist) return 0; } + +int drm_ttm_ioctl(drm_file_t *priv, int num_requests, drm_ttm_arg_t __user *data) +{ + return 0; +} -- cgit v1.2.3 From c488e25ceb421c6f84f110d786d9814ac4dba1b2 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 25 Aug 2006 20:03:39 +0200 Subject: More ioctl stubs. Buffer object locking order documentation. --- linux-core/drm_ttm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 46878a7d..05bae7de 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -799,7 +799,7 @@ int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist) return 0; } -int drm_ttm_ioctl(drm_file_t *priv, int num_requests, drm_ttm_arg_t __user *data) +int drm_ttm_ioctl(drm_file_t *priv, drm_ttm_arg_t __user *data) { return 0; } -- cgit v1.2.3 From 65e7274008446d2059b7fd7cd6d7b1d6b04da0ce Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sun, 27 Aug 2006 19:03:20 +0200 Subject: ttm create / destroy / ref / unref ioctl. --- linux-core/drm_ttm.c | 138 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 117 insertions(+), 21 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 05bae7de..293b1f8c 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -42,6 +42,7 @@ typedef struct drm_val_action { int validated; } drm_val_action_t; + /* * We may be manipulating other processes page tables, so for each TTM, keep track of * which mm_structs are currently mapping the ttm so that we can take the appropriate @@ -275,6 +276,7 @@ static drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size) ttm->lhandle = 0; atomic_set(&ttm->vma_count, 0); + ttm->destroy = 0; ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; @@ -746,25 +748,80 @@ int drm_user_create_region(drm_device_t * dev, unsigned long start, int len, return 0; } + /* - * Create a ttm and add it to the drm book-keeping. + * dev->struct_mutex locked. */ -int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist) +static void drm_ttm_object_remove(drm_device_t *dev, drm_ttm_object_t *object) { + drm_map_list_t *list = &object->map_list; + drm_local_map_t *map; + + if (list->user_token) + drm_ht_remove_item(&dev->map_hash, &list->hash); + + map = list->map; + + if (map) { + drm_ttm_t *ttm = (drm_ttm_t *)map->offset; + if (ttm) { + if (drm_destroy_ttm(ttm) != -EBUSY) { + drm_free(map, sizeof(*map), DRM_MEM_TTM); + } + } else { + drm_free(map, sizeof(*map), DRM_MEM_TTM); + } + } + + drm_free(object, sizeof(*object), DRM_MEM_TTM); +} + +/* + * dev->struct_mutex locked. + */ +static void drm_ttm_user_object_remove(drm_file_t *priv, drm_user_object_t *base) +{ + drm_ttm_object_t *object; + drm_device_t *dev = priv->head->dev; + + object = drm_user_object_entry(base, drm_ttm_object_t, base); + if (atomic_dec_and_test(&object->usage)) + drm_ttm_object_remove(dev, object); +} + + + +/* + * Create a ttm and add it to the drm book-keeping. + * dev->struct_mutex locked. + */ + +int drm_ttm_object_create(drm_device_t *dev, unsigned long size, + uint32_t flags, drm_ttm_object_t **ttm_object) +{ + drm_ttm_object_t *object; drm_map_list_t *list; drm_map_t *map; drm_ttm_t *ttm; - map = drm_alloc(sizeof(*map), DRM_MEM_TTM); - if (!map) + object = drm_calloc(1, sizeof(*object), DRM_MEM_TTM); + if (!object) + return -ENOMEM; + object->flags = flags; + list = &object->map_list; + + list->map = drm_calloc(1, sizeof(*map), DRM_MEM_TTM); + if (!list->map) { + drm_ttm_object_remove(dev, object); return -ENOMEM; + } + map = list->map; ttm = drm_init_ttm(dev, size); - if (!ttm) { DRM_ERROR("Could not create ttm\n"); - drm_free(map, sizeof(*map), DRM_MEM_TTM); + drm_ttm_object_remove(dev, object); return -ENOMEM; } @@ -772,34 +829,73 @@ int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist) map->type = _DRM_TTM; map->flags = _DRM_REMOVABLE; map->size = size; - - list = drm_calloc(1, sizeof(*list), DRM_MEM_TTM); - if (!list) { - drm_destroy_ttm(ttm); - drm_free(map, sizeof(*map), DRM_MEM_TTM); - return -ENOMEM; - } - map->handle = (void *)list; - + map->handle = (void *)object; + if (drm_ht_just_insert_please(&dev->map_hash, &list->hash, (unsigned long) map->handle, 32 - PAGE_SHIFT - 3, PAGE_SHIFT, DRM_MAP_HASH_OFFSET)) { - drm_destroy_ttm(ttm); - drm_free(map, sizeof(*map), DRM_MEM_TTM); - drm_free(list, sizeof(*list), DRM_MEM_TTM); + drm_ttm_object_remove(dev, object); return -ENOMEM; } list->user_token = list->hash.key; - list->map = map; - - *maplist = list; + object->base.remove = drm_ttm_user_object_remove; + object->base.type = drm_ttm_type; + object->base.ref_struct_locked = NULL; + object->base.unref = NULL; + atomic_set(&object->usage, 1); return 0; } + int drm_ttm_ioctl(drm_file_t *priv, drm_ttm_arg_t __user *data) { + drm_ttm_arg_t arg; + drm_device_t *dev = priv->head->dev; + drm_ttm_object_t *entry; + drm_user_object_t *uo; + unsigned long size; + int ret; + + DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); + + switch(arg.op) { + case drm_ttm_create: + mutex_lock(&dev->struct_mutex); + size = combine_64(arg.size_lo, arg.size_hi); + ret = drm_ttm_object_create(dev, size, arg.flags, &entry); + if (ret) { + mutex_unlock(&dev->struct_mutex); + return ret; + } + ret = drm_add_user_object(priv, &entry->base, + arg.flags & DRM_TTM_FLAG_SHAREABLE); + if (ret) { + drm_ttm_object_remove(dev, entry); + mutex_unlock(&dev->struct_mutex); + return ret; + } + arg.handle = entry->base.hash.key; + arg.user_token = entry->map_list.user_token; + mutex_unlock(&dev->struct_mutex); + break; + case drm_ttm_reference: + return drm_user_object_ref(priv, arg.handle, drm_ttm_type, &uo); + case drm_ttm_unreference: + return drm_user_object_unref(priv, arg.handle, drm_ttm_type); + case drm_ttm_destroy: + mutex_lock(&dev->struct_mutex); + uo = drm_lookup_user_object(priv, arg.handle); + if (!uo || (uo->type != drm_ttm_type) || uo->owner != priv) { + mutex_unlock(&dev->struct_mutex); + return -EINVAL; + } + ret = drm_remove_user_object(priv, uo); + mutex_unlock(&dev->struct_mutex); + return ret; + } + DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); return 0; } -- cgit v1.2.3 From 4fa58aa15242333a635cb590762c6e6312945745 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sun, 27 Aug 2006 19:07:38 +0200 Subject: Add TTM map handle on reference. --- linux-core/drm_ttm.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 293b1f8c..6e132745 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -882,7 +882,15 @@ int drm_ttm_ioctl(drm_file_t *priv, drm_ttm_arg_t __user *data) mutex_unlock(&dev->struct_mutex); break; case drm_ttm_reference: - return drm_user_object_ref(priv, arg.handle, drm_ttm_type, &uo); + ret = drm_user_object_ref(priv, arg.handle, drm_ttm_type, &uo); + if (ret) + return ret; + mutex_lock(&dev->struct_mutex); + uo = drm_lookup_user_object(priv, arg.handle); + entry = drm_user_object_entry(uo, drm_ttm_object_t, base); + arg.user_token = entry->map_list.user_token; + mutex_unlock(&dev->struct_mutex); + break; case drm_ttm_unreference: return drm_user_object_unref(priv, arg.handle, drm_ttm_type); case drm_ttm_destroy: -- cgit v1.2.3 From ac26b51503dfedf422d6ae49518adcf41dff1af3 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sun, 27 Aug 2006 19:45:38 +0200 Subject: Have TTM create and reference ioctl call return the actual TTM size. --- linux-core/drm_ttm.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 6e132745..ecf3e0ac 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -828,7 +828,7 @@ int drm_ttm_object_create(drm_device_t *dev, unsigned long size, map->offset = ttm->lhandle; map->type = _DRM_TTM; map->flags = _DRM_REMOVABLE; - map->size = size; + map->size = ttm->num_pages * PAGE_SIZE; map->handle = (void *)object; if (drm_ht_just_insert_please(&dev->map_hash, &list->hash, @@ -877,9 +877,7 @@ int drm_ttm_ioctl(drm_file_t *priv, drm_ttm_arg_t __user *data) mutex_unlock(&dev->struct_mutex); return ret; } - arg.handle = entry->base.hash.key; - arg.user_token = entry->map_list.user_token; - mutex_unlock(&dev->struct_mutex); + atomic_inc(&entry->usage); break; case drm_ttm_reference: ret = drm_user_object_ref(priv, arg.handle, drm_ttm_type, &uo); @@ -888,8 +886,6 @@ int drm_ttm_ioctl(drm_file_t *priv, drm_ttm_arg_t __user *data) mutex_lock(&dev->struct_mutex); uo = drm_lookup_user_object(priv, arg.handle); entry = drm_user_object_entry(uo, drm_ttm_object_t, base); - arg.user_token = entry->map_list.user_token; - mutex_unlock(&dev->struct_mutex); break; case drm_ttm_unreference: return drm_user_object_unref(priv, arg.handle, drm_ttm_type); @@ -904,6 +900,12 @@ int drm_ttm_ioctl(drm_file_t *priv, drm_ttm_arg_t __user *data) mutex_unlock(&dev->struct_mutex); return ret; } + arg.handle = entry->base.hash.key; + arg.user_token = entry->map_list.user_token; + split_32(entry->map_list.map->size, &arg.size_lo, &arg.size_hi); + atomic_dec(&entry->usage); + mutex_unlock(&dev->struct_mutex); + DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); return 0; } -- cgit v1.2.3 From b4b7b997605f88f3ffdcb0cc7cd1271e0cb24073 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sun, 27 Aug 2006 21:16:13 +0200 Subject: Remove the ioctl multiplexing, and instead allow for generic drm ioctls 0x80 - 0xFF. --- linux-core/drm_ttm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index ecf3e0ac..950b0d4d 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -850,10 +850,10 @@ int drm_ttm_object_create(drm_device_t *dev, unsigned long size, } -int drm_ttm_ioctl(drm_file_t *priv, drm_ttm_arg_t __user *data) +int drm_ttm_ioctl(DRM_IOCTL_ARGS) { + DRM_DEVICE; drm_ttm_arg_t arg; - drm_device_t *dev = priv->head->dev; drm_ttm_object_t *entry; drm_user_object_t *uo; unsigned long size; -- cgit v1.2.3 From 886d3b3061cdf53f5a353cbaac843f63104d2658 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sun, 27 Aug 2006 22:01:33 +0200 Subject: Bugfixes. --- linux-core/drm_ttm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 950b0d4d..ad7b279e 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -846,6 +846,7 @@ int drm_ttm_object_create(drm_device_t *dev, unsigned long size, object->base.unref = NULL; atomic_set(&object->usage, 1); + *ttm_object = object; return 0; } -- cgit v1.2.3 From e181f594a4a75790ce1d2a8e907f9fcc5e88b419 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 28 Aug 2006 09:49:09 +0200 Subject: Add a 64-bit drm unsigned type for 64-bit clean IOCTLS. Conversion functions in drmP.h and xf86drm.c. --- linux-core/drm_ttm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index ad7b279e..e76b41fb 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -865,7 +865,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) switch(arg.op) { case drm_ttm_create: mutex_lock(&dev->struct_mutex); - size = combine_64(arg.size_lo, arg.size_hi); + size = drm_ul(arg.size); ret = drm_ttm_object_create(dev, size, arg.flags, &entry); if (ret) { mutex_unlock(&dev->struct_mutex); @@ -903,7 +903,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) } arg.handle = entry->base.hash.key; arg.user_token = entry->map_list.user_token; - split_32(entry->map_list.map->size, &arg.size_lo, &arg.size_hi); + arg.size = drm_u64(entry->map_list.map->size); atomic_dec(&entry->usage); mutex_unlock(&dev->struct_mutex); -- cgit v1.2.3 From 0d67356de4e0c9e0d068ea9c16cf33df4fd13776 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 28 Aug 2006 16:36:37 +0200 Subject: Proper TTM dereferencing Initial buffer object creation. --- linux-core/drm_ttm.c | 56 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 15 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index e76b41fb..cda3ec29 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -752,7 +752,6 @@ int drm_user_create_region(drm_device_t * dev, unsigned long start, int len, /* * dev->struct_mutex locked. */ - static void drm_ttm_object_remove(drm_device_t *dev, drm_ttm_object_t *object) { drm_map_list_t *list = &object->map_list; @@ -777,17 +776,24 @@ static void drm_ttm_object_remove(drm_device_t *dev, drm_ttm_object_t *object) drm_free(object, sizeof(*object), DRM_MEM_TTM); } + +void drm_ttm_object_deref_locked(drm_device_t *dev, drm_ttm_object_t *to) +{ + if (atomic_dec_and_test(&to->usage)) { + drm_ttm_object_remove(dev, to); + } +} + + /* * dev->struct_mutex locked. */ -static void drm_ttm_user_object_remove(drm_file_t *priv, drm_user_object_t *base) +static void drm_ttm_user_deref_locked(drm_file_t *priv, drm_user_object_t *base) { - drm_ttm_object_t *object; - drm_device_t *dev = priv->head->dev; - - object = drm_user_object_entry(base, drm_ttm_object_t, base); - if (atomic_dec_and_test(&object->usage)) - drm_ttm_object_remove(dev, object); + DRM_ERROR("User deref ttm\n"); + drm_ttm_object_deref_locked(priv->head->dev, + drm_user_object_entry(base, drm_ttm_object_t, + base)); } @@ -840,16 +846,33 @@ int drm_ttm_object_create(drm_device_t *dev, unsigned long size, } list->user_token = list->hash.key; - object->base.remove = drm_ttm_user_object_remove; - object->base.type = drm_ttm_type; - object->base.ref_struct_locked = NULL; - object->base.unref = NULL; atomic_set(&object->usage, 1); *ttm_object = object; return 0; } +drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t *priv, uint32_t handle, + int check_owner) +{ + drm_user_object_t *uo; + drm_ttm_object_t *to; + + uo = drm_lookup_user_object(priv, handle); + + if (!uo || (uo->type != drm_ttm_type)) + return NULL; + + if (check_owner && priv != uo->owner) { + if (!drm_lookup_ref_object(priv, uo, _DRM_REF_USE)) + return NULL; + } + + to = drm_user_object_entry(uo, drm_ttm_object_t, base); + atomic_inc(&to->usage); + return to; +} + int drm_ttm_ioctl(DRM_IOCTL_ARGS) { @@ -878,6 +901,10 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) mutex_unlock(&dev->struct_mutex); return ret; } + entry->base.remove = drm_ttm_user_deref_locked; + entry->base.type = drm_ttm_type; + entry->base.ref_struct_locked = NULL; + entry->base.unref = NULL; atomic_inc(&entry->usage); break; case drm_ttm_reference: @@ -885,8 +912,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) if (ret) return ret; mutex_lock(&dev->struct_mutex); - uo = drm_lookup_user_object(priv, arg.handle); - entry = drm_user_object_entry(uo, drm_ttm_object_t, base); + entry = drm_lookup_ttm_object(priv, arg.handle , 0); break; case drm_ttm_unreference: return drm_user_object_unref(priv, arg.handle, drm_ttm_type); @@ -904,7 +930,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) arg.handle = entry->base.hash.key; arg.user_token = entry->map_list.user_token; arg.size = drm_u64(entry->map_list.map->size); - atomic_dec(&entry->usage); + drm_ttm_object_deref_locked(dev, entry); mutex_unlock(&dev->struct_mutex); DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); -- cgit v1.2.3 From 279e8d26c6cf7347aa9cb6d50d025a41dff9a5be Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 29 Aug 2006 10:45:34 +0200 Subject: =?UTF-8?q?64-bit=20IOCTL=20integer=20(Michel=20D=E4nzer=20&=20Bri?= =?UTF-8?q?an=20Paul)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- linux-core/drm_ttm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index cda3ec29..8cd0af61 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -888,7 +888,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) switch(arg.op) { case drm_ttm_create: mutex_lock(&dev->struct_mutex); - size = drm_ul(arg.size); + size = arg.size; ret = drm_ttm_object_create(dev, size, arg.flags, &entry); if (ret) { mutex_unlock(&dev->struct_mutex); @@ -929,7 +929,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) } arg.handle = entry->base.hash.key; arg.user_token = entry->map_list.user_token; - arg.size = drm_u64(entry->map_list.map->size); + arg.size = entry->map_list.map->size; drm_ttm_object_deref_locked(dev, entry); mutex_unlock(&dev->struct_mutex); -- cgit v1.2.3 From 0dedfc2cd03f50b435476e56637b333d345fddbd Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 29 Aug 2006 14:52:02 +0200 Subject: Checkpoint ttm addition to buffer objects. --- linux-core/drm_ttm.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 8cd0af61..e111070e 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -784,6 +784,16 @@ void drm_ttm_object_deref_locked(drm_device_t *dev, drm_ttm_object_t *to) } } +void drm_ttm_object_deref_unlocked(drm_device_t *dev, drm_ttm_object_t *to) +{ + if (atomic_dec_and_test(&to->usage)) { + mutex_lock(&dev->struct_mutex); + if (atomic_read(&to->usage) == 0) + drm_ttm_object_remove(dev, to); + mutex_unlock(&dev->struct_mutex); + } +} + /* * dev->struct_mutex locked. -- cgit v1.2.3 From 23f01c9fe8e6170459fe46ad5fc9757bbe967d96 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 29 Aug 2006 18:40:08 +0200 Subject: Checkpoint commit. Buffer object flags and IOCTL argument list. --- linux-core/drm_ttm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index e111070e..65d40344 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -202,10 +202,11 @@ int drm_destroy_ttm(drm_ttm_t * ttm) if (atomic_read(&ttm->vma_count) > 0) { ttm->destroy = 1; - DRM_DEBUG("VMAs are still alive. Skipping destruction.\n"); + DRM_ERROR("VMAs are still alive. Skipping destruction.\n"); return -EBUSY; } + DRM_ERROR("Destroying a ttm\n"); if (ttm->be_list) { list_for_each_safe(list, next, &ttm->be_list->head) { drm_ttm_backend_list_t *entry = @@ -479,6 +480,7 @@ void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry) uint32_t *cur_page_flags; int i; + DRM_ERROR("Destroying a TTM region\n"); list_del_init(&entry->head); drm_unbind_ttm_region(entry); @@ -800,7 +802,6 @@ void drm_ttm_object_deref_unlocked(drm_device_t *dev, drm_ttm_object_t *to) */ static void drm_ttm_user_deref_locked(drm_file_t *priv, drm_user_object_t *base) { - DRM_ERROR("User deref ttm\n"); drm_ttm_object_deref_locked(priv->head->dev, drm_user_object_entry(base, drm_ttm_object_t, base)); -- cgit v1.2.3 From 033bda07e9a4eab5058fb919b375deb57b08b5be Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 09:57:35 +0200 Subject: Buffer object reply fill in. Lindent of drm_bo.c drm_ttm.c --- linux-core/drm_ttm.c | 61 +++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 32 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 65d40344..33567d9b 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -42,7 +42,6 @@ typedef struct drm_val_action { int validated; } drm_val_action_t; - /* * We may be manipulating other processes page tables, so for each TTM, keep track of * which mm_structs are currently mapping the ttm so that we can take the appropriate @@ -204,7 +203,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) ttm->destroy = 1; DRM_ERROR("VMAs are still alive. Skipping destruction.\n"); return -EBUSY; - } + } DRM_ERROR("Destroying a ttm\n"); if (ttm->be_list) { @@ -263,7 +262,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) * FIXME: Avoid using vmalloc for the page- and page_flags tables? */ -static drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size) +static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) { drm_ttm_t *ttm; @@ -354,7 +353,8 @@ static int drm_ttm_lock_mmap_sem(drm_ttm_t * ttm) DRM_MEM_TTM); cur_count = shared_count + 10; mm_list = - drm_alloc(sizeof(*mm_list) * cur_count, DRM_MEM_TTM); + drm_alloc(sizeof(*mm_list) * cur_count, + DRM_MEM_TTM); if (!mm_list) return -ENOMEM; } @@ -489,7 +489,7 @@ void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry) if (be->needs_cache_adjust(be)) { int ret = drm_ttm_lock_mmap_sem(ttm); drm_ttm_lock_mm(ttm, 0, 1); - unmap_vma_pages(ttm, entry->page_offset, + unmap_vma_pages(ttm, entry->page_offset, entry->num_pages); drm_ttm_unlock_mm(ttm, 0, 1); drm_set_caching(ttm, entry->page_offset, @@ -542,7 +542,8 @@ int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset, if (!entry) return -ENOMEM; - be = ttm->dev->driver->bo_driver->create_ttm_backend_entry(ttm->dev, cached); + be = ttm->dev->driver->bo_driver->create_ttm_backend_entry(ttm->dev, + cached); if (!be) { drm_free(entry, sizeof(*entry), DRM_MEM_TTM); DRM_ERROR("Couldn't create backend.\n"); @@ -750,11 +751,10 @@ int drm_user_create_region(drm_device_t * dev, unsigned long start, int len, return 0; } - /* * dev->struct_mutex locked. */ -static void drm_ttm_object_remove(drm_device_t *dev, drm_ttm_object_t *object) +static void drm_ttm_object_remove(drm_device_t * dev, drm_ttm_object_t * object) { drm_map_list_t *list = &object->map_list; drm_local_map_t *map; @@ -765,7 +765,7 @@ static void drm_ttm_object_remove(drm_device_t *dev, drm_ttm_object_t *object) map = list->map; if (map) { - drm_ttm_t *ttm = (drm_ttm_t *)map->offset; + drm_ttm_t *ttm = (drm_ttm_t *) map->offset; if (ttm) { if (drm_destroy_ttm(ttm) != -EBUSY) { drm_free(map, sizeof(*map), DRM_MEM_TTM); @@ -778,15 +778,14 @@ static void drm_ttm_object_remove(drm_device_t *dev, drm_ttm_object_t *object) drm_free(object, sizeof(*object), DRM_MEM_TTM); } - -void drm_ttm_object_deref_locked(drm_device_t *dev, drm_ttm_object_t *to) +void drm_ttm_object_deref_locked(drm_device_t * dev, drm_ttm_object_t * to) { if (atomic_dec_and_test(&to->usage)) { drm_ttm_object_remove(dev, to); } } -void drm_ttm_object_deref_unlocked(drm_device_t *dev, drm_ttm_object_t *to) +void drm_ttm_object_deref_unlocked(drm_device_t * dev, drm_ttm_object_t * to) { if (atomic_dec_and_test(&to->usage)) { mutex_lock(&dev->struct_mutex); @@ -796,26 +795,25 @@ void drm_ttm_object_deref_unlocked(drm_device_t *dev, drm_ttm_object_t *to) } } - /* * dev->struct_mutex locked. */ -static void drm_ttm_user_deref_locked(drm_file_t *priv, drm_user_object_t *base) +static void drm_ttm_user_deref_locked(drm_file_t * priv, + drm_user_object_t * base) { drm_ttm_object_deref_locked(priv->head->dev, - drm_user_object_entry(base, drm_ttm_object_t, + drm_user_object_entry(base, + drm_ttm_object_t, base)); } - - /* * Create a ttm and add it to the drm book-keeping. * dev->struct_mutex locked. */ -int drm_ttm_object_create(drm_device_t *dev, unsigned long size, - uint32_t flags, drm_ttm_object_t **ttm_object) +int drm_ttm_object_create(drm_device_t * dev, unsigned long size, + uint32_t flags, drm_ttm_object_t ** ttm_object) { drm_ttm_object_t *object; drm_map_list_t *list; @@ -823,11 +821,11 @@ int drm_ttm_object_create(drm_device_t *dev, unsigned long size, drm_ttm_t *ttm; object = drm_calloc(1, sizeof(*object), DRM_MEM_TTM); - if (!object) + if (!object) return -ENOMEM; object->flags = flags; list = &object->map_list; - + list->map = drm_calloc(1, sizeof(*map), DRM_MEM_TTM); if (!list->map) { drm_ttm_object_remove(dev, object); @@ -847,9 +845,9 @@ int drm_ttm_object_create(drm_device_t *dev, unsigned long size, map->flags = _DRM_REMOVABLE; map->size = ttm->num_pages * PAGE_SIZE; map->handle = (void *)object; - - if (drm_ht_just_insert_please(&dev->map_hash, &list->hash, - (unsigned long) map->handle, + + if (drm_ht_just_insert_please(&dev->map_hash, &list->hash, + (unsigned long)map->handle, 32 - PAGE_SHIFT - 3, PAGE_SHIFT, DRM_MAP_HASH_OFFSET)) { drm_ttm_object_remove(dev, object); @@ -863,7 +861,7 @@ int drm_ttm_object_create(drm_device_t *dev, unsigned long size, return 0; } -drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t *priv, uint32_t handle, +drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t * priv, uint32_t handle, int check_owner) { drm_user_object_t *uo; @@ -871,7 +869,7 @@ drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t *priv, uint32_t handle, uo = drm_lookup_user_object(priv, handle); - if (!uo || (uo->type != drm_ttm_type)) + if (!uo || (uo->type != drm_ttm_type)) return NULL; if (check_owner && priv != uo->owner) { @@ -884,10 +882,9 @@ drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t *priv, uint32_t handle, return to; } - int drm_ttm_ioctl(DRM_IOCTL_ARGS) { - DRM_DEVICE; + DRM_DEVICE; drm_ttm_arg_t arg; drm_ttm_object_t *entry; drm_user_object_t *uo; @@ -895,8 +892,8 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) int ret; DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); - - switch(arg.op) { + + switch (arg.op) { case drm_ttm_create: mutex_lock(&dev->struct_mutex); size = arg.size; @@ -905,7 +902,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) mutex_unlock(&dev->struct_mutex); return ret; } - ret = drm_add_user_object(priv, &entry->base, + ret = drm_add_user_object(priv, &entry->base, arg.flags & DRM_TTM_FLAG_SHAREABLE); if (ret) { drm_ttm_object_remove(dev, entry); @@ -923,7 +920,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) if (ret) return ret; mutex_lock(&dev->struct_mutex); - entry = drm_lookup_ttm_object(priv, arg.handle , 0); + entry = drm_lookup_ttm_object(priv, arg.handle, 0); break; case drm_ttm_unreference: return drm_user_object_unref(priv, arg.handle, drm_ttm_type); -- cgit v1.2.3 From 4edb95d6e0a00a9a8885603cab2c99e3c6daa705 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 1 Sep 2006 11:23:21 +0200 Subject: Various bugfixes. --- linux-core/drm_ttm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 33567d9b..97e3e96d 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -447,6 +447,7 @@ int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) entry->num_pages); drm_ttm_unlock_mm(ttm, 0, 1); } + DRM_ERROR("Unbinding\n"); be->unbind(entry->be); if (ttm && be->needs_cache_adjust(be)) { drm_set_caching(ttm, entry->page_offset, -- cgit v1.2.3 From 405b5d9ca8cc9f6c5c7bb764c684bf74ba7660c6 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 1 Sep 2006 18:11:05 +0200 Subject: Flag bit pattern bugfixes. Remove some error messages. --- linux-core/drm_ttm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 97e3e96d..26133f9c 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -447,7 +447,9 @@ int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) entry->num_pages); drm_ttm_unlock_mm(ttm, 0, 1); } +#ifdef BODEBUG DRM_ERROR("Unbinding\n"); +#endif be->unbind(entry->be); if (ttm && be->needs_cache_adjust(be)) { drm_set_caching(ttm, entry->page_offset, -- cgit v1.2.3 From 99acb7936660843090ea8a9f22d2d50d9433e0de Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 8 Sep 2006 17:24:38 +0200 Subject: Various bugfixes. --- linux-core/drm_ttm.c | 63 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 8 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 26133f9c..a83d6401 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -42,6 +42,38 @@ typedef struct drm_val_action { int validated; } drm_val_action_t; +/* + * Use kmalloc if possible. Otherwise fall back to vmalloc. + */ + + +static void *ttm_alloc(unsigned long size, int type, int *do_vmalloc) +{ + void *ret = NULL; + + *do_vmalloc = 0; + if (size <= 4*PAGE_SIZE) { + ret = drm_alloc(size, type); + } + if (!ret) { + *do_vmalloc = 1; + ret = vmalloc(size); + } + return ret; +} + +static void ttm_free(void *pointer, unsigned long size, int type, + int do_vfree) +{ + if (!do_vfree) { + drm_free(pointer, size, type); + }else { + vfree(pointer); + } +} + + + /* * We may be manipulating other processes page tables, so for each TTM, keep track of * which mm_structs are currently mapping the ttm so that we can take the appropriate @@ -161,6 +193,7 @@ static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset, list_for_each(list, &ttm->vma_list->head) { drm_ttm_vma_list_t *entry = list_entry(list, drm_ttm_vma_list_t, head); + drm_clear_vma(entry->vma, entry->vma->vm_start + (page_offset << PAGE_SHIFT), @@ -205,7 +238,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) return -EBUSY; } - DRM_ERROR("Destroying a ttm\n"); + DRM_DEBUG("Destroying a ttm\n"); if (ttm->be_list) { list_for_each_safe(list, next, &ttm->be_list->head) { drm_ttm_backend_list_t *entry = @@ -231,12 +264,13 @@ int drm_destroy_ttm(drm_ttm_t * ttm) } } global_flush_tlb(); - vfree(ttm->pages); + ttm_free(ttm->pages, ttm->num_pages*sizeof(*ttm->pages), + DRM_MEM_TTM, ttm->pages_vmalloc); ttm->pages = NULL; } if (ttm->page_flags) { - vfree(ttm->page_flags); + ttm_free(ttm->page_flags, ttm->num_pages*sizeof(*ttm->page_flags), DRM_MEM_TTM, ttm->pf_vmalloc); ttm->page_flags = NULL; } @@ -280,7 +314,8 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) ttm->destroy = 0; ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - ttm->page_flags = vmalloc(ttm->num_pages * sizeof(*ttm->page_flags)); + ttm->page_flags = ttm_alloc(ttm->num_pages * sizeof(*ttm->page_flags), + DRM_MEM_TTM, &ttm->pf_vmalloc); if (!ttm->page_flags) { drm_destroy_ttm(ttm); DRM_ERROR("Failed allocating page_flags table\n"); @@ -288,7 +323,8 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) } memset(ttm->page_flags, 0, ttm->num_pages * sizeof(*ttm->page_flags)); - ttm->pages = vmalloc(ttm->num_pages * sizeof(*ttm->pages)); + ttm->pages = ttm_alloc(ttm->num_pages * sizeof(*ttm->pages), + DRM_MEM_TTM, &ttm->pages_vmalloc); if (!ttm->pages) { drm_destroy_ttm(ttm); DRM_ERROR("Failed allocating page table\n"); @@ -483,12 +519,13 @@ void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry) uint32_t *cur_page_flags; int i; - DRM_ERROR("Destroying a TTM region\n"); + DRM_DEBUG("Destroying a TTM region\n"); list_del_init(&entry->head); drm_unbind_ttm_region(entry); if (be) { be->clear(entry->be); +#if 0 /* Hmm, Isn't this done in unbind? */ if (be->needs_cache_adjust(be)) { int ret = drm_ttm_lock_mmap_sem(ttm); drm_ttm_lock_mm(ttm, 0, 1); @@ -500,6 +537,7 @@ void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry) if (!ret) drm_ttm_unlock_mm(ttm, 1, 0); } +#endif be->destroy(be); } cur_page_flags = ttm->page_flags + entry->page_offset; @@ -609,6 +647,12 @@ int drm_bind_ttm_region(drm_ttm_backend_list_t * region, ret = drm_ttm_lock_mmap_sem(ttm); if (ret) return ret; + + drm_ttm_lock_mm(ttm, 0, 1); + unmap_vma_pages(ttm, region->page_offset, + region->num_pages); + drm_ttm_unlock_mm(ttm, 0, 1); + drm_set_caching(ttm, region->page_offset, region->num_pages, DRM_TTM_PAGE_UNCACHED, 1); } else { @@ -676,7 +720,9 @@ void drm_user_destroy_region(drm_ttm_backend_list_t * entry) page_cache_release(*cur_page); cur_page++; } - vfree(entry->anon_pages); + ttm_free(entry->anon_pages, + sizeof(*entry->anon_pages)*entry->anon_locked, + DRM_MEM_TTM, entry->pages_vmalloc); } be->destroy(be); @@ -721,7 +767,8 @@ int drm_user_create_region(drm_device_t * dev, unsigned long start, int len, return -EFAULT; } - tmp->anon_pages = vmalloc(sizeof(*(tmp->anon_pages)) * len); + tmp->anon_pages = ttm_alloc(sizeof(*(tmp->anon_pages)) * len, + DRM_MEM_TTM, &tmp->pages_vmalloc); if (!tmp->anon_pages) { drm_user_destroy_region(tmp); -- cgit v1.2.3 From 191e284709ee792a32124e96e43d5876406b93dc Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 12 Sep 2006 12:01:00 +0200 Subject: More bugfixes. Disable the i915 IRQ turnoff for now since it seems to be causing problems. --- linux-core/drm_ttm.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index a83d6401..8aba36ca 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -251,19 +251,24 @@ int drm_destroy_ttm(drm_ttm_t * ttm) } if (ttm->pages) { + drm_buffer_manager_t *bm = &ttm->dev->bm; + int do_tlbflush = 0; for (i = 0; i < ttm->num_pages; ++i) { cur_page = ttm->pages + i; if (ttm->page_flags && (ttm->page_flags[i] & DRM_TTM_PAGE_UNCACHED) && *cur_page && !PageHighMem(*cur_page)) { change_page_attr(*cur_page, 1, PAGE_KERNEL); + do_tlbflush = 1; } if (*cur_page) { ClearPageReserved(*cur_page); __free_page(*cur_page); + --bm->cur_pages; } } - global_flush_tlb(); + if (do_tlbflush) + global_flush_tlb(); ttm_free(ttm->pages, ttm->num_pages*sizeof(*ttm->pages), DRM_MEM_TTM, ttm->pages_vmalloc); ttm->pages = NULL; @@ -308,6 +313,7 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) if (!ttm) return NULL; + ttm->dev = dev; ttm->lhandle = 0; atomic_set(&ttm->vma_count, 0); @@ -354,7 +360,6 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) INIT_LIST_HEAD(&ttm->vma_list->head); ttm->lhandle = (unsigned long)ttm; - ttm->dev = dev; return ttm; } @@ -562,6 +567,7 @@ int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset, drm_ttm_backend_list_t *entry; drm_ttm_backend_t *be; int ret, i; + drm_buffer_manager_t *bm = &ttm->dev->bm; if ((page_offset + n_pages) > ttm->num_pages || n_pages == 0) { DRM_ERROR("Region Doesn't fit ttm\n"); @@ -602,6 +608,11 @@ int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset, for (i = 0; i < entry->num_pages; ++i) { cur_page = ttm->pages + (page_offset + i); if (!*cur_page) { + if (bm->cur_pages >= bm->max_pages) { + DRM_ERROR("Maximum locked page count exceeded\n"); + drm_destroy_ttm_region(entry); + return -ENOMEM; + } *cur_page = alloc_page(GFP_KERNEL); if (!*cur_page) { DRM_ERROR("Page allocation failed\n"); @@ -609,6 +620,7 @@ int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset, return -ENOMEM; } SetPageReserved(*cur_page); + ++bm->cur_pages; } } -- cgit v1.2.3 From 9adc9584a7e0b61b16a943720bef31a71faeaef4 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 12 Sep 2006 17:39:44 +0200 Subject: Fix some debug messages. --- linux-core/drm_ttm.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 8aba36ca..889e0001 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -488,9 +488,6 @@ int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) entry->num_pages); drm_ttm_unlock_mm(ttm, 0, 1); } -#ifdef BODEBUG - DRM_ERROR("Unbinding\n"); -#endif be->unbind(entry->be); if (ttm && be->needs_cache_adjust(be)) { drm_set_caching(ttm, entry->page_offset, -- cgit v1.2.3 From 682c6ed0293771b093452597540118f47fda1adf Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 14 Sep 2006 12:17:38 +0200 Subject: Remove the use of reserved pages, and use locked pages instead. Update compatibility for latest linux versions. --- linux-core/drm_ttm.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 889e0001..cd95e311 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -199,6 +199,7 @@ static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset, (page_offset << PAGE_SHIFT), entry->vma->vm_start + ((page_offset + num_pages) << PAGE_SHIFT)); + #if !defined(flush_tlb_mm) && defined(MODULE) flush_tlb = 1; #endif @@ -209,7 +210,7 @@ static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset, #endif for (cur_page = first_page; cur_page != last_page; ++cur_page) { - if (page_mapcount(*cur_page) != 0) { + if (page_mapped(*cur_page)) { DRM_ERROR("Mapped page detected. Map count is %d\n", page_mapcount(*cur_page)); return -1; @@ -239,6 +240,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) } DRM_DEBUG("Destroying a ttm\n"); + if (ttm->be_list) { list_for_each_safe(list, next, &ttm->be_list->head) { drm_ttm_backend_list_t *entry = @@ -262,7 +264,22 @@ int drm_destroy_ttm(drm_ttm_t * ttm) do_tlbflush = 1; } if (*cur_page) { - ClearPageReserved(*cur_page); + ClearPageLocked(*cur_page); + + /* + * Debugging code. Remove if the error message never + * shows up. + */ + + if (page_count(*cur_page) != 1) { + DRM_ERROR("Erroneous page count. " + "Leaking pages.\n"); + } + + /* + * End debugging. + */ + __free_page(*cur_page); --bm->cur_pages; } @@ -526,20 +543,7 @@ void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry) drm_unbind_ttm_region(entry); if (be) { - be->clear(entry->be); -#if 0 /* Hmm, Isn't this done in unbind? */ - if (be->needs_cache_adjust(be)) { - int ret = drm_ttm_lock_mmap_sem(ttm); - drm_ttm_lock_mm(ttm, 0, 1); - unmap_vma_pages(ttm, entry->page_offset, - entry->num_pages); - drm_ttm_unlock_mm(ttm, 0, 1); - drm_set_caching(ttm, entry->page_offset, - entry->num_pages, 0, 1); - if (!ret) - drm_ttm_unlock_mm(ttm, 1, 0); - } -#endif + be->clear(be); be->destroy(be); } cur_page_flags = ttm->page_flags + entry->page_offset; @@ -616,7 +620,7 @@ int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset, drm_destroy_ttm_region(entry); return -ENOMEM; } - SetPageReserved(*cur_page); + SetPageLocked(*cur_page); ++bm->cur_pages; } } -- cgit v1.2.3 From 7223b4e264a64df2df70715d8777f2ccaa883d5e Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 14 Sep 2006 16:42:00 +0200 Subject: Simplify ttm alloc and free. --- linux-core/drm_ttm.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index cd95e311..f72e7d30 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -47,31 +47,29 @@ typedef struct drm_val_action { */ -static void *ttm_alloc(unsigned long size, int type, int *do_vmalloc) +static void *ttm_alloc(unsigned long size, int type) { void *ret = NULL; - *do_vmalloc = 0; if (size <= 4*PAGE_SIZE) { ret = drm_alloc(size, type); } if (!ret) { - *do_vmalloc = 1; ret = vmalloc(size); } return ret; } - -static void ttm_free(void *pointer, unsigned long size, int type, - int do_vfree) + +static void ttm_free(void *pointer, unsigned long size, int type) { - if (!do_vfree) { - drm_free(pointer, size, type); - }else { + + if ((unsigned long) pointer >= VMALLOC_START && + (unsigned long) pointer <= VMALLOC_END) { vfree(pointer); + } else { + drm_free(pointer, size, type); } -} - +} /* @@ -287,12 +285,12 @@ int drm_destroy_ttm(drm_ttm_t * ttm) if (do_tlbflush) global_flush_tlb(); ttm_free(ttm->pages, ttm->num_pages*sizeof(*ttm->pages), - DRM_MEM_TTM, ttm->pages_vmalloc); + DRM_MEM_TTM); ttm->pages = NULL; } if (ttm->page_flags) { - ttm_free(ttm->page_flags, ttm->num_pages*sizeof(*ttm->page_flags), DRM_MEM_TTM, ttm->pf_vmalloc); + ttm_free(ttm->page_flags, ttm->num_pages*sizeof(*ttm->page_flags), DRM_MEM_TTM); ttm->page_flags = NULL; } @@ -338,7 +336,7 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; ttm->page_flags = ttm_alloc(ttm->num_pages * sizeof(*ttm->page_flags), - DRM_MEM_TTM, &ttm->pf_vmalloc); + DRM_MEM_TTM); if (!ttm->page_flags) { drm_destroy_ttm(ttm); DRM_ERROR("Failed allocating page_flags table\n"); @@ -347,7 +345,7 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) memset(ttm->page_flags, 0, ttm->num_pages * sizeof(*ttm->page_flags)); ttm->pages = ttm_alloc(ttm->num_pages * sizeof(*ttm->pages), - DRM_MEM_TTM, &ttm->pages_vmalloc); + DRM_MEM_TTM); if (!ttm->pages) { drm_destroy_ttm(ttm); DRM_ERROR("Failed allocating page table\n"); @@ -735,7 +733,7 @@ void drm_user_destroy_region(drm_ttm_backend_list_t * entry) } ttm_free(entry->anon_pages, sizeof(*entry->anon_pages)*entry->anon_locked, - DRM_MEM_TTM, entry->pages_vmalloc); + DRM_MEM_TTM); } be->destroy(be); @@ -781,7 +779,7 @@ int drm_user_create_region(drm_device_t * dev, unsigned long start, int len, } tmp->anon_pages = ttm_alloc(sizeof(*(tmp->anon_pages)) * len, - DRM_MEM_TTM, &tmp->pages_vmalloc); + DRM_MEM_TTM); if (!tmp->anon_pages) { drm_user_destroy_region(tmp); -- cgit v1.2.3 From 235f6fc650e9974211843b9196a903963dae0211 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 27 Sep 2006 09:27:31 +0200 Subject: Adapt to architecture-specific hooks for gatt pages. --- linux-core/drm_ttm.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index f72e7d30..6790c886 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -170,7 +170,6 @@ static int ioremap_vmas(drm_ttm_t * ttm, unsigned long page_offset, if (ret) break; } - global_flush_tlb(); return ret; } @@ -182,9 +181,7 @@ static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset, unsigned long num_pages) { struct list_head *list; - struct page **first_page = ttm->pages + page_offset; - struct page **last_page = ttm->pages + (page_offset + num_pages); - struct page **cur_page; + #if !defined(flush_tlb_mm) && defined(MODULE) int flush_tlb = 0; #endif @@ -207,13 +204,6 @@ static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset, global_flush_tlb(); #endif - for (cur_page = first_page; cur_page != last_page; ++cur_page) { - if (page_mapped(*cur_page)) { - DRM_ERROR("Mapped page detected. Map count is %d\n", - page_mapcount(*cur_page)); - return -1; - } - } return 0; } @@ -258,7 +248,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) if (ttm->page_flags && (ttm->page_flags[i] & DRM_TTM_PAGE_UNCACHED) && *cur_page && !PageHighMem(*cur_page)) { - change_page_attr(*cur_page, 1, PAGE_KERNEL); + unmap_page_from_agp(*cur_page); do_tlbflush = 1; } if (*cur_page) { @@ -278,19 +268,20 @@ int drm_destroy_ttm(drm_ttm_t * ttm) * End debugging. */ - __free_page(*cur_page); + drm_free_gatt_pages(*cur_page, 0); --bm->cur_pages; } } if (do_tlbflush) - global_flush_tlb(); + flush_agp_mappings(); ttm_free(ttm->pages, ttm->num_pages*sizeof(*ttm->pages), DRM_MEM_TTM); ttm->pages = NULL; } if (ttm->page_flags) { - ttm_free(ttm->page_flags, ttm->num_pages*sizeof(*ttm->page_flags), DRM_MEM_TTM); + ttm_free(ttm->page_flags, ttm->num_pages*sizeof(*ttm->page_flags), + DRM_MEM_TTM); ttm->page_flags = NULL; } @@ -455,7 +446,6 @@ static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset, { int i, cur; struct page **cur_page; - pgprot_t attr = (noncached) ? PAGE_KERNEL_NOCACHE : PAGE_KERNEL; for (i = 0; i < num_pages; ++i) { cur = page_offset + i; @@ -472,12 +462,16 @@ static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset, DRM_TTM_PAGE_UNCACHED) != noncached) { DRM_MASK_VAL(ttm->page_flags[cur], DRM_TTM_PAGE_UNCACHED, noncached); - change_page_attr(*cur_page, 1, attr); + if (noncached) { + map_page_into_agp(*cur_page); + } else { + unmap_page_from_agp(*cur_page); + } } } } if (do_tlbflush) - global_flush_tlb(); + flush_agp_mappings(); return 0; } @@ -612,7 +606,7 @@ int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset, drm_destroy_ttm_region(entry); return -ENOMEM; } - *cur_page = alloc_page(GFP_KERNEL); + *cur_page = drm_alloc_gatt_pages(0); if (!*cur_page) { DRM_ERROR("Page allocation failed\n"); drm_destroy_ttm_region(entry); -- cgit v1.2.3 From d85b99435f0ea7a17b3b7be31b53c00632c07177 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 2 Oct 2006 13:49:43 +0200 Subject: Allow for 44 bit user-tokens (or drm_file offsets) --- linux-core/drm_ttm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 6790c886..5fbe283e 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -903,13 +903,13 @@ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, if (drm_ht_just_insert_please(&dev->map_hash, &list->hash, (unsigned long)map->handle, - 32 - PAGE_SHIFT - 3, PAGE_SHIFT, - DRM_MAP_HASH_OFFSET)) { + 32 - PAGE_SHIFT - 3, 0, + DRM_MAP_HASH_OFFSET >> PAGE_SHIFT)) { drm_ttm_object_remove(dev, object); return -ENOMEM; } - list->user_token = list->hash.key; + list->user_token = list->hash.key << PAGE_SHIFT; atomic_set(&object->usage, 1); *ttm_object = object; -- cgit v1.2.3 From eacedf41a65f135722e7bee6f1a66a803619237f Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 2 Oct 2006 15:06:35 +0200 Subject: Make the user_token 44-bit for TTMs, and have them occupy a unique file space starting at 0x00100000000. This will hopefully allow us to use unmap_mapping_range(). Note that user-space will need 64-bit file offset support. --- linux-core/drm_ttm.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 5fbe283e..311c57fa 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -817,6 +817,11 @@ static void drm_ttm_object_remove(drm_device_t * dev, drm_ttm_object_t * object) if (list->user_token) drm_ht_remove_item(&dev->map_hash, &list->hash); + if (list->file_offset_node) { + drm_mm_put_block(&dev->offset_manager, list->file_offset_node); + list->file_offset_node = NULL; + } + map = list->map; if (map) { @@ -901,15 +906,24 @@ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, map->size = ttm->num_pages * PAGE_SIZE; map->handle = (void *)object; - if (drm_ht_just_insert_please(&dev->map_hash, &list->hash, - (unsigned long)map->handle, - 32 - PAGE_SHIFT - 3, 0, - DRM_MAP_HASH_OFFSET >> PAGE_SHIFT)) { + list->file_offset_node = drm_mm_search_free(&dev->offset_manager, + ttm->num_pages, + 0,0); + if (!list->file_offset_node) { + drm_ttm_object_remove(dev, object); + return -ENOMEM; + } + list->file_offset_node = drm_mm_get_block(list->file_offset_node, + ttm->num_pages,0); + + list->hash.key = list->file_offset_node->start; + + if (drm_ht_insert_item(&dev->map_hash, &list->hash)) { drm_ttm_object_remove(dev, object); return -ENOMEM; } - list->user_token = list->hash.key << PAGE_SHIFT; + list->user_token = ((drm_u64_t) list->hash.key) << PAGE_SHIFT; atomic_set(&object->usage, 1); *ttm_object = object; -- cgit v1.2.3 From cee659afb56e7ac443402ac791144f391721061e Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 3 Oct 2006 12:08:07 +0200 Subject: Get rid of all ugly PTE hacks. --- linux-core/drm_ttm.c | 77 +++++++++++++--------------------------------------- 1 file changed, 19 insertions(+), 58 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 311c57fa..ed50da90 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -123,31 +123,12 @@ void drm_ttm_delete_mm(drm_ttm_t * ttm, struct mm_struct *mm) BUG_ON(1); } -static void drm_ttm_lock_mm(drm_ttm_t * ttm, int mm_sem, int page_table) +static void drm_ttm_unlock_mm(drm_ttm_t * ttm) { p_mm_entry_t *entry; list_for_each_entry(entry, &ttm->p_mm_list, head) { - if (mm_sem) { - down_write(&entry->mm->mmap_sem); - } - if (page_table) { - spin_lock(&entry->mm->page_table_lock); - } - } -} - -static void drm_ttm_unlock_mm(drm_ttm_t * ttm, int mm_sem, int page_table) -{ - p_mm_entry_t *entry; - - list_for_each_entry(entry, &ttm->p_mm_list, head) { - if (page_table) { - spin_unlock(&entry->mm->page_table_lock); - } - if (mm_sem) { - up_write(&entry->mm->mmap_sem); - } + up_write(&entry->mm->mmap_sem); } } @@ -180,30 +161,13 @@ static int ioremap_vmas(drm_ttm_t * ttm, unsigned long page_offset, static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset, unsigned long num_pages) { - struct list_head *list; - -#if !defined(flush_tlb_mm) && defined(MODULE) - int flush_tlb = 0; -#endif - list_for_each(list, &ttm->vma_list->head) { - drm_ttm_vma_list_t *entry = - list_entry(list, drm_ttm_vma_list_t, head); - - drm_clear_vma(entry->vma, - entry->vma->vm_start + - (page_offset << PAGE_SHIFT), - entry->vma->vm_start + - ((page_offset + num_pages) << PAGE_SHIFT)); - -#if !defined(flush_tlb_mm) && defined(MODULE) - flush_tlb = 1; -#endif - } -#if !defined(flush_tlb_mm) && defined(MODULE) - if (flush_tlb) - global_flush_tlb(); -#endif + drm_device_t *dev = ttm->dev; + loff_t offset = ((loff_t) ttm->mapping_offset + page_offset) + << PAGE_SHIFT; + loff_t holelen = num_pages << PAGE_SHIFT; + + unmap_mapping_range(dev->dev_mapping, offset, holelen, 1); return 0; } @@ -437,15 +401,16 @@ static int drm_ttm_lock_mmap_sem(drm_ttm_t * ttm) } /* - * Change caching policy for range of pages in a ttm. + * Change caching policy for the linear kernel map + * for range of pages in a ttm. */ static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset, - unsigned long num_pages, int noncached, - int do_tlbflush) + unsigned long num_pages, int noncached) { int i, cur; struct page **cur_page; + int do_tlbflush = 0; for (i = 0; i < num_pages; ++i) { cur = page_offset + i; @@ -467,6 +432,7 @@ static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset, } else { unmap_page_from_agp(*cur_page); } + do_tlbflush = 1; } } } @@ -492,16 +458,14 @@ int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) ret = drm_ttm_lock_mmap_sem(ttm); if (ret) return ret; - drm_ttm_lock_mm(ttm, 0, 1); unmap_vma_pages(ttm, entry->page_offset, entry->num_pages); - drm_ttm_unlock_mm(ttm, 0, 1); } be->unbind(entry->be); if (ttm && be->needs_cache_adjust(be)) { drm_set_caching(ttm, entry->page_offset, - entry->num_pages, 0, 1); - drm_ttm_unlock_mm(ttm, 1, 0); + entry->num_pages, 0); + drm_ttm_unlock_mm(ttm); } break; default: @@ -653,20 +617,17 @@ int drm_bind_ttm_region(drm_ttm_backend_list_t * region, if (ret) return ret; - drm_ttm_lock_mm(ttm, 0, 1); unmap_vma_pages(ttm, region->page_offset, region->num_pages); - drm_ttm_unlock_mm(ttm, 0, 1); - drm_set_caching(ttm, region->page_offset, region->num_pages, - DRM_TTM_PAGE_UNCACHED, 1); + DRM_TTM_PAGE_UNCACHED); } else { DRM_DEBUG("Binding cached\n"); } if ((ret = be->bind(be, aper_offset))) { if (ttm && be->needs_cache_adjust(be)) - drm_ttm_unlock_mm(ttm, 1, 0); + drm_ttm_unlock_mm(ttm); drm_unbind_ttm_region(region); DRM_ERROR("Couldn't bind backend.\n"); return ret; @@ -682,7 +643,7 @@ int drm_bind_ttm_region(drm_ttm_backend_list_t * region, if (ttm && be->needs_cache_adjust(be)) { ioremap_vmas(ttm, region->page_offset, region->num_pages, aper_offset); - drm_ttm_unlock_mm(ttm, 1, 0); + drm_ttm_unlock_mm(ttm); } region->state = ttm_bound; @@ -924,7 +885,7 @@ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, } list->user_token = ((drm_u64_t) list->hash.key) << PAGE_SHIFT; - + ttm->mapping_offset = list->hash.key; atomic_set(&object->usage, 1); *ttm_object = object; return 0; -- cgit v1.2.3 From c58574c60505a699e19e1ed59e1b441be2594e53 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 10 Oct 2006 10:37:26 +0200 Subject: Use a nopage-based approach to fault in pfns. --- linux-core/drm_ttm.c | 175 ++------------------------------------------------- 1 file changed, 5 insertions(+), 170 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index ed50da90..51e28ac4 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -71,89 +71,6 @@ static void ttm_free(void *pointer, unsigned long size, int type) } } - -/* - * We may be manipulating other processes page tables, so for each TTM, keep track of - * which mm_structs are currently mapping the ttm so that we can take the appropriate - * locks when we modify their page tables. A typical application is when we evict another - * process' buffers. - */ - -int drm_ttm_add_mm_to_list(drm_ttm_t * ttm, struct mm_struct *mm) -{ - p_mm_entry_t *entry, *n_entry; - - list_for_each_entry(entry, &ttm->p_mm_list, head) { - if (mm == entry->mm) { - atomic_inc(&entry->refcount); - return 0; - } else if ((unsigned long)mm < (unsigned long)entry->mm) ; - } - - n_entry = drm_alloc(sizeof(*n_entry), DRM_MEM_TTM); - if (!entry) { - DRM_ERROR("Allocation of process mm pointer entry failed\n"); - return -ENOMEM; - } - INIT_LIST_HEAD(&n_entry->head); - n_entry->mm = mm; - atomic_set(&n_entry->refcount, 0); - atomic_inc(&ttm->shared_count); - ttm->mm_list_seq++; - - list_add_tail(&n_entry->head, &entry->head); - - return 0; -} - -void drm_ttm_delete_mm(drm_ttm_t * ttm, struct mm_struct *mm) -{ - p_mm_entry_t *entry, *n; - list_for_each_entry_safe(entry, n, &ttm->p_mm_list, head) { - if (mm == entry->mm) { - if (atomic_add_negative(-1, &entry->refcount)) { - list_del(&entry->head); - drm_free(entry, sizeof(*entry), DRM_MEM_TTM); - atomic_dec(&ttm->shared_count); - ttm->mm_list_seq++; - } - return; - } - } - BUG_ON(1); -} - -static void drm_ttm_unlock_mm(drm_ttm_t * ttm) -{ - p_mm_entry_t *entry; - - list_for_each_entry(entry, &ttm->p_mm_list, head) { - up_write(&entry->mm->mmap_sem); - } -} - -static int ioremap_vmas(drm_ttm_t * ttm, unsigned long page_offset, - unsigned long num_pages, unsigned long aper_offset) -{ - struct list_head *list; - int ret = 0; - - list_for_each(list, &ttm->vma_list->head) { - drm_ttm_vma_list_t *entry = - list_entry(list, drm_ttm_vma_list_t, head); - - ret = io_remap_pfn_range(entry->vma, - entry->vma->vm_start + - (page_offset << PAGE_SHIFT), - (ttm->aperture_base >> PAGE_SHIFT) + - aper_offset, num_pages << PAGE_SHIFT, - drm_io_prot(_DRM_AGP, entry->vma)); - if (ret) - break; - } - return ret; -} - /* * Unmap all vma pages from vmas mapping this ttm. */ @@ -216,17 +133,15 @@ int drm_destroy_ttm(drm_ttm_t * ttm) do_tlbflush = 1; } if (*cur_page) { - ClearPageLocked(*cur_page); - - /* - * Debugging code. Remove if the error message never - * shows up. - */ - + unlock_page(*cur_page); if (page_count(*cur_page) != 1) { DRM_ERROR("Erroneous page count. " "Leaking pages.\n"); } + if (page_mapped(*cur_page)) { + DRM_ERROR("Erroneous map count. " + "Leaking page mappings.\n"); + } /* * End debugging. @@ -334,72 +249,6 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) return ttm; } -/* - * Lock the mmap_sems for processes that are mapping this ttm. - * This looks a bit clumsy, since we need to maintain the correct - * locking order - * mm->mmap_sem - * dev->struct_sem; - * and while we release dev->struct_sem to lock the mmap_sems, - * the mmap_sem list may have been updated. We need to revalidate - * it after relocking dev->struc_sem. - */ - -static int drm_ttm_lock_mmap_sem(drm_ttm_t * ttm) -{ - struct mm_struct **mm_list = NULL, **mm_list_p; - uint32_t list_seq; - uint32_t cur_count, shared_count; - p_mm_entry_t *entry; - unsigned i; - - cur_count = 0; - list_seq = ttm->mm_list_seq; - shared_count = atomic_read(&ttm->shared_count); - - do { - if (shared_count > cur_count) { - if (mm_list) - drm_free(mm_list, sizeof(*mm_list) * cur_count, - DRM_MEM_TTM); - cur_count = shared_count + 10; - mm_list = - drm_alloc(sizeof(*mm_list) * cur_count, - DRM_MEM_TTM); - if (!mm_list) - return -ENOMEM; - } - - mm_list_p = mm_list; - list_for_each_entry(entry, &ttm->p_mm_list, head) { - *mm_list_p++ = entry->mm; - } - - mutex_unlock(&ttm->dev->struct_mutex); - mm_list_p = mm_list; - for (i = 0; i < shared_count; ++i, ++mm_list_p) { - down_write(&((*mm_list_p)->mmap_sem)); - } - - mutex_lock(&ttm->dev->struct_mutex); - - if (list_seq != ttm->mm_list_seq) { - mm_list_p = mm_list; - for (i = 0; i < shared_count; ++i, ++mm_list_p) { - up_write(&((*mm_list_p)->mmap_sem)); - } - - } - shared_count = atomic_read(&ttm->shared_count); - - } while (list_seq != ttm->mm_list_seq); - - if (mm_list) - drm_free(mm_list, sizeof(*mm_list) * cur_count, DRM_MEM_TTM); - - return 0; -} - /* * Change caching policy for the linear kernel map * for range of pages in a ttm. @@ -449,15 +298,11 @@ int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) { drm_ttm_backend_t *be = entry->be; drm_ttm_t *ttm = entry->owner; - int ret; if (be) { switch (entry->state) { case ttm_bound: if (ttm && be->needs_cache_adjust(be)) { - ret = drm_ttm_lock_mmap_sem(ttm); - if (ret) - return ret; unmap_vma_pages(ttm, entry->page_offset, entry->num_pages); } @@ -465,7 +310,6 @@ int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) if (ttm && be->needs_cache_adjust(be)) { drm_set_caching(ttm, entry->page_offset, entry->num_pages, 0); - drm_ttm_unlock_mm(ttm); } break; default: @@ -613,7 +457,6 @@ int drm_bind_ttm_region(drm_ttm_backend_list_t * region, ttm = region->owner; if (ttm && be->needs_cache_adjust(be)) { - ret = drm_ttm_lock_mmap_sem(ttm); if (ret) return ret; @@ -626,8 +469,6 @@ int drm_bind_ttm_region(drm_ttm_backend_list_t * region, } if ((ret = be->bind(be, aper_offset))) { - if (ttm && be->needs_cache_adjust(be)) - drm_ttm_unlock_mm(ttm); drm_unbind_ttm_region(region); DRM_ERROR("Couldn't bind backend.\n"); return ret; @@ -640,12 +481,6 @@ int drm_bind_ttm_region(drm_ttm_backend_list_t * region, cur_page_flag++; } - if (ttm && be->needs_cache_adjust(be)) { - ioremap_vmas(ttm, region->page_offset, region->num_pages, - aper_offset); - drm_ttm_unlock_mm(ttm); - } - region->state = ttm_bound; return 0; } -- cgit v1.2.3 From f2db76e2f206d2017f710eaddc4b33add4498898 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 11 Oct 2006 13:40:35 +0200 Subject: Big update: Adapt for new functions in the 2.6.19 kernel. Remove the ability to have multiple regions in one TTM. This simplifies a lot of code. Remove the ability to access TTMs from user space. We don't need it anymore without ttm regions. Don't change caching policy for evicted buffers. Instead change it only when the buffer is accessed by the CPU (on the first page fault). This tremendously speeds up eviction rates. Current code is safe for kernels <= 2.6.14. Should also be OK with 2.6.19 and above. --- linux-core/drm_ttm.c | 649 +++++++++++---------------------------------------- 1 file changed, 141 insertions(+), 508 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 51e28ac4..297d4f71 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -27,20 +27,6 @@ **************************************************************************/ #include "drmP.h" -#include - -typedef struct p_mm_entry { - struct list_head head; - struct mm_struct *mm; - atomic_t refcount; -} p_mm_entry_t; - -typedef struct drm_val_action { - int needs_rx_flush; - int evicted_tt; - int evicted_vram; - int validated; -} drm_val_action_t; /* * Use kmalloc if possible. Otherwise fall back to vmalloc. @@ -75,19 +61,51 @@ static void ttm_free(void *pointer, unsigned long size, int type) * Unmap all vma pages from vmas mapping this ttm. */ -static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset, - unsigned long num_pages) +static int unmap_vma_pages(drm_ttm_t * ttm) { drm_device_t *dev = ttm->dev; - loff_t offset = ((loff_t) ttm->mapping_offset + page_offset) - << PAGE_SHIFT; - loff_t holelen = num_pages << PAGE_SHIFT; + loff_t offset = ((loff_t) ttm->mapping_offset) << PAGE_SHIFT; + loff_t holelen = ((loff_t) ttm->num_pages) << PAGE_SHIFT; - unmap_mapping_range(dev->dev_mapping, offset, holelen, 1); return 0; } +/* + * Change caching policy for the linear kernel map + * for range of pages in a ttm. + */ + +static int drm_set_caching(drm_ttm_t * ttm, int noncached) +{ + int i; + struct page **cur_page; + int do_tlbflush = 0; + + if ((ttm->page_flags & DRM_TTM_PAGE_UNCACHED) == noncached) + return 0; + + for (i = 0; i < ttm->num_pages; ++i) { + cur_page = ttm->pages + i; + if (*cur_page) { + if (!PageHighMem(*cur_page)) { + if (noncached) { + map_page_into_agp(*cur_page); + } else { + unmap_page_from_agp(*cur_page); + } + do_tlbflush = 1; + } + } + } + if (do_tlbflush) + flush_agp_mappings(); + + DRM_MASK_VAL(ttm->page_flags, DRM_TTM_PAGE_UNCACHED, noncached); + + return 0; +} + /* * Free all resources associated with a ttm. */ @@ -96,8 +114,8 @@ int drm_destroy_ttm(drm_ttm_t * ttm) { int i; - struct list_head *list, *next; struct page **cur_page; + drm_ttm_backend_t *be; if (!ttm) return 0; @@ -110,30 +128,26 @@ int drm_destroy_ttm(drm_ttm_t * ttm) DRM_DEBUG("Destroying a ttm\n"); - if (ttm->be_list) { - list_for_each_safe(list, next, &ttm->be_list->head) { - drm_ttm_backend_list_t *entry = - list_entry(list, drm_ttm_backend_list_t, head); - drm_destroy_ttm_region(entry); - } + be = ttm->be; - drm_free(ttm->be_list, sizeof(*ttm->be_list), DRM_MEM_TTM); - ttm->be_list = NULL; + if (be) { + be->destroy(be); + ttm->be = NULL; } if (ttm->pages) { drm_buffer_manager_t *bm = &ttm->dev->bm; - int do_tlbflush = 0; + if (ttm->page_flags & DRM_TTM_PAGE_UNCACHED) + drm_set_caching(ttm, 0); + for (i = 0; i < ttm->num_pages; ++i) { cur_page = ttm->pages + i; - if (ttm->page_flags && - (ttm->page_flags[i] & DRM_TTM_PAGE_UNCACHED) && - *cur_page && !PageHighMem(*cur_page)) { - unmap_page_from_agp(*cur_page); - do_tlbflush = 1; - } if (*cur_page) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)) unlock_page(*cur_page); +#else + ClearPageReserved(*cur_page); +#endif if (page_count(*cur_page) != 1) { DRM_ERROR("Erroneous page count. " "Leaking pages.\n"); @@ -151,47 +165,66 @@ int drm_destroy_ttm(drm_ttm_t * ttm) --bm->cur_pages; } } - if (do_tlbflush) - flush_agp_mappings(); ttm_free(ttm->pages, ttm->num_pages*sizeof(*ttm->pages), DRM_MEM_TTM); ttm->pages = NULL; } - if (ttm->page_flags) { - ttm_free(ttm->page_flags, ttm->num_pages*sizeof(*ttm->page_flags), - DRM_MEM_TTM); - ttm->page_flags = NULL; - } - - if (ttm->vma_list) { - list_for_each_safe(list, next, &ttm->vma_list->head) { - drm_ttm_vma_list_t *entry = - list_entry(list, drm_ttm_vma_list_t, head); - list_del(list); - entry->vma->vm_private_data = NULL; - drm_free(entry, sizeof(*entry), DRM_MEM_TTM); - } - drm_free(ttm->vma_list, sizeof(*ttm->vma_list), DRM_MEM_TTM); - ttm->vma_list = NULL; - } - drm_free(ttm, sizeof(*ttm), DRM_MEM_TTM); return 0; } +static int drm_ttm_populate(drm_ttm_t *ttm) +{ + struct page *page; + unsigned long i; + drm_buffer_manager_t *bm; + drm_ttm_backend_t *be; + + + if (ttm->state != ttm_unpopulated) + return 0; + + bm = &ttm->dev->bm; + be = ttm->be; + for (i=0; inum_pages; ++i) { + page = ttm->pages[i]; + if (!page) { + if (bm->cur_pages >= bm->max_pages) { + DRM_ERROR("Maximum locked page count exceeded\n"); + return -ENOMEM; + } + page = drm_alloc_gatt_pages(0); + if (!page) + return -ENOMEM; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)) + SetPageLocked(page); +#else + SetPageReserved(page); +#endif + ttm->pages[i] = page; + ++bm->cur_pages; + } + } + be->populate(be, ttm->num_pages, ttm->pages); + ttm->state = ttm_unbound; + return 0; +} + + + /* * Initialize a ttm. - * FIXME: Avoid using vmalloc for the page- and page_flags tables? */ -static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) +static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size, + int cached) { - + drm_bo_driver_t *bo_driver = dev->driver->bo_driver; drm_ttm_t *ttm; - if (!dev->driver->bo_driver) + if (!bo_driver) return NULL; ttm = drm_calloc(1, sizeof(*ttm), DRM_MEM_TTM); @@ -199,21 +232,12 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) return NULL; ttm->dev = dev; - ttm->lhandle = 0; atomic_set(&ttm->vma_count, 0); ttm->destroy = 0; ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - ttm->page_flags = ttm_alloc(ttm->num_pages * sizeof(*ttm->page_flags), - DRM_MEM_TTM); - if (!ttm->page_flags) { - drm_destroy_ttm(ttm); - DRM_ERROR("Failed allocating page_flags table\n"); - return NULL; - } - memset(ttm->page_flags, 0, ttm->num_pages * sizeof(*ttm->page_flags)); - + ttm->page_flags = 0; ttm->pages = ttm_alloc(ttm->num_pages * sizeof(*ttm->pages), DRM_MEM_TTM); if (!ttm->pages) { @@ -222,382 +246,86 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) return NULL; } memset(ttm->pages, 0, ttm->num_pages * sizeof(*ttm->pages)); - - ttm->be_list = drm_calloc(1, sizeof(*ttm->be_list), DRM_MEM_TTM); - if (!ttm->be_list) { - DRM_ERROR("Alloc be regions failed\n"); - drm_destroy_ttm(ttm); - return NULL; - } - - INIT_LIST_HEAD(&ttm->be_list->head); - INIT_LIST_HEAD(&ttm->p_mm_list); - atomic_set(&ttm->shared_count, 0); - ttm->mm_list_seq = 0; - - ttm->vma_list = drm_calloc(1, sizeof(*ttm->vma_list), DRM_MEM_TTM); - if (!ttm->vma_list) { - DRM_ERROR("Alloc vma list failed\n"); + ttm->be = bo_driver->create_ttm_backend_entry(dev, cached); + if (!ttm->be) { drm_destroy_ttm(ttm); + DRM_ERROR("Failed creating ttm backend entry\n"); return NULL; } - - INIT_LIST_HEAD(&ttm->vma_list->head); - - ttm->lhandle = (unsigned long)ttm; - + ttm->state = ttm_unpopulated; return ttm; } /* - * Change caching policy for the linear kernel map - * for range of pages in a ttm. + * Unbind a ttm region from the aperture. */ -static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset, - unsigned long num_pages, int noncached) +int drm_evict_ttm(drm_ttm_t * ttm) { - int i, cur; - struct page **cur_page; - int do_tlbflush = 0; + drm_ttm_backend_t *be = ttm->be; - for (i = 0; i < num_pages; ++i) { - cur = page_offset + i; - cur_page = ttm->pages + cur; - if (*cur_page) { - if (PageHighMem(*cur_page)) { - if (noncached - && page_address(*cur_page) != NULL) { - DRM_ERROR - ("Illegal mapped HighMem Page\n"); - return -EINVAL; - } - } else if ((ttm->page_flags[cur] & - DRM_TTM_PAGE_UNCACHED) != noncached) { - DRM_MASK_VAL(ttm->page_flags[cur], - DRM_TTM_PAGE_UNCACHED, noncached); - if (noncached) { - map_page_into_agp(*cur_page); - } else { - unmap_page_from_agp(*cur_page); - } - do_tlbflush = 1; - } + switch (ttm->state) { + case ttm_bound: + if (be->needs_cache_adjust(be)) { + unmap_vma_pages(ttm); } + be->unbind(be); + break; + default: + break; } - if (do_tlbflush) - flush_agp_mappings(); + ttm->state = ttm_evicted; return 0; } -/* - * Unbind a ttm region from the aperture. - */ - -int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) +void drm_fixup_ttm_caching(drm_ttm_t * ttm) { - drm_ttm_backend_t *be = entry->be; - drm_ttm_t *ttm = entry->owner; - if (be) { - switch (entry->state) { - case ttm_bound: - if (ttm && be->needs_cache_adjust(be)) { - unmap_vma_pages(ttm, entry->page_offset, - entry->num_pages); - } - be->unbind(entry->be); - if (ttm && be->needs_cache_adjust(be)) { - drm_set_caching(ttm, entry->page_offset, - entry->num_pages, 0); - } - break; - default: - break; + if (ttm->state == ttm_evicted) { + drm_ttm_backend_t *be = ttm->be; + if (be->needs_cache_adjust(be)) { + drm_set_caching(ttm, 0); } + ttm->state = ttm_unbound; } - entry->state = ttm_evicted; - return 0; } + -void drm_unbind_ttm_region(drm_ttm_backend_list_t * entry) +void drm_unbind_ttm(drm_ttm_t * ttm) { - drm_evict_ttm_region(entry); - entry->state = ttm_unbound; -} - -/* - * Destroy and clean up all resources associated with a ttm region. - * FIXME: release pages to OS when doing this operation. - */ - -void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry) -{ - drm_ttm_backend_t *be = entry->be; - drm_ttm_t *ttm = entry->owner; - uint32_t *cur_page_flags; - int i; - - DRM_DEBUG("Destroying a TTM region\n"); - list_del_init(&entry->head); + if (ttm->state == ttm_bound) + drm_evict_ttm(ttm); - drm_unbind_ttm_region(entry); - if (be) { - be->clear(be); - be->destroy(be); - } - cur_page_flags = ttm->page_flags + entry->page_offset; - for (i = 0; i < entry->num_pages; ++i) { - DRM_MASK_VAL(*cur_page_flags, DRM_TTM_PAGE_USED, 0); - cur_page_flags++; - } - - drm_free(entry, sizeof(*entry), DRM_MEM_TTM); + drm_fixup_ttm_caching(ttm); } -/* - * Create a ttm region from a range of ttm pages. - */ - -int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset, - unsigned long n_pages, int cached, - drm_ttm_backend_list_t ** region) +int drm_bind_ttm(drm_ttm_t * ttm, + unsigned long aper_offset) { - struct page **cur_page; - uint32_t *cur_page_flags; - drm_ttm_backend_list_t *entry; - drm_ttm_backend_t *be; - int ret, i; - drm_buffer_manager_t *bm = &ttm->dev->bm; - if ((page_offset + n_pages) > ttm->num_pages || n_pages == 0) { - DRM_ERROR("Region Doesn't fit ttm\n"); - return -EINVAL; - } - - cur_page_flags = ttm->page_flags + page_offset; - for (i = 0; i < n_pages; ++i, ++cur_page_flags) { - if (*cur_page_flags & DRM_TTM_PAGE_USED) { - DRM_ERROR("TTM region overlap\n"); - return -EINVAL; - } else { - DRM_MASK_VAL(*cur_page_flags, DRM_TTM_PAGE_USED, - DRM_TTM_PAGE_USED); - } - } - - entry = drm_calloc(1, sizeof(*entry), DRM_MEM_TTM); - if (!entry) - return -ENOMEM; - - be = ttm->dev->driver->bo_driver->create_ttm_backend_entry(ttm->dev, - cached); - if (!be) { - drm_free(entry, sizeof(*entry), DRM_MEM_TTM); - DRM_ERROR("Couldn't create backend.\n"); - return -EINVAL; - } - entry->state = ttm_unbound; - entry->page_offset = page_offset; - entry->num_pages = n_pages; - entry->be = be; - entry->owner = ttm; - - INIT_LIST_HEAD(&entry->head); - list_add_tail(&entry->head, &ttm->be_list->head); - - for (i = 0; i < entry->num_pages; ++i) { - cur_page = ttm->pages + (page_offset + i); - if (!*cur_page) { - if (bm->cur_pages >= bm->max_pages) { - DRM_ERROR("Maximum locked page count exceeded\n"); - drm_destroy_ttm_region(entry); - return -ENOMEM; - } - *cur_page = drm_alloc_gatt_pages(0); - if (!*cur_page) { - DRM_ERROR("Page allocation failed\n"); - drm_destroy_ttm_region(entry); - return -ENOMEM; - } - SetPageLocked(*cur_page); - ++bm->cur_pages; - } - } - - if ((ret = be->populate(be, n_pages, ttm->pages + page_offset))) { - drm_destroy_ttm_region(entry); - DRM_ERROR("Couldn't populate backend.\n"); - return ret; - } - ttm->aperture_base = be->aperture_base; - - *region = entry; - return 0; -} - -/* - * Bind a ttm region. Set correct caching policy. - */ - -int drm_bind_ttm_region(drm_ttm_backend_list_t * region, - unsigned long aper_offset) -{ - - int i; - uint32_t *cur_page_flag; int ret = 0; drm_ttm_backend_t *be; - drm_ttm_t *ttm; - if (!region || region->state == ttm_bound) + if (!ttm) return -EINVAL; + if (ttm->state == ttm_bound) + return 0; - be = region->be; - ttm = region->owner; - - if (ttm && be->needs_cache_adjust(be)) { - if (ret) - return ret; - - unmap_vma_pages(ttm, region->page_offset, - region->num_pages); - drm_set_caching(ttm, region->page_offset, region->num_pages, - DRM_TTM_PAGE_UNCACHED); - } else { - DRM_DEBUG("Binding cached\n"); - } - + be = ttm->be; + + drm_ttm_populate(ttm); + if (ttm->state == ttm_unbound && be->needs_cache_adjust(be)) { + unmap_vma_pages(ttm); + drm_set_caching(ttm, DRM_TTM_PAGE_UNCACHED); + } if ((ret = be->bind(be, aper_offset))) { - drm_unbind_ttm_region(region); + drm_unbind_ttm(ttm); DRM_ERROR("Couldn't bind backend.\n"); return ret; } - cur_page_flag = ttm->page_flags + region->page_offset; - for (i = 0; i < region->num_pages; ++i) { - DRM_MASK_VAL(*cur_page_flag, DRM_TTM_MASK_PFN, - (i + aper_offset) << PAGE_SHIFT); - cur_page_flag++; - } - - region->state = ttm_bound; - return 0; -} - -int drm_rebind_ttm_region(drm_ttm_backend_list_t * entry, - unsigned long aper_offset) -{ - return drm_bind_ttm_region(entry, aper_offset); - -} - -/* - * Destroy an anonymous ttm region. - */ - -void drm_user_destroy_region(drm_ttm_backend_list_t * entry) -{ - drm_ttm_backend_t *be; - struct page **cur_page; - int i; - - if (!entry || entry->owner) - return; - - be = entry->be; - if (!be) { - drm_free(entry, sizeof(*entry), DRM_MEM_TTM); - return; - } - - be->unbind(be); - - if (entry->anon_pages) { - cur_page = entry->anon_pages; - for (i = 0; i < entry->anon_locked; ++i) { - if (!PageReserved(*cur_page)) - SetPageDirty(*cur_page); - page_cache_release(*cur_page); - cur_page++; - } - ttm_free(entry->anon_pages, - sizeof(*entry->anon_pages)*entry->anon_locked, - DRM_MEM_TTM); - } - - be->destroy(be); - drm_free(entry, sizeof(*entry), DRM_MEM_TTM); - return; -} - -/* - * Create a ttm region from an arbitrary region of user pages. - * Since this region has no backing ttm, it's owner is set to - * null, and it is registered with the file of the caller. - * Gets destroyed when the file is closed. We call this an - * anonymous ttm region. - */ - -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; - drm_ttm_backend_t *be; - int ret; - - if (len <= 0) - return -EINVAL; - if (!dev->driver->bo_driver->create_ttm_backend_entry) - return -EFAULT; - - tmp = drm_calloc(1, sizeof(*tmp), DRM_MEM_TTM); - - if (!tmp) - return -ENOMEM; - - be = dev->driver->bo_driver->create_ttm_backend_entry(dev, 1); - tmp->be = be; - - if (!be) { - drm_user_destroy_region(tmp); - return -ENOMEM; - } - if (be->needs_cache_adjust(be)) { - drm_user_destroy_region(tmp); - return -EFAULT; - } - - tmp->anon_pages = ttm_alloc(sizeof(*(tmp->anon_pages)) * len, - DRM_MEM_TTM); - - if (!tmp->anon_pages) { - drm_user_destroy_region(tmp); - return -ENOMEM; - } - - down_read(¤t->mm->mmap_sem); - ret = get_user_pages(current, current->mm, start, len, 1, 0, - tmp->anon_pages, NULL); - up_read(¤t->mm->mmap_sem); - - if (ret != len) { - drm_user_destroy_region(tmp); - DRM_ERROR("Could not lock %d pages. Return code was %d\n", - len, ret); - return -EPERM; - } - tmp->anon_locked = len; - - ret = be->populate(be, len, tmp->anon_pages); - - if (ret) { - drm_user_destroy_region(tmp); - return ret; - } - - tmp->state = ttm_unbound; - *entry = tmp; + ttm->aper_offset = aper_offset; + ttm->state = ttm_bound; return 0; } @@ -651,29 +379,18 @@ void drm_ttm_object_deref_unlocked(drm_device_t * dev, drm_ttm_object_t * to) } } -/* - * dev->struct_mutex locked. - */ -static void drm_ttm_user_deref_locked(drm_file_t * priv, - drm_user_object_t * base) -{ - drm_ttm_object_deref_locked(priv->head->dev, - drm_user_object_entry(base, - drm_ttm_object_t, - base)); -} - /* * Create a ttm and add it to the drm book-keeping. * dev->struct_mutex locked. */ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, - uint32_t flags, drm_ttm_object_t ** ttm_object) + uint32_t flags, int cached, + drm_ttm_object_t ** ttm_object) { drm_ttm_object_t *object; drm_map_list_t *list; - drm_map_t *map; + drm_local_map_t *map; drm_ttm_t *ttm; object = drm_calloc(1, sizeof(*object), DRM_MEM_TTM); @@ -689,14 +406,14 @@ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, } map = list->map; - ttm = drm_init_ttm(dev, size); + ttm = drm_init_ttm(dev, size, cached); if (!ttm) { DRM_ERROR("Could not create ttm\n"); drm_ttm_object_remove(dev, object); return -ENOMEM; } - map->offset = ttm->lhandle; + map->offset = (unsigned long) ttm; map->type = _DRM_TTM; map->flags = _DRM_REMOVABLE; map->size = ttm->num_pages * PAGE_SIZE; @@ -725,87 +442,3 @@ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, *ttm_object = object; return 0; } - -drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t * priv, uint32_t handle, - int check_owner) -{ - drm_user_object_t *uo; - drm_ttm_object_t *to; - - uo = drm_lookup_user_object(priv, handle); - - if (!uo || (uo->type != drm_ttm_type)) - return NULL; - - if (check_owner && priv != uo->owner) { - if (!drm_lookup_ref_object(priv, uo, _DRM_REF_USE)) - return NULL; - } - - to = drm_user_object_entry(uo, drm_ttm_object_t, base); - atomic_inc(&to->usage); - return to; -} - -int drm_ttm_ioctl(DRM_IOCTL_ARGS) -{ - DRM_DEVICE; - drm_ttm_arg_t arg; - drm_ttm_object_t *entry; - drm_user_object_t *uo; - unsigned long size; - int ret; - - DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); - - switch (arg.op) { - case drm_ttm_create: - mutex_lock(&dev->struct_mutex); - size = arg.size; - ret = drm_ttm_object_create(dev, size, arg.flags, &entry); - if (ret) { - mutex_unlock(&dev->struct_mutex); - return ret; - } - ret = drm_add_user_object(priv, &entry->base, - arg.flags & DRM_TTM_FLAG_SHAREABLE); - if (ret) { - drm_ttm_object_remove(dev, entry); - mutex_unlock(&dev->struct_mutex); - return ret; - } - entry->base.remove = drm_ttm_user_deref_locked; - entry->base.type = drm_ttm_type; - entry->base.ref_struct_locked = NULL; - entry->base.unref = NULL; - atomic_inc(&entry->usage); - break; - case drm_ttm_reference: - ret = drm_user_object_ref(priv, arg.handle, drm_ttm_type, &uo); - if (ret) - return ret; - mutex_lock(&dev->struct_mutex); - entry = drm_lookup_ttm_object(priv, arg.handle, 0); - break; - case drm_ttm_unreference: - return drm_user_object_unref(priv, arg.handle, drm_ttm_type); - case drm_ttm_destroy: - mutex_lock(&dev->struct_mutex); - uo = drm_lookup_user_object(priv, arg.handle); - if (!uo || (uo->type != drm_ttm_type) || uo->owner != priv) { - mutex_unlock(&dev->struct_mutex); - return -EINVAL; - } - ret = drm_remove_user_object(priv, uo); - mutex_unlock(&dev->struct_mutex); - return ret; - } - arg.handle = entry->base.hash.key; - arg.user_token = entry->map_list.user_token; - arg.size = entry->map_list.map->size; - drm_ttm_object_deref_locked(dev, entry); - mutex_unlock(&dev->struct_mutex); - - DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); - return 0; -} -- cgit v1.2.3 From 30703893674b3da5b862dee2acd6efca13424398 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 11 Oct 2006 22:21:01 +0200 Subject: Compatibility code for 2.6.15-2.6.18. It is ugly but a little comfort is that it will go away in the mainstream kernel. Some bugfixes, mainly in error paths. --- linux-core/drm_ttm.c | 70 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 9 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 297d4f71..b56270ea 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -66,8 +66,17 @@ static int unmap_vma_pages(drm_ttm_t * ttm) drm_device_t *dev = ttm->dev; loff_t offset = ((loff_t) ttm->mapping_offset) << PAGE_SHIFT; loff_t holelen = ((loff_t) ttm->num_pages) << PAGE_SHIFT; - + +#ifdef DRM_ODD_MM_COMPAT + int ret; + ret = drm_ttm_lock_mm(ttm); + if (ret) + return ret; +#endif unmap_mapping_range(dev->dev_mapping, offset, holelen, 1); +#ifdef DRM_ODD_MM_COMPAT + drm_ttm_finish_unmap(ttm); +#endif return 0; } @@ -128,8 +137,11 @@ int drm_destroy_ttm(drm_ttm_t * ttm) DRM_DEBUG("Destroying a ttm\n"); +#ifdef DRM_TTM_ODD_COMPAT + BUG_ON(!list_empty(&ttm->vma_list)); + BUG_ON(!list_empty(&ttm->p_mm_list)); +#endif be = ttm->be; - if (be) { be->destroy(be); ttm->be = NULL; @@ -231,6 +243,11 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size, if (!ttm) return NULL; +#ifdef DRM_ODD_MM_COMPAT + INIT_LIST_HEAD(&ttm->p_mm_list); + INIT_LIST_HEAD(&ttm->vma_list); +#endif + ttm->dev = dev; atomic_set(&ttm->vma_count, 0); @@ -263,11 +280,15 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size, int drm_evict_ttm(drm_ttm_t * ttm) { drm_ttm_backend_t *be = ttm->be; + int ret; switch (ttm->state) { case ttm_bound: if (be->needs_cache_adjust(be)) { - unmap_vma_pages(ttm); + ret = unmap_vma_pages(ttm); + if (ret) { + return ret; + } } be->unbind(be); break; @@ -291,12 +312,18 @@ void drm_fixup_ttm_caching(drm_ttm_t * ttm) } -void drm_unbind_ttm(drm_ttm_t * ttm) +int drm_unbind_ttm(drm_ttm_t * ttm) { + int ret = 0; + if (ttm->state == ttm_bound) - drm_evict_ttm(ttm); + ret = drm_evict_ttm(ttm); + + if (ret) + return ret; drm_fixup_ttm_caching(ttm); + return 0; } int drm_bind_ttm(drm_ttm_t * ttm, @@ -313,20 +340,45 @@ int drm_bind_ttm(drm_ttm_t * ttm, be = ttm->be; - drm_ttm_populate(ttm); + ret = drm_ttm_populate(ttm); + if (ret) + return ret; if (ttm->state == ttm_unbound && be->needs_cache_adjust(be)) { - unmap_vma_pages(ttm); + ret = unmap_vma_pages(ttm); + if (ret) + return ret; + drm_set_caching(ttm, DRM_TTM_PAGE_UNCACHED); - } + } +#ifdef DRM_ODD_MM_COMPAT + else if (ttm->state == ttm_evicted && be->needs_cache_adjust(be)) { + ret = drm_ttm_lock_mm(ttm); + if (ret) + return ret; + } +#endif if ((ret = be->bind(be, aper_offset))) { - drm_unbind_ttm(ttm); + ttm->state = ttm_evicted; +#ifdef DRM_ODD_MM_COMPAT + if (be->needs_cache_adjust(be)) + drm_ttm_unlock_mm(ttm); +#endif DRM_ERROR("Couldn't bind backend.\n"); return ret; } + ttm->aper_offset = aper_offset; ttm->state = ttm_bound; +#ifdef DRM_ODD_MM_COMPAT + if (be->needs_cache_adjust(be)) { + ret = drm_ttm_remap_bound(ttm); + if (ret) + return ret; + } +#endif + return 0; } -- cgit v1.2.3 From 10150df02b7062b9975661ccd82b475cd23c8839 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 12 Oct 2006 12:09:16 +0200 Subject: Simplify the AGP backend interface somewhat. Fix buffer bound caching policy changing, Allow on-the-fly changing of caching policy on bound buffers if the hardware supports it. Allow drivers to use driver-specific AGP memory types for TTM AGP pages. Will make AGP drivers much easier to migrate. --- linux-core/drm_ttm.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index b56270ea..f1fe1c89 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -230,8 +230,7 @@ static int drm_ttm_populate(drm_ttm_t *ttm) * Initialize a ttm. */ -static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size, - int cached) +static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) { drm_bo_driver_t *bo_driver = dev->driver->bo_driver; drm_ttm_t *ttm; @@ -263,7 +262,7 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size, return NULL; } memset(ttm->pages, 0, ttm->num_pages * sizeof(*ttm->pages)); - ttm->be = bo_driver->create_ttm_backend_entry(dev, cached); + ttm->be = bo_driver->create_ttm_backend_entry(dev); if (!ttm->be) { drm_destroy_ttm(ttm); DRM_ERROR("Failed creating ttm backend entry\n"); @@ -284,7 +283,7 @@ int drm_evict_ttm(drm_ttm_t * ttm) switch (ttm->state) { case ttm_bound: - if (be->needs_cache_adjust(be)) { + if (be->needs_ub_cache_adjust(be)) { ret = unmap_vma_pages(ttm); if (ret) { return ret; @@ -304,7 +303,7 @@ void drm_fixup_ttm_caching(drm_ttm_t * ttm) if (ttm->state == ttm_evicted) { drm_ttm_backend_t *be = ttm->be; - if (be->needs_cache_adjust(be)) { + if (be->needs_ub_cache_adjust(be)) { drm_set_caching(ttm, 0); } ttm->state = ttm_unbound; @@ -326,7 +325,7 @@ int drm_unbind_ttm(drm_ttm_t * ttm) return 0; } -int drm_bind_ttm(drm_ttm_t * ttm, +int drm_bind_ttm(drm_ttm_t * ttm, int cached, unsigned long aper_offset) { @@ -343,7 +342,7 @@ int drm_bind_ttm(drm_ttm_t * ttm, ret = drm_ttm_populate(ttm); if (ret) return ret; - if (ttm->state == ttm_unbound && be->needs_cache_adjust(be)) { + if (ttm->state == ttm_unbound && !cached) { ret = unmap_vma_pages(ttm); if (ret) return ret; @@ -351,16 +350,16 @@ int drm_bind_ttm(drm_ttm_t * ttm, drm_set_caching(ttm, DRM_TTM_PAGE_UNCACHED); } #ifdef DRM_ODD_MM_COMPAT - else if (ttm->state == ttm_evicted && be->needs_cache_adjust(be)) { + else if (ttm->state == ttm_evicted && !cached) { ret = drm_ttm_lock_mm(ttm); if (ret) return ret; } #endif - if ((ret = be->bind(be, aper_offset))) { + if ((ret = be->bind(be, aper_offset, cached))) { ttm->state = ttm_evicted; #ifdef DRM_ODD_MM_COMPAT - if (be->needs_cache_adjust(be)) + if (be->needs_ub_cache_adjust(be)) drm_ttm_unlock_mm(ttm); #endif DRM_ERROR("Couldn't bind backend.\n"); @@ -372,7 +371,7 @@ int drm_bind_ttm(drm_ttm_t * ttm, ttm->state = ttm_bound; #ifdef DRM_ODD_MM_COMPAT - if (be->needs_cache_adjust(be)) { + if (be->needs_ub_cache_adjust(be)) { ret = drm_ttm_remap_bound(ttm); if (ret) return ret; @@ -437,7 +436,7 @@ void drm_ttm_object_deref_unlocked(drm_device_t * dev, drm_ttm_object_t * to) */ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, - uint32_t flags, int cached, + uint32_t flags, drm_ttm_object_t ** ttm_object) { drm_ttm_object_t *object; @@ -458,7 +457,7 @@ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, } map = list->map; - ttm = drm_init_ttm(dev, size, cached); + ttm = drm_init_ttm(dev, size); if (!ttm) { DRM_ERROR("Could not create ttm\n"); drm_ttm_object_remove(dev, object); -- cgit v1.2.3 From db5c671e86c3db8c99ce5a4954632248e6f849aa Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 11:28:48 +0200 Subject: Remove the memory manager parameter from the put_block function, as this makes the client code a lot cleaner. Prepare buffer manager for lock and unlock calls. --- linux-core/drm_ttm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index f1fe1c89..0f9cb11f 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -393,7 +393,7 @@ static void drm_ttm_object_remove(drm_device_t * dev, drm_ttm_object_t * object) drm_ht_remove_item(&dev->map_hash, &list->hash); if (list->file_offset_node) { - drm_mm_put_block(&dev->offset_manager, list->file_offset_node); + drm_mm_put_block(list->file_offset_node); list->file_offset_node = NULL; } -- cgit v1.2.3 From d515936ea7f98f6aaa9217699796beadef9d664b Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 19:40:57 +0200 Subject: Add memory usage accounting to avoid DOS problems. --- linux-core/drm_ttm.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 0f9cb11f..3e66319a 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -37,12 +37,17 @@ static void *ttm_alloc(unsigned long size, int type) { void *ret = NULL; - if (size <= 4*PAGE_SIZE) { + if (drm_alloc_memctl(size)) + return NULL; + if (size <= PAGE_SIZE) { ret = drm_alloc(size, type); } if (!ret) { ret = vmalloc(size); } + if (!ret) { + drm_free_memctl(size); + } return ret; } @@ -55,6 +60,7 @@ static void ttm_free(void *pointer, unsigned long size, int type) } else { drm_free(pointer, size, type); } + drm_free_memctl(size); } /* @@ -174,6 +180,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) */ drm_free_gatt_pages(*cur_page, 0); + drm_free_memctl(PAGE_SIZE); --bm->cur_pages; } } @@ -182,8 +189,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) ttm->pages = NULL; } - drm_free(ttm, sizeof(*ttm), DRM_MEM_TTM); - + drm_ctl_free(ttm, sizeof(*ttm), DRM_MEM_TTM); return 0; } @@ -203,13 +209,14 @@ static int drm_ttm_populate(drm_ttm_t *ttm) for (i=0; inum_pages; ++i) { page = ttm->pages[i]; if (!page) { - if (bm->cur_pages >= bm->max_pages) { - DRM_ERROR("Maximum locked page count exceeded\n"); + if (drm_alloc_memctl(PAGE_SIZE)) { return -ENOMEM; } page = drm_alloc_gatt_pages(0); - if (!page) + if (!page) { + drm_free_memctl(PAGE_SIZE); return -ENOMEM; + } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)) SetPageLocked(page); #else @@ -238,7 +245,7 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) if (!bo_driver) return NULL; - ttm = drm_calloc(1, sizeof(*ttm), DRM_MEM_TTM); + ttm = drm_ctl_calloc(1, sizeof(*ttm), DRM_MEM_TTM); if (!ttm) return NULL; @@ -254,6 +261,11 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; ttm->page_flags = 0; + + /* + * Account also for AGP module memory usage. + */ + ttm->pages = ttm_alloc(ttm->num_pages * sizeof(*ttm->pages), DRM_MEM_TTM); if (!ttm->pages) { @@ -403,14 +415,14 @@ static void drm_ttm_object_remove(drm_device_t * dev, drm_ttm_object_t * object) drm_ttm_t *ttm = (drm_ttm_t *) map->offset; if (ttm) { if (drm_destroy_ttm(ttm) != -EBUSY) { - drm_free(map, sizeof(*map), DRM_MEM_TTM); + drm_ctl_free(map, sizeof(*map), DRM_MEM_TTM); } } else { - drm_free(map, sizeof(*map), DRM_MEM_TTM); + drm_ctl_free(map, sizeof(*map), DRM_MEM_TTM); } } - drm_free(object, sizeof(*object), DRM_MEM_TTM); + drm_ctl_free(object, sizeof(*object), DRM_MEM_TTM); } void drm_ttm_object_deref_locked(drm_device_t * dev, drm_ttm_object_t * to) @@ -444,13 +456,13 @@ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, drm_local_map_t *map; drm_ttm_t *ttm; - object = drm_calloc(1, sizeof(*object), DRM_MEM_TTM); + object = drm_ctl_calloc(1, sizeof(*object), DRM_MEM_TTM); if (!object) return -ENOMEM; object->flags = flags; list = &object->map_list; - list->map = drm_calloc(1, sizeof(*map), DRM_MEM_TTM); + list->map = drm_ctl_calloc(1, sizeof(*map), DRM_MEM_TTM); if (!list->map) { drm_ttm_object_remove(dev, object); return -ENOMEM; -- cgit v1.2.3 From 89b944179856fadf8667587eff142129c2c6b826 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 19:57:06 +0200 Subject: Lindent. --- linux-core/drm_ttm.c | 53 ++++++++++++++++++++++------------------------------ 1 file changed, 22 insertions(+), 31 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 3e66319a..599589fc 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -32,7 +32,6 @@ * Use kmalloc if possible. Otherwise fall back to vmalloc. */ - static void *ttm_alloc(unsigned long size, int type) { void *ret = NULL; @@ -53,15 +52,15 @@ static void *ttm_alloc(unsigned long size, int type) static void ttm_free(void *pointer, unsigned long size, int type) { - - if ((unsigned long) pointer >= VMALLOC_START && - (unsigned long) pointer <= VMALLOC_END) { + + if ((unsigned long)pointer >= VMALLOC_START && + (unsigned long)pointer <= VMALLOC_END) { vfree(pointer); } else { drm_free(pointer, size, type); } drm_free_memctl(size); -} +} /* * Unmap all vma pages from vmas mapping this ttm. @@ -155,7 +154,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) if (ttm->pages) { drm_buffer_manager_t *bm = &ttm->dev->bm; - if (ttm->page_flags & DRM_TTM_PAGE_UNCACHED) + if (ttm->page_flags & DRM_TTM_PAGE_UNCACHED) drm_set_caching(ttm, 0); for (i = 0; i < ttm->num_pages; ++i) { @@ -184,7 +183,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) --bm->cur_pages; } } - ttm_free(ttm->pages, ttm->num_pages*sizeof(*ttm->pages), + ttm_free(ttm->pages, ttm->num_pages * sizeof(*ttm->pages), DRM_MEM_TTM); ttm->pages = NULL; } @@ -193,20 +192,19 @@ int drm_destroy_ttm(drm_ttm_t * ttm) return 0; } -static int drm_ttm_populate(drm_ttm_t *ttm) +static int drm_ttm_populate(drm_ttm_t * ttm) { struct page *page; unsigned long i; drm_buffer_manager_t *bm; drm_ttm_backend_t *be; - - if (ttm->state != ttm_unpopulated) + if (ttm->state != ttm_unpopulated) return 0; - + bm = &ttm->dev->bm; be = ttm->be; - for (i=0; inum_pages; ++i) { + for (i = 0; i < ttm->num_pages; ++i) { page = ttm->pages[i]; if (!page) { if (drm_alloc_memctl(PAGE_SIZE)) { @@ -229,9 +227,7 @@ static int drm_ttm_populate(drm_ttm_t *ttm) be->populate(be, ttm->num_pages, ttm->pages); ttm->state = ttm_unbound; return 0; -} - - +} /* * Initialize a ttm. @@ -266,7 +262,7 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) * Account also for AGP module memory usage. */ - ttm->pages = ttm_alloc(ttm->num_pages * sizeof(*ttm->pages), + ttm->pages = ttm_alloc(ttm->num_pages * sizeof(*ttm->pages), DRM_MEM_TTM); if (!ttm->pages) { drm_destroy_ttm(ttm); @@ -321,13 +317,12 @@ void drm_fixup_ttm_caching(drm_ttm_t * ttm) ttm->state = ttm_unbound; } } - int drm_unbind_ttm(drm_ttm_t * ttm) { int ret = 0; - if (ttm->state == ttm_bound) + if (ttm->state == ttm_bound) ret = drm_evict_ttm(ttm); if (ret) @@ -337,8 +332,7 @@ int drm_unbind_ttm(drm_ttm_t * ttm) return 0; } -int drm_bind_ttm(drm_ttm_t * ttm, int cached, - unsigned long aper_offset) +int drm_bind_ttm(drm_ttm_t * ttm, int cached, unsigned long aper_offset) { int ret = 0; @@ -350,7 +344,7 @@ int drm_bind_ttm(drm_ttm_t * ttm, int cached, return 0; be = ttm->be; - + ret = drm_ttm_populate(ttm); if (ret) return ret; @@ -361,7 +355,7 @@ int drm_bind_ttm(drm_ttm_t * ttm, int cached, drm_set_caching(ttm, DRM_TTM_PAGE_UNCACHED); } -#ifdef DRM_ODD_MM_COMPAT +#ifdef DRM_ODD_MM_COMPAT else if (ttm->state == ttm_evicted && !cached) { ret = drm_ttm_lock_mm(ttm); if (ret) @@ -378,18 +372,17 @@ int drm_bind_ttm(drm_ttm_t * ttm, int cached, return ret; } - ttm->aper_offset = aper_offset; ttm->state = ttm_bound; #ifdef DRM_ODD_MM_COMPAT if (be->needs_ub_cache_adjust(be)) { ret = drm_ttm_remap_bound(ttm); - if (ret) + if (ret) return ret; } #endif - + return 0; } @@ -448,8 +441,7 @@ void drm_ttm_object_deref_unlocked(drm_device_t * dev, drm_ttm_object_t * to) */ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, - uint32_t flags, - drm_ttm_object_t ** ttm_object) + uint32_t flags, drm_ttm_object_t ** ttm_object) { drm_ttm_object_t *object; drm_map_list_t *list; @@ -476,21 +468,20 @@ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, return -ENOMEM; } - map->offset = (unsigned long) ttm; + map->offset = (unsigned long)ttm; map->type = _DRM_TTM; map->flags = _DRM_REMOVABLE; map->size = ttm->num_pages * PAGE_SIZE; map->handle = (void *)object; list->file_offset_node = drm_mm_search_free(&dev->offset_manager, - ttm->num_pages, - 0,0); + ttm->num_pages, 0, 0); if (!list->file_offset_node) { drm_ttm_object_remove(dev, object); return -ENOMEM; } list->file_offset_node = drm_mm_get_block(list->file_offset_node, - ttm->num_pages,0); + ttm->num_pages, 0); list->hash.key = list->file_offset_node->start; -- cgit v1.2.3 From 9ed4656799043f24f4d64615ebb8128bedc99799 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sat, 21 Oct 2006 14:17:51 +0200 Subject: The CPU cache must be flushed _before_ we start modifying the kernel map ptes, otherwise data will be missing, which becomes apparent when the kernel evicts batch buffers which are likely to be written into in the evicted state, and then rebound to the AGP aperture. This means we cannot rely on the AGP module to flush the cache for us. --- linux-core/drm_ttm.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 599589fc..7344acce 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -28,6 +28,18 @@ #include "drmP.h" +static void drm_ttm_ipi_handler(void *null) +{ + wbinvd(); +} + +static void drm_ttm_cache_flush(void) +{ + if (on_each_cpu(drm_ttm_ipi_handler, NULL, 1, 1) != 0) + DRM_ERROR("Timed out waiting for drm cache flush.\n"); +} + + /* * Use kmalloc if possible. Otherwise fall back to vmalloc. */ @@ -99,6 +111,9 @@ static int drm_set_caching(drm_ttm_t * ttm, int noncached) if ((ttm->page_flags & DRM_TTM_PAGE_UNCACHED) == noncached) return 0; + if (noncached) + drm_ttm_cache_flush(); + for (i = 0; i < ttm->num_pages; ++i) { cur_page = ttm->pages + i; if (*cur_page) { -- cgit v1.2.3 From b4fba1679b6156e3ca6f053b44cae0b003febe7f Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 26 Oct 2006 21:14:23 +0200 Subject: Add a one-page hole in the file offset space between buffers. --- linux-core/drm_ttm.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 7344acce..13bec48b 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -489,14 +489,20 @@ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, map->size = ttm->num_pages * PAGE_SIZE; map->handle = (void *)object; + /* + * Add a one-page "hole" to the block size to avoid the mm subsystem + * merging vmas. + * FIXME: Is this really needed? + */ + list->file_offset_node = drm_mm_search_free(&dev->offset_manager, - ttm->num_pages, 0, 0); + ttm->num_pages + 1, 0, 0); if (!list->file_offset_node) { drm_ttm_object_remove(dev, object); return -ENOMEM; } list->file_offset_node = drm_mm_get_block(list->file_offset_node, - ttm->num_pages, 0); + ttm->num_pages + 1, 0); list->hash.key = list->file_offset_node->start; -- cgit v1.2.3 From 4b04c0cc45f7a89c757ce442e4f2742b9d3aa293 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 30 Oct 2006 11:18:44 +0100 Subject: Bugzilla Bug #8819 Build fixes for powerpc. Reported by Katerina Barone-Adesi --- linux-core/drm_ttm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 13bec48b..931972af 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -30,7 +30,7 @@ static void drm_ttm_ipi_handler(void *null) { - wbinvd(); + flush_agp_cache(); } static void drm_ttm_cache_flush(void) -- cgit v1.2.3