1 // SPDX-License-Identifier: GPL-2.0 OR MIT
4 #include <linux/slab.h>
5 #include <linux/dma-mapping.h>
7 #include "lima_device.h"
9 #include "lima_object.h"
10 #include "lima_regs.h"
13 struct list_head list;
14 unsigned int ref_count;
16 struct drm_mm_node node;
21 #define LIMA_VM_PD_SHIFT 22
22 #define LIMA_VM_PT_SHIFT 12
23 #define LIMA_VM_PB_SHIFT (LIMA_VM_PD_SHIFT + LIMA_VM_NUM_PT_PER_BT_SHIFT)
24 #define LIMA_VM_BT_SHIFT LIMA_VM_PT_SHIFT
26 #define LIMA_VM_PT_MASK ((1 << LIMA_VM_PD_SHIFT) - 1)
27 #define LIMA_VM_BT_MASK ((1 << LIMA_VM_PB_SHIFT) - 1)
29 #define LIMA_PDE(va) (va >> LIMA_VM_PD_SHIFT)
30 #define LIMA_PTE(va) ((va & LIMA_VM_PT_MASK) >> LIMA_VM_PT_SHIFT)
31 #define LIMA_PBE(va) (va >> LIMA_VM_PB_SHIFT)
32 #define LIMA_BTE(va) ((va & LIMA_VM_BT_MASK) >> LIMA_VM_BT_SHIFT)
35 static void lima_vm_unmap_page_table(struct lima_vm *vm, u32 start, u32 end)
39 for (addr = start; addr <= end; addr += LIMA_PAGE_SIZE) {
40 u32 pbe = LIMA_PBE(addr);
41 u32 bte = LIMA_BTE(addr);
43 vm->bts[pbe].cpu[bte] = 0;
47 static int lima_vm_map_page_table(struct lima_vm *vm, dma_addr_t *dma,
53 for (addr = start; addr <= end; addr += LIMA_PAGE_SIZE) {
54 u32 pbe = LIMA_PBE(addr);
55 u32 bte = LIMA_BTE(addr);
57 if (!vm->bts[pbe].cpu) {
62 vm->bts[pbe].cpu = dma_alloc_wc(
63 vm->dev->dev, LIMA_PAGE_SIZE << LIMA_VM_NUM_PT_PER_BT_SHIFT,
64 &vm->bts[pbe].dma, GFP_KERNEL | __GFP_ZERO);
65 if (!vm->bts[pbe].cpu) {
67 lima_vm_unmap_page_table(vm, start, addr - 1);
71 pts = vm->bts[pbe].dma;
72 pd = vm->pd.cpu + (pbe << LIMA_VM_NUM_PT_PER_BT_SHIFT);
73 for (j = 0; j < LIMA_VM_NUM_PT_PER_BT; j++) {
74 pd[j] = pts | LIMA_VM_FLAG_PRESENT;
75 pts += LIMA_PAGE_SIZE;
79 vm->bts[pbe].cpu[bte] = dma[i++] | LIMA_VM_FLAGS_CACHE;
85 static struct lima_bo_va *
86 lima_vm_bo_find(struct lima_vm *vm, struct lima_bo *bo)
88 struct lima_bo_va *bo_va, *ret = NULL;
90 list_for_each_entry(bo_va, &bo->va, list) {
91 if (bo_va->vm == vm) {
100 int lima_vm_bo_add(struct lima_vm *vm, struct lima_bo *bo, bool create)
102 struct lima_bo_va *bo_va;
105 mutex_lock(&bo->lock);
107 bo_va = lima_vm_bo_find(vm, bo);
110 mutex_unlock(&bo->lock);
114 /* should not create new bo_va if not asked by caller */
116 mutex_unlock(&bo->lock);
120 bo_va = kzalloc(sizeof(*bo_va), GFP_KERNEL);
127 bo_va->ref_count = 1;
129 mutex_lock(&vm->lock);
131 err = drm_mm_insert_node(&vm->mm, &bo_va->node, bo->gem.size);
135 err = lima_vm_map_page_table(vm, bo->pages_dma_addr, bo_va->node.start,
136 bo_va->node.start + bo_va->node.size - 1);
140 mutex_unlock(&vm->lock);
142 list_add_tail(&bo_va->list, &bo->va);
144 mutex_unlock(&bo->lock);
148 drm_mm_remove_node(&bo_va->node);
150 mutex_unlock(&vm->lock);
153 mutex_unlock(&bo->lock);
157 void lima_vm_bo_del(struct lima_vm *vm, struct lima_bo *bo)
159 struct lima_bo_va *bo_va;
161 mutex_lock(&bo->lock);
163 bo_va = lima_vm_bo_find(vm, bo);
164 if (--bo_va->ref_count > 0) {
165 mutex_unlock(&bo->lock);
169 mutex_lock(&vm->lock);
171 lima_vm_unmap_page_table(vm, bo_va->node.start,
172 bo_va->node.start + bo_va->node.size - 1);
174 drm_mm_remove_node(&bo_va->node);
176 mutex_unlock(&vm->lock);
178 list_del(&bo_va->list);
180 mutex_unlock(&bo->lock);
185 u32 lima_vm_get_va(struct lima_vm *vm, struct lima_bo *bo)
187 struct lima_bo_va *bo_va;
190 mutex_lock(&bo->lock);
192 bo_va = lima_vm_bo_find(vm, bo);
193 ret = bo_va->node.start;
195 mutex_unlock(&bo->lock);
200 struct lima_vm *lima_vm_create(struct lima_device *dev)
204 vm = kzalloc(sizeof(*vm), GFP_KERNEL);
209 mutex_init(&vm->lock);
210 kref_init(&vm->refcount);
212 vm->pd.cpu = dma_alloc_wc(dev->dev, LIMA_PAGE_SIZE, &vm->pd.dma,
213 GFP_KERNEL | __GFP_ZERO);
218 int err = lima_vm_map_page_table(
219 vm, &dev->dlbu_dma, LIMA_VA_RESERVE_DLBU,
220 LIMA_VA_RESERVE_DLBU + LIMA_PAGE_SIZE - 1);
225 drm_mm_init(&vm->mm, dev->va_start, dev->va_end - dev->va_start);
230 dma_free_wc(dev->dev, LIMA_PAGE_SIZE, vm->pd.cpu, vm->pd.dma);
236 void lima_vm_release(struct kref *kref)
238 struct lima_vm *vm = container_of(kref, struct lima_vm, refcount);
241 drm_mm_takedown(&vm->mm);
243 for (i = 0; i < LIMA_VM_NUM_BT; i++) {
245 dma_free_wc(vm->dev->dev, LIMA_PAGE_SIZE << LIMA_VM_NUM_PT_PER_BT_SHIFT,
246 vm->bts[i].cpu, vm->bts[i].dma);
250 dma_free_wc(vm->dev->dev, LIMA_PAGE_SIZE, vm->pd.cpu, vm->pd.dma);
255 void lima_vm_print(struct lima_vm *vm)
264 for (i = 0; i < LIMA_VM_NUM_BT; i++) {
269 for (j = 0; j < LIMA_VM_NUM_PT_PER_BT; j++) {
270 int idx = (i << LIMA_VM_NUM_PT_PER_BT_SHIFT) + j;
272 printk(KERN_INFO "lima vm pd %03x:%08x\n", idx, pd[idx]);
274 for (k = 0; k < LIMA_PAGE_ENT_NUM; k++) {
278 printk(KERN_INFO " pt %03x:%08x\n", k, pte);