summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/lima/lima_vm.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2019-04-05 11:21:47 +1000
committerDave Airlie <airlied@redhat.com>2019-04-05 11:38:02 +1000
commit14d2bd53a47a7e1cb3e03d00a6b952734cf90f3f (patch)
tree616e11aacdf96d495bf6ef9c8163fb83cd5b712b /drivers/gpu/drm/lima/lima_vm.c
parent5ebffda257731a11cf1db6c6142c82d5b30aec35 (diff)
parentf15a3ea80391e83f32d4a23f83b1f02415cd5889 (diff)
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.c282
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);
+ }
+ }
+ }
+}