diff options
author | Dave Airlie | 2019-04-05 03:21:47 +0200 |
---|---|---|
committer | Dave Airlie | 2019-04-05 03:38:02 +0200 |
commit | 14d2bd53a47a7e1cb3e03d00a6b952734cf90f3f (patch) | |
tree | 616e11aacdf96d495bf6ef9c8163fb83cd5b712b /drivers/gpu/drm/lima/lima_vm.c | |
parent | Merge commit 'refs/for-upstream/mali-dp' of git://linux-arm.org/linux-ld into... (diff) | |
parent | MAINTAINERS: Add ASPEED BMC GFX DRM driver entry (diff) | |
download | kernel-qcow2-linux-14d2bd53a47a7e1cb3e03d00a6b952734cf90f3f.tar.gz kernel-qcow2-linux-14d2bd53a47a7e1cb3e03d00a6b952734cf90f3f.tar.xz kernel-qcow2-linux-14d2bd53a47a7e1cb3e03d00a6b952734cf90f3f.zip |
Merge tag 'drm-misc-next-2019-04-04' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for 5.2:
UAPI Changes:
-syncobj: Add TIMELINE_WAIT|QUERY|TRANSFER|TIMELINE_SIGNAL ioctls (Chunming)
-Clarify that 1.0 can be represented by drm_color_lut (Daniel)
Cross-subsystem Changes:
-dt-bindings: Add binding for rk3066 hdmi (Johan)
-dt-bindings: Add binding for Feiyang FY07024DI26A30-D panel (Jagan)
-dt-bindings: Add Rocktech vendor prefix and jh057n00900 panel bindings (Guido)
-MAINTAINERS: Add lima and ASPEED entries (Joel & Qiang)
Core Changes:
-memory: use dma_alloc_coherent when mem encryption is active (Christian)
-dma_buf: add support for a dma_fence chain (Christian)
-shmem_gem: fix off-by-one bug in new shmem gem helpers (Dan)
Driver Changes:
-rockchip: Add support for rk3066 hdmi (Johan)
-ASPEED: Add driver supporting ASPEED BMC display controller to drm (Joel)
-lima: Add driver supporting Arm Mali4xx gpus to drm (Qiang)
-vc4/v3d: Various cleanups and improved error handling (Eric)
-panel: Add support for Feiyang FY07024DI26A30-D MIPI-DSI panel (Jagan)
-panel: Add support for Rocktech jh057n00900 MIPI-DSI panel (Guido)
Cc: Johan Jonker <jbx6244@gmail.com>
Cc: Christian König <christian.koenig@amd.com>
Cc: Chunming Zhou <david1.zhou@amd.com>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Cc: Eric Anholt <eric@anholt.net>
Cc: Qiang Yu <yuq825@gmail.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Jagan Teki <jagan@amarulasolutions.com>
Cc: Guido Günther <agx@sigxcpu.org>
Cc: Joel Stanley <joel@jms.id.au>
[airlied: fixed XA limit build breakage, Rodrigo also submitted the same patch, but
I squashed it in the merge.]
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Sean Paul <sean@poorly.run>
Link: https://patchwork.freedesktop.org/patch/msgid/20190404201016.GA139524@art_vandelay
Diffstat (limited to 'drivers/gpu/drm/lima/lima_vm.c')
-rw-r--r-- | drivers/gpu/drm/lima/lima_vm.c | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/drivers/gpu/drm/lima/lima_vm.c b/drivers/gpu/drm/lima/lima_vm.c new file mode 100644 index 000000000000..19e88ca16527 --- /dev/null +++ b/drivers/gpu/drm/lima/lima_vm.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* Copyright 2017-2019 Qiang Yu <yuq825@gmail.com> */ + +#include <linux/slab.h> +#include <linux/dma-mapping.h> + +#include "lima_device.h" +#include "lima_vm.h" +#include "lima_object.h" +#include "lima_regs.h" + +struct lima_bo_va { + struct list_head list; + unsigned int ref_count; + + struct drm_mm_node node; + + struct lima_vm *vm; +}; + +#define LIMA_VM_PD_SHIFT 22 +#define LIMA_VM_PT_SHIFT 12 +#define LIMA_VM_PB_SHIFT (LIMA_VM_PD_SHIFT + LIMA_VM_NUM_PT_PER_BT_SHIFT) +#define LIMA_VM_BT_SHIFT LIMA_VM_PT_SHIFT + +#define LIMA_VM_PT_MASK ((1 << LIMA_VM_PD_SHIFT) - 1) +#define LIMA_VM_BT_MASK ((1 << LIMA_VM_PB_SHIFT) - 1) + +#define LIMA_PDE(va) (va >> LIMA_VM_PD_SHIFT) +#define LIMA_PTE(va) ((va & LIMA_VM_PT_MASK) >> LIMA_VM_PT_SHIFT) +#define LIMA_PBE(va) (va >> LIMA_VM_PB_SHIFT) +#define LIMA_BTE(va) ((va & LIMA_VM_BT_MASK) >> LIMA_VM_BT_SHIFT) + + +static void lima_vm_unmap_page_table(struct lima_vm *vm, u32 start, u32 end) +{ + u32 addr; + + for (addr = start; addr <= end; addr += LIMA_PAGE_SIZE) { + u32 pbe = LIMA_PBE(addr); + u32 bte = LIMA_BTE(addr); + + vm->bts[pbe].cpu[bte] = 0; + } +} + +static int lima_vm_map_page_table(struct lima_vm *vm, dma_addr_t *dma, + u32 start, u32 end) +{ + u64 addr; + int i = 0; + + for (addr = start; addr <= end; addr += LIMA_PAGE_SIZE) { + u32 pbe = LIMA_PBE(addr); + u32 bte = LIMA_BTE(addr); + + if (!vm->bts[pbe].cpu) { + dma_addr_t pts; + u32 *pd; + int j; + + vm->bts[pbe].cpu = dma_alloc_wc( + vm->dev->dev, LIMA_PAGE_SIZE << LIMA_VM_NUM_PT_PER_BT_SHIFT, + &vm->bts[pbe].dma, GFP_KERNEL | __GFP_ZERO); + if (!vm->bts[pbe].cpu) { + if (addr != start) + lima_vm_unmap_page_table(vm, start, addr - 1); + return -ENOMEM; + } + + pts = vm->bts[pbe].dma; + pd = vm->pd.cpu + (pbe << LIMA_VM_NUM_PT_PER_BT_SHIFT); + for (j = 0; j < LIMA_VM_NUM_PT_PER_BT; j++) { + pd[j] = pts | LIMA_VM_FLAG_PRESENT; + pts += LIMA_PAGE_SIZE; + } + } + + vm->bts[pbe].cpu[bte] = dma[i++] | LIMA_VM_FLAGS_CACHE; + } + + return 0; +} + +static struct lima_bo_va * +lima_vm_bo_find(struct lima_vm *vm, struct lima_bo *bo) +{ + struct lima_bo_va *bo_va, *ret = NULL; + + list_for_each_entry(bo_va, &bo->va, list) { + if (bo_va->vm == vm) { + ret = bo_va; + break; + } + } + + return ret; +} + +int lima_vm_bo_add(struct lima_vm *vm, struct lima_bo *bo, bool create) +{ + struct lima_bo_va *bo_va; + int err; + + mutex_lock(&bo->lock); + + bo_va = lima_vm_bo_find(vm, bo); + if (bo_va) { + bo_va->ref_count++; + mutex_unlock(&bo->lock); + return 0; + } + + /* should not create new bo_va if not asked by caller */ + if (!create) { + mutex_unlock(&bo->lock); + return -ENOENT; + } + + bo_va = kzalloc(sizeof(*bo_va), GFP_KERNEL); + if (!bo_va) { + err = -ENOMEM; + goto err_out0; + } + + bo_va->vm = vm; + bo_va->ref_count = 1; + + mutex_lock(&vm->lock); + + err = drm_mm_insert_node(&vm->mm, &bo_va->node, bo->gem.size); + if (err) + goto err_out1; + + err = lima_vm_map_page_table(vm, bo->pages_dma_addr, bo_va->node.start, + bo_va->node.start + bo_va->node.size - 1); + if (err) + goto err_out2; + + mutex_unlock(&vm->lock); + + list_add_tail(&bo_va->list, &bo->va); + + mutex_unlock(&bo->lock); + return 0; + +err_out2: + drm_mm_remove_node(&bo_va->node); +err_out1: + mutex_unlock(&vm->lock); + kfree(bo_va); +err_out0: + mutex_unlock(&bo->lock); + return err; +} + +void lima_vm_bo_del(struct lima_vm *vm, struct lima_bo *bo) +{ + struct lima_bo_va *bo_va; + + mutex_lock(&bo->lock); + + bo_va = lima_vm_bo_find(vm, bo); + if (--bo_va->ref_count > 0) { + mutex_unlock(&bo->lock); + return; + } + + mutex_lock(&vm->lock); + + lima_vm_unmap_page_table(vm, bo_va->node.start, + bo_va->node.start + bo_va->node.size - 1); + + drm_mm_remove_node(&bo_va->node); + + mutex_unlock(&vm->lock); + + list_del(&bo_va->list); + + mutex_unlock(&bo->lock); + + kfree(bo_va); +} + +u32 lima_vm_get_va(struct lima_vm *vm, struct lima_bo *bo) +{ + struct lima_bo_va *bo_va; + u32 ret; + + mutex_lock(&bo->lock); + + bo_va = lima_vm_bo_find(vm, bo); + ret = bo_va->node.start; + + mutex_unlock(&bo->lock); + + return ret; +} + +struct lima_vm *lima_vm_create(struct lima_device *dev) +{ + struct lima_vm *vm; + + vm = kzalloc(sizeof(*vm), GFP_KERNEL); + if (!vm) + return NULL; + + vm->dev = dev; + mutex_init(&vm->lock); + kref_init(&vm->refcount); + + vm->pd.cpu = dma_alloc_wc(dev->dev, LIMA_PAGE_SIZE, &vm->pd.dma, + GFP_KERNEL | __GFP_ZERO); + if (!vm->pd.cpu) + goto err_out0; + + if (dev->dlbu_cpu) { + int err = lima_vm_map_page_table( + vm, &dev->dlbu_dma, LIMA_VA_RESERVE_DLBU, + LIMA_VA_RESERVE_DLBU + LIMA_PAGE_SIZE - 1); + if (err) + goto err_out1; + } + + drm_mm_init(&vm->mm, dev->va_start, dev->va_end - dev->va_start); + + return vm; + +err_out1: + dma_free_wc(dev->dev, LIMA_PAGE_SIZE, vm->pd.cpu, vm->pd.dma); +err_out0: + kfree(vm); + return NULL; +} + +void lima_vm_release(struct kref *kref) +{ + struct lima_vm *vm = container_of(kref, struct lima_vm, refcount); + int i; + + drm_mm_takedown(&vm->mm); + + for (i = 0; i < LIMA_VM_NUM_BT; i++) { + if (vm->bts[i].cpu) + dma_free_wc(vm->dev->dev, LIMA_PAGE_SIZE << LIMA_VM_NUM_PT_PER_BT_SHIFT, + vm->bts[i].cpu, vm->bts[i].dma); + } + + if (vm->pd.cpu) + dma_free_wc(vm->dev->dev, LIMA_PAGE_SIZE, vm->pd.cpu, vm->pd.dma); + + kfree(vm); +} + +void lima_vm_print(struct lima_vm *vm) +{ + int i, j, k; + u32 *pd, *pt; + + if (!vm->pd.cpu) + return; + + pd = vm->pd.cpu; + for (i = 0; i < LIMA_VM_NUM_BT; i++) { + if (!vm->bts[i].cpu) + continue; + + pt = vm->bts[i].cpu; + for (j = 0; j < LIMA_VM_NUM_PT_PER_BT; j++) { + int idx = (i << LIMA_VM_NUM_PT_PER_BT_SHIFT) + j; + + printk(KERN_INFO "lima vm pd %03x:%08x\n", idx, pd[idx]); + + for (k = 0; k < LIMA_PAGE_ENT_NUM; k++) { + u32 pte = *pt++; + + if (pte) + printk(KERN_INFO " pt %03x:%08x\n", k, pte); + } + } + } +} |