root/drivers/gpu/drm/lima/lima_vm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lima_vm_unmap_page_table
  2. lima_vm_map_page_table
  3. lima_vm_bo_find
  4. lima_vm_bo_add
  5. lima_vm_bo_del
  6. lima_vm_get_va
  7. lima_vm_create
  8. lima_vm_release
  9. lima_vm_print

   1 // SPDX-License-Identifier: GPL-2.0 OR MIT
   2 /* Copyright 2017-2019 Qiang Yu <yuq825@gmail.com> */
   3 
   4 #include <linux/slab.h>
   5 #include <linux/dma-mapping.h>
   6 
   7 #include "lima_device.h"
   8 #include "lima_vm.h"
   9 #include "lima_object.h"
  10 #include "lima_regs.h"
  11 
  12 struct lima_bo_va {
  13         struct list_head list;
  14         unsigned int ref_count;
  15 
  16         struct drm_mm_node node;
  17 
  18         struct lima_vm *vm;
  19 };
  20 
  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
  25 
  26 #define LIMA_VM_PT_MASK ((1 << LIMA_VM_PD_SHIFT) - 1)
  27 #define LIMA_VM_BT_MASK ((1 << LIMA_VM_PB_SHIFT) - 1)
  28 
  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)
  33 
  34 
  35 static void lima_vm_unmap_page_table(struct lima_vm *vm, u32 start, u32 end)
  36 {
  37         u32 addr;
  38 
  39         for (addr = start; addr <= end; addr += LIMA_PAGE_SIZE) {
  40                 u32 pbe = LIMA_PBE(addr);
  41                 u32 bte = LIMA_BTE(addr);
  42 
  43                 vm->bts[pbe].cpu[bte] = 0;
  44         }
  45 }
  46 
  47 static int lima_vm_map_page_table(struct lima_vm *vm, dma_addr_t *dma,
  48                                   u32 start, u32 end)
  49 {
  50         u64 addr;
  51         int i = 0;
  52 
  53         for (addr = start; addr <= end; addr += LIMA_PAGE_SIZE) {
  54                 u32 pbe = LIMA_PBE(addr);
  55                 u32 bte = LIMA_BTE(addr);
  56 
  57                 if (!vm->bts[pbe].cpu) {
  58                         dma_addr_t pts;
  59                         u32 *pd;
  60                         int j;
  61 
  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) {
  66                                 if (addr != start)
  67                                         lima_vm_unmap_page_table(vm, start, addr - 1);
  68                                 return -ENOMEM;
  69                         }
  70 
  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;
  76                         }
  77                 }
  78 
  79                 vm->bts[pbe].cpu[bte] = dma[i++] | LIMA_VM_FLAGS_CACHE;
  80         }
  81 
  82         return 0;
  83 }
  84 
  85 static struct lima_bo_va *
  86 lima_vm_bo_find(struct lima_vm *vm, struct lima_bo *bo)
  87 {
  88         struct lima_bo_va *bo_va, *ret = NULL;
  89 
  90         list_for_each_entry(bo_va, &bo->va, list) {
  91                 if (bo_va->vm == vm) {
  92                         ret = bo_va;
  93                         break;
  94                 }
  95         }
  96 
  97         return ret;
  98 }
  99 
 100 int lima_vm_bo_add(struct lima_vm *vm, struct lima_bo *bo, bool create)
 101 {
 102         struct lima_bo_va *bo_va;
 103         int err;
 104 
 105         mutex_lock(&bo->lock);
 106 
 107         bo_va = lima_vm_bo_find(vm, bo);
 108         if (bo_va) {
 109                 bo_va->ref_count++;
 110                 mutex_unlock(&bo->lock);
 111                 return 0;
 112         }
 113 
 114         /* should not create new bo_va if not asked by caller */
 115         if (!create) {
 116                 mutex_unlock(&bo->lock);
 117                 return -ENOENT;
 118         }
 119 
 120         bo_va = kzalloc(sizeof(*bo_va), GFP_KERNEL);
 121         if (!bo_va) {
 122                 err = -ENOMEM;
 123                 goto err_out0;
 124         }
 125 
 126         bo_va->vm = vm;
 127         bo_va->ref_count = 1;
 128 
 129         mutex_lock(&vm->lock);
 130 
 131         err = drm_mm_insert_node(&vm->mm, &bo_va->node, bo->gem.size);
 132         if (err)
 133                 goto err_out1;
 134 
 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);
 137         if (err)
 138                 goto err_out2;
 139 
 140         mutex_unlock(&vm->lock);
 141 
 142         list_add_tail(&bo_va->list, &bo->va);
 143 
 144         mutex_unlock(&bo->lock);
 145         return 0;
 146 
 147 err_out2:
 148         drm_mm_remove_node(&bo_va->node);
 149 err_out1:
 150         mutex_unlock(&vm->lock);
 151         kfree(bo_va);
 152 err_out0:
 153         mutex_unlock(&bo->lock);
 154         return err;
 155 }
 156 
 157 void lima_vm_bo_del(struct lima_vm *vm, struct lima_bo *bo)
 158 {
 159         struct lima_bo_va *bo_va;
 160 
 161         mutex_lock(&bo->lock);
 162 
 163         bo_va = lima_vm_bo_find(vm, bo);
 164         if (--bo_va->ref_count > 0) {
 165                 mutex_unlock(&bo->lock);
 166                 return;
 167         }
 168 
 169         mutex_lock(&vm->lock);
 170 
 171         lima_vm_unmap_page_table(vm, bo_va->node.start,
 172                                  bo_va->node.start + bo_va->node.size - 1);
 173 
 174         drm_mm_remove_node(&bo_va->node);
 175 
 176         mutex_unlock(&vm->lock);
 177 
 178         list_del(&bo_va->list);
 179 
 180         mutex_unlock(&bo->lock);
 181 
 182         kfree(bo_va);
 183 }
 184 
 185 u32 lima_vm_get_va(struct lima_vm *vm, struct lima_bo *bo)
 186 {
 187         struct lima_bo_va *bo_va;
 188         u32 ret;
 189 
 190         mutex_lock(&bo->lock);
 191 
 192         bo_va = lima_vm_bo_find(vm, bo);
 193         ret = bo_va->node.start;
 194 
 195         mutex_unlock(&bo->lock);
 196 
 197         return ret;
 198 }
 199 
 200 struct lima_vm *lima_vm_create(struct lima_device *dev)
 201 {
 202         struct lima_vm *vm;
 203 
 204         vm = kzalloc(sizeof(*vm), GFP_KERNEL);
 205         if (!vm)
 206                 return NULL;
 207 
 208         vm->dev = dev;
 209         mutex_init(&vm->lock);
 210         kref_init(&vm->refcount);
 211 
 212         vm->pd.cpu = dma_alloc_wc(dev->dev, LIMA_PAGE_SIZE, &vm->pd.dma,
 213                                   GFP_KERNEL | __GFP_ZERO);
 214         if (!vm->pd.cpu)
 215                 goto err_out0;
 216 
 217         if (dev->dlbu_cpu) {
 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);
 221                 if (err)
 222                         goto err_out1;
 223         }
 224 
 225         drm_mm_init(&vm->mm, dev->va_start, dev->va_end - dev->va_start);
 226 
 227         return vm;
 228 
 229 err_out1:
 230         dma_free_wc(dev->dev, LIMA_PAGE_SIZE, vm->pd.cpu, vm->pd.dma);
 231 err_out0:
 232         kfree(vm);
 233         return NULL;
 234 }
 235 
 236 void lima_vm_release(struct kref *kref)
 237 {
 238         struct lima_vm *vm = container_of(kref, struct lima_vm, refcount);
 239         int i;
 240 
 241         drm_mm_takedown(&vm->mm);
 242 
 243         for (i = 0; i < LIMA_VM_NUM_BT; i++) {
 244                 if (vm->bts[i].cpu)
 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);
 247         }
 248 
 249         if (vm->pd.cpu)
 250                 dma_free_wc(vm->dev->dev, LIMA_PAGE_SIZE, vm->pd.cpu, vm->pd.dma);
 251 
 252         kfree(vm);
 253 }
 254 
 255 void lima_vm_print(struct lima_vm *vm)
 256 {
 257         int i, j, k;
 258         u32 *pd, *pt;
 259 
 260         if (!vm->pd.cpu)
 261                 return;
 262 
 263         pd = vm->pd.cpu;
 264         for (i = 0; i < LIMA_VM_NUM_BT; i++) {
 265                 if (!vm->bts[i].cpu)
 266                         continue;
 267 
 268                 pt = vm->bts[i].cpu;
 269                 for (j = 0; j < LIMA_VM_NUM_PT_PER_BT; j++) {
 270                         int idx = (i << LIMA_VM_NUM_PT_PER_BT_SHIFT) + j;
 271 
 272                         printk(KERN_INFO "lima vm pd %03x:%08x\n", idx, pd[idx]);
 273 
 274                         for (k = 0; k < LIMA_PAGE_ENT_NUM; k++) {
 275                                 u32 pte = *pt++;
 276 
 277                                 if (pte)
 278                                         printk(KERN_INFO "  pt %03x:%08x\n", k, pte);
 279                         }
 280                 }
 281         }
 282 }

/* [<][>][^][v][top][bottom][index][help] */