From b0bc5f1ae559c705565e516ebb289bf072559dec Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 14 Dec 2007 11:42:17 -0800 Subject: Make ttm create/destroy APIs consistent. Pass page_flags in create. Creating a ttm was done with drm_ttm_init while destruction was done with drm_destroy_ttm. Renaming these to drm_ttm_create and drm_ttm_destroy makes their use clearer. Passing page_flags to the create function will allow that to know whether user or kernel pages are needed, with the goal of allowing kernel ttms to be saved for later reuse. --- linux-core/drm_ttm.c | 16 ++++++++-------- 1 file changed, 8 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 3540571f..4200bc1a 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -193,7 +193,7 @@ static void drm_ttm_free_alloced_pages(struct drm_ttm *ttm) * Free all resources associated with a ttm. */ -int drm_destroy_ttm(struct drm_ttm *ttm) +int drm_ttm_destroy(struct drm_ttm *ttm) { struct drm_ttm_backend *be; @@ -251,11 +251,11 @@ int drm_ttm_set_user(struct drm_ttm *ttm, int i; BUG_ON(num_pages != ttm->num_pages); + BUG_ON((ttm->page_flags & DRM_TTM_PAGE_USER) == 0); ttm->dummy_read_page = dummy_read_page; - ttm->page_flags |= DRM_TTM_PAGE_USER | - ((write) ? DRM_TTM_PAGE_USER_WRITE : 0); - + if (write) + ttm->page_flags |= DRM_TTM_PAGE_USER_WRITE; down_read(&mm->mmap_sem); ret = get_user_pages(tsk, mm, start, num_pages, @@ -299,7 +299,7 @@ int drm_ttm_populate(struct drm_ttm *ttm) * Initialize a ttm. */ -struct drm_ttm *drm_ttm_init(struct drm_device *dev, unsigned long size) +struct drm_ttm *drm_ttm_create(struct drm_device *dev, unsigned long size, uint32_t page_flags) { struct drm_bo_driver *bo_driver = dev->driver->bo_driver; struct drm_ttm *ttm; @@ -317,7 +317,7 @@ struct drm_ttm *drm_ttm_init(struct drm_device *dev, unsigned long size) ttm->destroy = 0; ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - ttm->page_flags = 0; + ttm->page_flags = page_flags; /* * Account also for AGP module memory usage. @@ -325,13 +325,13 @@ struct drm_ttm *drm_ttm_init(struct drm_device *dev, unsigned long size) ttm_alloc_pages(ttm); if (!ttm->pages) { - drm_destroy_ttm(ttm); + drm_ttm_destroy(ttm); DRM_ERROR("Failed allocating page table\n"); return NULL; } ttm->be = bo_driver->create_ttm_backend_entry(dev); if (!ttm->be) { - drm_destroy_ttm(ttm); + drm_ttm_destroy(ttm); DRM_ERROR("Failed creating ttm backend entry\n"); return NULL; } -- cgit v1.2.3 From 0b031dbd63bbb3e0ba6d39e1e5c4eb4e87985158 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 14 Dec 2007 13:19:35 -0800 Subject: Document drm_ttm_set_user. Add a comment explaining the parameters for this function --- linux-core/drm_ttm.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'linux-core/drm_ttm.c') diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 4200bc1a..4c1b3274 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -239,6 +239,22 @@ struct page *drm_ttm_get_page(struct drm_ttm *ttm, int index) } EXPORT_SYMBOL(drm_ttm_get_page); +/** + * drm_ttm_set_user: + * + * @ttm: the ttm to map pages to. This must always be + * a freshly created ttm. + * + * @tsk: a pointer to the address space from which to map + * pages. + * + * @write: a boolean indicating that write access is desired + * + * start: the starting address + * + * Map a range of user addresses to a new ttm object. This + * provides access to user memory from the graphics device. + */ int drm_ttm_set_user(struct drm_ttm *ttm, struct task_struct *tsk, int write, -- cgit v1.2.3 From 6d44f48002c19d67187adb660ef74dd1870d52c2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 16 Dec 2007 00:54:25 -0800 Subject: Clean up and document drm_ttm.c APIs. drm_bind_ttm -> drm_ttm_bind. Aside from changing drm_bind_ttm to drm_ttm_bind, this patch adds only documentation and fixes the functions inside drm_ttm.c to all be prefixed with drm_ttm_. --- linux-core/drm_ttm.c | 79 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 64 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 4c1b3274..e3b9fcce 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -46,7 +46,7 @@ EXPORT_SYMBOL(drm_ttm_cache_flush); * Use kmalloc if possible. Otherwise fall back to vmalloc. */ -static void ttm_alloc_pages(struct drm_ttm *ttm) +static void drm_ttm_alloc_pages(struct drm_ttm *ttm) { unsigned long size = ttm->num_pages * sizeof(*ttm->pages); ttm->pages = NULL; @@ -66,7 +66,7 @@ static void ttm_alloc_pages(struct drm_ttm *ttm) drm_free_memctl(size); } -static void ttm_free_pages(struct drm_ttm *ttm) +static void drm_ttm_free_pages(struct drm_ttm *ttm) { unsigned long size = ttm->num_pages * sizeof(*ttm->pages); @@ -103,7 +103,7 @@ static struct page *drm_ttm_alloc_page(void) * for range of pages in a ttm. */ -static int drm_set_caching(struct drm_ttm *ttm, int noncached) +static int drm_ttm_set_caching(struct drm_ttm *ttm, int noncached) { int i; struct page **cur_page; @@ -208,14 +208,14 @@ int drm_ttm_destroy(struct drm_ttm *ttm) if (ttm->pages) { if (ttm->page_flags & DRM_TTM_PAGE_UNCACHED) - drm_set_caching(ttm, 0); + drm_ttm_set_caching(ttm, 0); if (ttm->page_flags & DRM_TTM_PAGE_USER) drm_ttm_free_user_pages(ttm); else drm_ttm_free_alloced_pages(ttm); - ttm_free_pages(ttm); + drm_ttm_free_pages(ttm); } drm_ctl_free(ttm, sizeof(*ttm), DRM_MEM_TTM); @@ -291,6 +291,14 @@ int drm_ttm_set_user(struct drm_ttm *ttm, return 0; } +/** + * drm_ttm_populate: + * + * @ttm: the object to allocate pages for + * + * Allocate pages for all unset page entries, then + * call the backend to create the hardware mappings + */ int drm_ttm_populate(struct drm_ttm *ttm) { struct page *page; @@ -311,8 +319,16 @@ int drm_ttm_populate(struct drm_ttm *ttm) return 0; } -/* - * Initialize a ttm. +/** + * drm_ttm_create: + * + * @dev: the drm_device + * + * @size: The size (in bytes) of the desired object + * + * @page_flags: various DRM_TTM_PAGE_* flags. See drm_object.h. + * + * Allocate and initialize a ttm, leaving it unpopulated at this time */ struct drm_ttm *drm_ttm_create(struct drm_device *dev, unsigned long size, uint32_t page_flags) @@ -339,7 +355,7 @@ struct drm_ttm *drm_ttm_create(struct drm_device *dev, unsigned long size, uint3 * Account also for AGP module memory usage. */ - ttm_alloc_pages(ttm); + drm_ttm_alloc_pages(ttm); if (!ttm->pages) { drm_ttm_destroy(ttm); DRM_ERROR("Failed allocating page table\n"); @@ -355,10 +371,15 @@ struct drm_ttm *drm_ttm_create(struct drm_device *dev, unsigned long size, uint3 return ttm; } -/* - * Unbind a ttm region from the aperture. +/** + * drm_ttm_evict: + * + * @ttm: the object to be unbound from the aperture. + * + * Transition a ttm from bound to evicted, where it + * isn't present in the aperture, but various caches may + * not be consistent. */ - void drm_ttm_evict(struct drm_ttm *ttm) { struct drm_ttm_backend *be = ttm->be; @@ -372,17 +393,33 @@ void drm_ttm_evict(struct drm_ttm *ttm) ttm->state = ttm_evicted; } +/** + * drm_ttm_fixup_caching: + * + * @ttm: the object to set unbound + * + * XXX this function is misnamed. Transition a ttm from evicted to + * unbound, flushing caches as appropriate. + */ void drm_ttm_fixup_caching(struct drm_ttm *ttm) { if (ttm->state == ttm_evicted) { struct drm_ttm_backend *be = ttm->be; if (be->func->needs_ub_cache_adjust(be)) - drm_set_caching(ttm, 0); + drm_ttm_set_caching(ttm, 0); ttm->state = ttm_unbound; } } +/** + * drm_ttm_unbind: + * + * @ttm: the object to unbind from the graphics device + * + * Unbind an object from the aperture. This removes the mappings + * from the graphics device and flushes caches if necessary. + */ void drm_ttm_unbind(struct drm_ttm *ttm) { if (ttm->state == ttm_bound) @@ -391,7 +428,19 @@ void drm_ttm_unbind(struct drm_ttm *ttm) drm_ttm_fixup_caching(ttm); } -int drm_bind_ttm(struct drm_ttm *ttm, struct drm_bo_mem_reg *bo_mem) +/** + * drm_ttm_bind: + * + * @ttm: the ttm object to bind to the graphics device + * + * @bo_mem: the aperture memory region which will hold the object + * + * Bind a ttm object to the aperture. This ensures that the necessary + * pages are allocated, flushes CPU caches as needed and marks the + * ttm as DRM_TTM_PAGE_USER_DIRTY to indicate that it may have been + * modified by the GPU + */ +int drm_ttm_bind(struct drm_ttm *ttm, struct drm_bo_mem_reg *bo_mem) { struct drm_bo_driver *bo_driver = ttm->dev->driver->bo_driver; int ret = 0; @@ -409,7 +458,7 @@ int drm_bind_ttm(struct drm_ttm *ttm, struct drm_bo_mem_reg *bo_mem) return ret; if (ttm->state == ttm_unbound && !(bo_mem->flags & DRM_BO_FLAG_CACHED)) - drm_set_caching(ttm, DRM_TTM_PAGE_UNCACHED); + drm_ttm_set_caching(ttm, DRM_TTM_PAGE_UNCACHED); else if ((bo_mem->flags & DRM_BO_FLAG_CACHED_MAPPED) && bo_driver->ttm_cache_flush) bo_driver->ttm_cache_flush(ttm); @@ -426,4 +475,4 @@ int drm_bind_ttm(struct drm_ttm *ttm, struct drm_bo_mem_reg *bo_mem) ttm->page_flags |= DRM_TTM_PAGE_USER_DIRTY; return 0; } -EXPORT_SYMBOL(drm_bind_ttm); +EXPORT_SYMBOL(drm_ttm_bind); -- cgit v1.2.3 From 881ee70ab7bab5d6f6140dc9bf1e19c7b5844084 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 16 Dec 2007 01:12:07 -0800 Subject: Move dummy_read_page from drm_ttm_set_user to drm_ttm_create. I'm hoping to use the dummy_read_page for kernel allocated buffers to avoid allocating extra pages for read-only buffers (like vertex and batch buffers). This also eliminates the 'write' parameter to drm_ttm_set_user and just has DRM_TTM_PAGE_WRITE passed into drm_ttm_create. --- linux-core/drm_ttm.c | 16 +++++++--------- 1 file changed, 7 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 e3b9fcce..c1fc13fc 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -145,7 +145,7 @@ static void drm_ttm_free_user_pages(struct drm_ttm *ttm) int i; BUG_ON(!(ttm->page_flags & DRM_TTM_PAGE_USER)); - write = ((ttm->page_flags & DRM_TTM_PAGE_USER_WRITE) != 0); + write = ((ttm->page_flags & DRM_TTM_PAGE_WRITE) != 0); dirty = ((ttm->page_flags & DRM_TTM_PAGE_USER_DIRTY) != 0); for (i = 0; i < ttm->num_pages; ++i) { @@ -257,22 +257,17 @@ EXPORT_SYMBOL(drm_ttm_get_page); */ int drm_ttm_set_user(struct drm_ttm *ttm, struct task_struct *tsk, - int write, unsigned long start, - unsigned long num_pages, - struct page *dummy_read_page) + unsigned long num_pages) { struct mm_struct *mm = tsk->mm; int ret; int i; + int write = (ttm->page_flags & DRM_TTM_PAGE_WRITE) != 0; BUG_ON(num_pages != ttm->num_pages); BUG_ON((ttm->page_flags & DRM_TTM_PAGE_USER) == 0); - ttm->dummy_read_page = dummy_read_page; - if (write) - ttm->page_flags |= DRM_TTM_PAGE_USER_WRITE; - down_read(&mm->mmap_sem); ret = get_user_pages(tsk, mm, start, num_pages, write, 0, ttm->pages, NULL); @@ -331,7 +326,8 @@ int drm_ttm_populate(struct drm_ttm *ttm) * Allocate and initialize a ttm, leaving it unpopulated at this time */ -struct drm_ttm *drm_ttm_create(struct drm_device *dev, unsigned long size, uint32_t page_flags) +struct drm_ttm *drm_ttm_create(struct drm_device *dev, unsigned long size, + uint32_t page_flags, struct page *dummy_read_page) { struct drm_bo_driver *bo_driver = dev->driver->bo_driver; struct drm_ttm *ttm; @@ -351,6 +347,8 @@ struct drm_ttm *drm_ttm_create(struct drm_device *dev, unsigned long size, uint3 ttm->page_flags = page_flags; + ttm->dummy_read_page = dummy_read_page; + /* * Account also for AGP module memory usage. */ -- cgit v1.2.3 From 37fb2ac4071f62bad2c36cc9ca84f9c8feee6bf5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 16 Dec 2007 01:47:51 -0800 Subject: Use dummy_read_page for unpopulated kernel-allocated ttm pages. Previously, dummy_read_page was used only for read-only user allocations; it filled in pages that were not present in the user address map (presumably, these were allocated but never written to pages). This patch allows them to be used for read-only ttms allocated from the kernel, so that applications can over-allocate buffers without forcing every page to be allocated. --- linux-core/drm_ttm.c | 18 +++++++----------- 1 file changed, 7 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 c1fc13fc..a9d87338 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -262,7 +262,6 @@ int drm_ttm_set_user(struct drm_ttm *ttm, { struct mm_struct *mm = tsk->mm; int ret; - int i; int write = (ttm->page_flags & DRM_TTM_PAGE_WRITE) != 0; BUG_ON(num_pages != ttm->num_pages); @@ -278,11 +277,6 @@ int drm_ttm_set_user(struct drm_ttm *ttm, return -ENOMEM; } - for (i = 0; i < num_pages; ++i) { - if (ttm->pages[i] == NULL) - ttm->pages[i] = ttm->dummy_read_page; - } - return 0; } @@ -304,12 +298,14 @@ int drm_ttm_populate(struct drm_ttm *ttm) return 0; be = ttm->be; - for (i = 0; i < ttm->num_pages; ++i) { - page = drm_ttm_get_page(ttm, i); - if (!page) - return -ENOMEM; + if (ttm->page_flags & DRM_TTM_PAGE_WRITE) { + for (i = 0; i < ttm->num_pages; ++i) { + page = drm_ttm_get_page(ttm, i); + if (!page) + return -ENOMEM; + } } - be->func->populate(be, ttm->num_pages, ttm->pages); + be->func->populate(be, ttm->num_pages, ttm->pages, ttm->dummy_read_page); ttm->state = ttm_unbound; return 0; } -- cgit v1.2.3