|
@@ -35,162 +35,6 @@
|
|
|
#include "drm_sarea.h"
|
|
|
#include "nouveau_drv.h"
|
|
|
|
|
|
-static struct mem_block *
|
|
|
-split_block(struct mem_block *p, uint64_t start, uint64_t size,
|
|
|
- struct drm_file *file_priv)
|
|
|
-{
|
|
|
- /* Maybe cut off the start of an existing block */
|
|
|
- if (start > p->start) {
|
|
|
- struct mem_block *newblock =
|
|
|
- kmalloc(sizeof(*newblock), GFP_KERNEL);
|
|
|
- if (!newblock)
|
|
|
- goto out;
|
|
|
- newblock->start = start;
|
|
|
- newblock->size = p->size - (start - p->start);
|
|
|
- newblock->file_priv = NULL;
|
|
|
- newblock->next = p->next;
|
|
|
- newblock->prev = p;
|
|
|
- p->next->prev = newblock;
|
|
|
- p->next = newblock;
|
|
|
- p->size -= newblock->size;
|
|
|
- p = newblock;
|
|
|
- }
|
|
|
-
|
|
|
- /* Maybe cut off the end of an existing block */
|
|
|
- if (size < p->size) {
|
|
|
- struct mem_block *newblock =
|
|
|
- kmalloc(sizeof(*newblock), GFP_KERNEL);
|
|
|
- if (!newblock)
|
|
|
- goto out;
|
|
|
- newblock->start = start + size;
|
|
|
- newblock->size = p->size - size;
|
|
|
- newblock->file_priv = NULL;
|
|
|
- newblock->next = p->next;
|
|
|
- newblock->prev = p;
|
|
|
- p->next->prev = newblock;
|
|
|
- p->next = newblock;
|
|
|
- p->size = size;
|
|
|
- }
|
|
|
-
|
|
|
-out:
|
|
|
- /* Our block is in the middle */
|
|
|
- p->file_priv = file_priv;
|
|
|
- return p;
|
|
|
-}
|
|
|
-
|
|
|
-struct mem_block *
|
|
|
-nouveau_mem_alloc_block(struct mem_block *heap, uint64_t size,
|
|
|
- int align2, struct drm_file *file_priv, int tail)
|
|
|
-{
|
|
|
- struct mem_block *p;
|
|
|
- uint64_t mask = (1 << align2) - 1;
|
|
|
-
|
|
|
- if (!heap)
|
|
|
- return NULL;
|
|
|
-
|
|
|
- if (tail) {
|
|
|
- list_for_each_prev(p, heap) {
|
|
|
- uint64_t start = ((p->start + p->size) - size) & ~mask;
|
|
|
-
|
|
|
- if (p->file_priv == NULL && start >= p->start &&
|
|
|
- start + size <= p->start + p->size)
|
|
|
- return split_block(p, start, size, file_priv);
|
|
|
- }
|
|
|
- } else {
|
|
|
- list_for_each(p, heap) {
|
|
|
- uint64_t start = (p->start + mask) & ~mask;
|
|
|
-
|
|
|
- if (p->file_priv == NULL &&
|
|
|
- start + size <= p->start + p->size)
|
|
|
- return split_block(p, start, size, file_priv);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
-void nouveau_mem_free_block(struct mem_block *p)
|
|
|
-{
|
|
|
- p->file_priv = NULL;
|
|
|
-
|
|
|
- /* Assumes a single contiguous range. Needs a special file_priv in
|
|
|
- * 'heap' to stop it being subsumed.
|
|
|
- */
|
|
|
- if (p->next->file_priv == NULL) {
|
|
|
- struct mem_block *q = p->next;
|
|
|
- p->size += q->size;
|
|
|
- p->next = q->next;
|
|
|
- p->next->prev = p;
|
|
|
- kfree(q);
|
|
|
- }
|
|
|
-
|
|
|
- if (p->prev->file_priv == NULL) {
|
|
|
- struct mem_block *q = p->prev;
|
|
|
- q->size += p->size;
|
|
|
- q->next = p->next;
|
|
|
- q->next->prev = q;
|
|
|
- kfree(p);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/* Initialize. How to check for an uninitialized heap?
|
|
|
- */
|
|
|
-int nouveau_mem_init_heap(struct mem_block **heap, uint64_t start,
|
|
|
- uint64_t size)
|
|
|
-{
|
|
|
- struct mem_block *blocks = kmalloc(sizeof(*blocks), GFP_KERNEL);
|
|
|
-
|
|
|
- if (!blocks)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
- *heap = kmalloc(sizeof(**heap), GFP_KERNEL);
|
|
|
- if (!*heap) {
|
|
|
- kfree(blocks);
|
|
|
- return -ENOMEM;
|
|
|
- }
|
|
|
-
|
|
|
- blocks->start = start;
|
|
|
- blocks->size = size;
|
|
|
- blocks->file_priv = NULL;
|
|
|
- blocks->next = blocks->prev = *heap;
|
|
|
-
|
|
|
- memset(*heap, 0, sizeof(**heap));
|
|
|
- (*heap)->file_priv = (struct drm_file *) -1;
|
|
|
- (*heap)->next = (*heap)->prev = blocks;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Free all blocks associated with the releasing file_priv
|
|
|
- */
|
|
|
-void nouveau_mem_release(struct drm_file *file_priv, struct mem_block *heap)
|
|
|
-{
|
|
|
- struct mem_block *p;
|
|
|
-
|
|
|
- if (!heap || !heap->next)
|
|
|
- return;
|
|
|
-
|
|
|
- list_for_each(p, heap) {
|
|
|
- if (p->file_priv == file_priv)
|
|
|
- p->file_priv = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- /* Assumes a single contiguous range. Needs a special file_priv in
|
|
|
- * 'heap' to stop it being subsumed.
|
|
|
- */
|
|
|
- list_for_each(p, heap) {
|
|
|
- while ((p->file_priv == NULL) &&
|
|
|
- (p->next->file_priv == NULL) &&
|
|
|
- (p->next != heap)) {
|
|
|
- struct mem_block *q = p->next;
|
|
|
- p->size += q->size;
|
|
|
- p->next = q->next;
|
|
|
- p->next->prev = p;
|
|
|
- kfree(q);
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* NV10-NV40 tiling helpers
|
|
|
*/
|
|
@@ -421,24 +265,8 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
|
|
|
/*
|
|
|
* Cleanup everything
|
|
|
*/
|
|
|
-void nouveau_mem_takedown(struct mem_block **heap)
|
|
|
-{
|
|
|
- struct mem_block *p;
|
|
|
-
|
|
|
- if (!*heap)
|
|
|
- return;
|
|
|
-
|
|
|
- for (p = (*heap)->next; p != *heap;) {
|
|
|
- struct mem_block *q = p;
|
|
|
- p = p->next;
|
|
|
- kfree(q);
|
|
|
- }
|
|
|
-
|
|
|
- kfree(*heap);
|
|
|
- *heap = NULL;
|
|
|
-}
|
|
|
-
|
|
|
-void nouveau_mem_close(struct drm_device *dev)
|
|
|
+void
|
|
|
+nouveau_mem_close(struct drm_device *dev)
|
|
|
{
|
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
|
|