diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 3731ee12..6de6c06f 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -65,6 +65,8 @@ # define _DRM_FREE free # include "drm.h" #endif +#include "xf86mm.h" + /* Not all systems have MAP_FAILED defined */ #ifndef MAP_FAILED @@ -2384,7 +2386,7 @@ int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, unsigned flags) int drmTTMDestroy(int fd, const drmTTM *ttm) { - drm_ttm_arg_t arg; + drm_ttm_arg_t arg; arg.op = drm_ttm_destroy; arg.handle = ttm->handle; @@ -2425,4 +2427,135 @@ drm_handle_t drmTTMMapHandle(int fd, const drmTTM *ttm) (void) fd; return ttm->user_token; } + +static int drmAdjustListNodes(DrmBufList *list) +{ + DrmBufNode *node; + DrmMMListHead *l; + int ret = 0; + + while(list->numCurrent < list->numTarget) { + node = (DrmBufNode *) malloc(sizeof(*node)); + if (!node) { + ret = -ENOMEM; + break; + } + list->numCurrent++; + DRMLISTADD(&node->head, &list->free); + } + + while(list->numCurrent > list->numTarget) { + l = list->free.next; + if (l == &list->free) + break; + DRMLISTDEL(l); + node = DRMLISTENTRY(DrmBufNode, l, head); + free(node); + list->numCurrent--; + } + return ret; +} + +static void drmFreeList(DrmBufList *list) +{ + DrmBufNode *node; + DrmMMListHead *l; + int ret = 0; + + l = list->list.next; + while(l != &list->list) { + DRMLISTDEL(l); + node = DRMLISTENTRY(DrmBufNode, l, head); + free(node); + l = list->free.next; + list->numCurrent--; + list->numOnList--; + } + + l = list->free.next; + while(l != &list->free) { + DRMLISTDEL(l); + node = DRMLISTENTRY(DrmBufNode, l, head); + free(node); + l = list->free.next; + list->numCurrent--; + } +} + +int drmResetList(DrmBufList *list) { + + DrmMMListHead *l; + int ret; + + ret = drmAdjustListNodes(list); + if (ret) + return ret; + + l = list->list.next; + while(l != &list->list) { + DRMLISTDEL(l); + DRMLISTADD(l, &list->free); + list->numOnList--; + } + return drmAdjustListNodes(list); +} + +static int drmAddListItem(DrmBufList *list, DrmBuf *item, drm_bo_arg_t *arg) +{ + DrmBufNode *node; + DrmMMListHead *l; + + l = list->free.next; + if (l == &list->free) { + node = (DrmBufNode *) malloc(sizeof(*node)); + if (!node) { + return -ENOMEM; + } + list->numCurrent++; + } else { + DRMLISTDEL(l); + node = DRMLISTENTRY(DrmBufNode, l, head); + } + node->buf = item; + DRMLISTADD(&node->head, &list->list); + list->numOnList++; + return 0; +} + +int drmCreateBufList(int numTarget, DrmBufList *list) +{ + DRMINITLISTHEAD(&list->list); + DRMINITLISTHEAD(&list->free); + list->numTarget = numTarget; + list->numCurrent = 0; + list->numOnList = 0; + return drmAdjustListNodes(list); +} + +/* + * Prepare list for IOCTL submission. + */ + +static drm_bo_arg_t *drmPrepareList(DrmBufList *list) +{ + DrmMMListHead *cur, *next; + DrmBufNode *first, *curNode, *nextNode; + + cur = list->list.next; + if (cur == &list->list) + return NULL; + + first = DRMLISTENTRY(DrmBufNode, cur, head); + curNode = DRMLISTENTRY(DrmBufNode, cur, head); + + for (next = cur->next; next != &list->list; + cur = next, next = cur->next) { + nextNode = DRMLISTENTRY(DrmBufNode, next, head); + curNode->bo_arg.req.next = ((unsigned long) &nextNode->bo_arg.req); + curNode = nextNode; + } + curNode->bo_arg.req.next = 0; + return &first->bo_arg; +} + #endif diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h new file mode 100644 index 00000000..5fb78723 --- /dev/null +++ b/libdrm/xf86mm.h @@ -0,0 +1,105 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA. + * 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. + * + * + **************************************************************************/ + +#ifndef _XF86MM_H_ +#define _XF86MM_H_ +#include + + +/* + * List macros heavily inspired by the Linux kernel + * list handling. No list looping yet. + */ + +typedef struct _drmMMListHead +{ + struct _drmMMListHead *prev; + struct _drmMMListHead *next; +} DrmMMListHead; + +#define DRMINITLISTHEAD(__item) \ + do{ \ + (__item)->prev = (__item); \ + (__item)->next = (__item); \ + } while (0) + +#define DRMLISTADD(__item, __list) \ + do { \ + (__item)->prev = (__list); \ + (__item)->next = (__list)->next; \ + (__list)->next->prev = (__item); \ + (__list)->next = (__item); \ + } while (0) + +#define DRMLISTADDTAIL(__item, __list) \ + do { \ + (__item)->next = (__list); \ + (__item)->prev = (__list)->prev; \ + (__list)->prev->next = (__item); \ + (__list)->prev = (__item); \ + } while(0) + +#define DRMLISTDEL(__item) \ + do { \ + (__item)->prev->next = (__item)->next; \ + (__item)->next->prev = (__item)->prev; \ + } while(0) + +#define DRMLISTDELINIT(__item) \ + do { \ + (__item)->prev->next = (__item)->next; \ + (__item)->next->prev = (__item)->prev; \ + (__item)->next = (__item); \ + (__item)->prev = (__item); \ + } while(0) + +#define DRMLISTENTRY(__type, __item, __field) \ + ((__type *)(((char *) (__item)) - offsetof(__type, __field))) + + +typedef struct _DrmBuf{ + unsigned handle; +} DrmBuf; + + +typedef struct _DrmBufNode { + DrmMMListHead head; + DrmBuf *buf; + drm_bo_arg_t bo_arg; +} DrmBufNode; + +typedef struct _DrmMMBufList { + unsigned numTarget; + unsigned numCurrent; + unsigned numOnList; + DrmMMListHead list; + DrmMMListHead free; +} DrmBufList; + + +#endif diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 81b7a1b6..4d490abe 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -652,7 +652,8 @@ typedef struct drm_ref_object { */ typedef struct drm_bo_driver{ - int cached_pages; + int cached_tt; + int cached_vram; drm_ttm_backend_t *(*create_ttm_backend_entry) (struct drm_device *dev, int cached); } drm_bo_driver_t; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 30656060..55901660 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -214,7 +214,8 @@ static void drm_bo_base_deref_locked(drm_file_t *priv, drm_user_object_t *uo) } -static int drm_bo_new_flags(uint32_t flags, uint32_t new_mask, uint32_t hint, +static int drm_bo_new_flags(drm_bo_driver_t *driver, + uint32_t flags, uint32_t new_mask, uint32_t hint, int init, uint32_t *n_flags) { uint32_t new_flags; @@ -263,6 +264,24 @@ static int drm_bo_new_flags(uint32_t flags, uint32_t new_mask, uint32_t hint, } new_flags |= new_mask & ~DRM_BO_MASK_MEM; + + if (hint & DRM_BO_HINT_BIND_CACHED) { + new_flags |= DRM_BO_FLAG_CACHED; + if (((new_flags & DRM_BO_FLAG_MEM_TT) && !driver->cached_tt) || + ((new_flags & DRM_BO_FLAG_MEM_VRAM) && !driver->cached_vram)) + new_flags &= ~DRM_BO_FLAG_CACHED; + } + + if ((new_flags & DRM_BO_FLAG_NO_EVICT) && + ((flags ^ new_flags) & DRM_BO_FLAG_CACHED)) { + if (flags & DRM_BO_FLAG_CACHED) { + DRM_ERROR("Cannot change caching policy of pinned buffer\n"); + return -EINVAL; + } else { + new_flags &= ~DRM_BO_FLAG_CACHED; + } + } + *n_flags = new_flags; return 0; } @@ -531,11 +550,12 @@ static int drm_buffer_object_validate(drm_device_t *dev, drm_buffer_object_t *bo return 0; } + /* * Call bo->mutex locked. */ -static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t new_flags, +static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t hint, uint32_t ttm_handle) { @@ -578,7 +598,7 @@ static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t ne ttm = drm_ttm_from_object(to); ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, bo->num_pages, - new_flags & DRM_BO_FLAG_CACHED, + hint & DRM_BO_HINT_BIND_CACHED, &bo->ttm_region); if (ret) { drm_ttm_object_deref_unlocked(dev, to); @@ -631,6 +651,10 @@ int drm_buffer_object_create(drm_file_t *priv, bo->num_pages = num_pages; bo->buffer_start = buffer_start; + ret = drm_bo_new_flags(dev->driver->bo_driver, bo->flags, mask, hint, + 1, &new_flags); + if (ret) + goto out_err; ret = drm_bo_add_ttm(priv, bo, new_flags, ttm_handle); if (ret) goto out_err; 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)); diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 64ab3f50..bc78dc2e 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -49,7 +49,8 @@ static drm_fence_driver_t i915_fence_driver = { }; static drm_bo_driver_t i915_bo_driver = { - .cached_pages = 1, + .cached_vram = 0, + .cached_tt = 1, .create_ttm_backend_entry = i915_create_ttm_backend_entry }; diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index 46a2a728..452d4ee8 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -86,6 +86,8 @@ static void i915_perform_flush(drm_device_t * dev) dev_priv->flush_sequence = (uint32_t) READ_BREADCRUMB(dev_priv); dev_priv->flush_flags = fm->pending_flush; dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0); + DRM_ERROR("Saved flush status is 0x%08x\n", + dev_priv->saved_flush_status); I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21)); dev_priv->flush_pending = 1; fm->pending_flush = 0; diff --git a/shared-core/drm.h b/shared-core/drm.h index e50ebfe2..5888c9be 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -685,7 +685,7 @@ typedef struct drm_ttm_arg { #define DRM_BO_FLAG_NO_MOVE 0x00000008 #define DRM_BO_FLAG_NO_EVICT 0x00000010 #define DRM_BO_FLAG_SHADOW_VRAM 0x00000020 -#define DRM_BO_FLAG_READ_LOCAL 0x00000040 +#define DRM_BO_FLAG_READ_CACHED 0x00000040 #define DRM_BO_FLAG_CACHED 0x00000080 #define DRM_BO_FLAG_SHAREABLE 0x00000100 @@ -697,6 +697,7 @@ typedef struct drm_ttm_arg { #define DRM_BO_HINT_PREFER_VRAM 0x00000001 #define DRM_BO_HINT_AVOID_LOCAL 0x00000002 #define DRM_BO_HINT_DONT_BLOCK 0x00000004 +#define DRM_BO_HINT_BIND_CACHED 0x00000008 typedef enum { drm_bo_type_ttm, diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 8ef9d8e1..e661269b 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -195,9 +195,6 @@ static int i915_initialize(drm_device_t * dev, I915_WRITE(0x02080, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); -#ifdef I915_HAVE_FENCE - dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0); -#endif dev->dev_private = (void *)dev_priv; return 0; diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 08d3140b..4195555e 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -275,6 +275,12 @@ void i915_driver_irq_postinstall(drm_device_t * dev) i915_enable_interrupt(dev); DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); + + /* + * Initialize the hardware status page IRQ location. + */ + + I915_WRITE(I915REG_INSTPM, ( 1 << 5) | ( 1 << 21)); } void i915_driver_irq_uninstall(drm_device_t * dev)