Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
base.c
Go to the documentation of this file.
1 /*
2  * Copyright 2010 Red Hat Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: Ben Skeggs
23  */
24 
25 #include <core/gpuobj.h>
26 #include <core/mm.h>
27 
28 #include <subdev/fb.h>
29 #include <subdev/vm.h>
30 
31 void
33 {
34  struct nouveau_vm *vm = vma->vm;
35  struct nouveau_vmmgr *vmm = vm->vmm;
36  struct nouveau_mm_node *r;
37  int big = vma->node->type != vmm->spg_shift;
38  u32 offset = vma->node->offset + (delta >> 12);
39  u32 bits = vma->node->type - 12;
40  u32 pde = (offset >> vmm->pgt_bits) - vm->fpde;
41  u32 pte = (offset & ((1 << vmm->pgt_bits) - 1)) >> bits;
42  u32 max = 1 << (vmm->pgt_bits - bits);
43  u32 end, len;
44 
45  delta = 0;
47  u64 phys = (u64)r->offset << 12;
48  u32 num = r->length >> bits;
49 
50  while (num) {
51  struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big];
52 
53  end = (pte + num);
54  if (unlikely(end >= max))
55  end = max;
56  len = end - pte;
57 
58  vmm->map(vma, pgt, node, pte, len, phys, delta);
59 
60  num -= len;
61  pte += len;
62  if (unlikely(end >= max)) {
63  phys += len << (bits + 12);
64  pde++;
65  pte = 0;
66  }
67 
68  delta += (u64)len << vma->node->type;
69  }
70  }
71 
72  vmm->flush(vm);
73 }
74 
75 void
77 {
78  nouveau_vm_map_at(vma, 0, node);
79 }
80 
81 void
83  struct nouveau_mem *mem)
84 {
85  struct nouveau_vm *vm = vma->vm;
86  struct nouveau_vmmgr *vmm = vm->vmm;
87  int big = vma->node->type != vmm->spg_shift;
88  u32 offset = vma->node->offset + (delta >> 12);
89  u32 bits = vma->node->type - 12;
90  u32 num = length >> vma->node->type;
91  u32 pde = (offset >> vmm->pgt_bits) - vm->fpde;
92  u32 pte = (offset & ((1 << vmm->pgt_bits) - 1)) >> bits;
93  u32 max = 1 << (vmm->pgt_bits - bits);
94  unsigned m, sglen;
95  u32 end, len;
96  int i;
97  struct scatterlist *sg;
98 
99  for_each_sg(mem->sg->sgl, sg, mem->sg->nents, i) {
100  struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big];
101  sglen = sg_dma_len(sg) >> PAGE_SHIFT;
102 
103  end = pte + sglen;
104  if (unlikely(end >= max))
105  end = max;
106  len = end - pte;
107 
108  for (m = 0; m < len; m++) {
109  dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
110 
111  vmm->map_sg(vma, pgt, mem, pte, 1, &addr);
112  num--;
113  pte++;
114 
115  if (num == 0)
116  goto finish;
117  }
118  if (unlikely(end >= max)) {
119  pde++;
120  pte = 0;
121  }
122  if (m < sglen) {
123  for (; m < sglen; m++) {
124  dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
125 
126  vmm->map_sg(vma, pgt, mem, pte, 1, &addr);
127  num--;
128  pte++;
129  if (num == 0)
130  goto finish;
131  }
132  }
133 
134  }
135 finish:
136  vmm->flush(vm);
137 }
138 
139 void
141  struct nouveau_mem *mem)
142 {
143  struct nouveau_vm *vm = vma->vm;
144  struct nouveau_vmmgr *vmm = vm->vmm;
145  dma_addr_t *list = mem->pages;
146  int big = vma->node->type != vmm->spg_shift;
147  u32 offset = vma->node->offset + (delta >> 12);
148  u32 bits = vma->node->type - 12;
149  u32 num = length >> vma->node->type;
150  u32 pde = (offset >> vmm->pgt_bits) - vm->fpde;
151  u32 pte = (offset & ((1 << vmm->pgt_bits) - 1)) >> bits;
152  u32 max = 1 << (vmm->pgt_bits - bits);
153  u32 end, len;
154 
155  while (num) {
156  struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big];
157 
158  end = (pte + num);
159  if (unlikely(end >= max))
160  end = max;
161  len = end - pte;
162 
163  vmm->map_sg(vma, pgt, mem, pte, len, list);
164 
165  num -= len;
166  pte += len;
167  list += len;
168  if (unlikely(end >= max)) {
169  pde++;
170  pte = 0;
171  }
172  }
173 
174  vmm->flush(vm);
175 }
176 
177 void
179 {
180  struct nouveau_vm *vm = vma->vm;
181  struct nouveau_vmmgr *vmm = vm->vmm;
182  int big = vma->node->type != vmm->spg_shift;
183  u32 offset = vma->node->offset + (delta >> 12);
184  u32 bits = vma->node->type - 12;
185  u32 num = length >> vma->node->type;
186  u32 pde = (offset >> vmm->pgt_bits) - vm->fpde;
187  u32 pte = (offset & ((1 << vmm->pgt_bits) - 1)) >> bits;
188  u32 max = 1 << (vmm->pgt_bits - bits);
189  u32 end, len;
190 
191  while (num) {
192  struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big];
193 
194  end = (pte + num);
195  if (unlikely(end >= max))
196  end = max;
197  len = end - pte;
198 
199  vmm->unmap(pgt, pte, len);
200 
201  num -= len;
202  pte += len;
203  if (unlikely(end >= max)) {
204  pde++;
205  pte = 0;
206  }
207  }
208 
209  vmm->flush(vm);
210 }
211 
212 void
214 {
215  nouveau_vm_unmap_at(vma, 0, (u64)vma->node->length << 12);
216 }
217 
218 static void
219 nouveau_vm_unmap_pgt(struct nouveau_vm *vm, int big, u32 fpde, u32 lpde)
220 {
221  struct nouveau_vmmgr *vmm = vm->vmm;
222  struct nouveau_vm_pgd *vpgd;
223  struct nouveau_vm_pgt *vpgt;
224  struct nouveau_gpuobj *pgt;
225  u32 pde;
226 
227  for (pde = fpde; pde <= lpde; pde++) {
228  vpgt = &vm->pgt[pde - vm->fpde];
229  if (--vpgt->refcount[big])
230  continue;
231 
232  pgt = vpgt->obj[big];
233  vpgt->obj[big] = NULL;
234 
235  list_for_each_entry(vpgd, &vm->pgd_list, head) {
236  vmm->map_pgt(vpgd->obj, pde, vpgt->obj);
237  }
238 
239  mutex_unlock(&vm->mm.mutex);
240  nouveau_gpuobj_ref(NULL, &pgt);
241  mutex_lock(&vm->mm.mutex);
242  }
243 }
244 
245 static int
246 nouveau_vm_map_pgt(struct nouveau_vm *vm, u32 pde, u32 type)
247 {
248  struct nouveau_vmmgr *vmm = vm->vmm;
249  struct nouveau_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde];
250  struct nouveau_vm_pgd *vpgd;
251  struct nouveau_gpuobj *pgt;
252  int big = (type != vmm->spg_shift);
253  u32 pgt_size;
254  int ret;
255 
256  pgt_size = (1 << (vmm->pgt_bits + 12)) >> type;
257  pgt_size *= 8;
258 
259  mutex_unlock(&vm->mm.mutex);
260  ret = nouveau_gpuobj_new(nv_object(vm->vmm), NULL, pgt_size, 0x1000,
261  NVOBJ_FLAG_ZERO_ALLOC, &pgt);
262  mutex_lock(&vm->mm.mutex);
263  if (unlikely(ret))
264  return ret;
265 
266  /* someone beat us to filling the PDE while we didn't have the lock */
267  if (unlikely(vpgt->refcount[big]++)) {
268  mutex_unlock(&vm->mm.mutex);
269  nouveau_gpuobj_ref(NULL, &pgt);
270  mutex_lock(&vm->mm.mutex);
271  return 0;
272  }
273 
274  vpgt->obj[big] = pgt;
275  list_for_each_entry(vpgd, &vm->pgd_list, head) {
276  vmm->map_pgt(vpgd->obj, pde, vpgt->obj);
277  }
278 
279  return 0;
280 }
281 
282 int
283 nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift,
284  u32 access, struct nouveau_vma *vma)
285 {
286  struct nouveau_vmmgr *vmm = vm->vmm;
287  u32 align = (1 << page_shift) >> 12;
288  u32 msize = size >> 12;
289  u32 fpde, lpde, pde;
290  int ret;
291 
292  mutex_lock(&vm->mm.mutex);
293  ret = nouveau_mm_head(&vm->mm, page_shift, msize, msize, align,
294  &vma->node);
295  if (unlikely(ret != 0)) {
296  mutex_unlock(&vm->mm.mutex);
297  return ret;
298  }
299 
300  fpde = (vma->node->offset >> vmm->pgt_bits);
301  lpde = (vma->node->offset + vma->node->length - 1) >> vmm->pgt_bits;
302 
303  for (pde = fpde; pde <= lpde; pde++) {
304  struct nouveau_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde];
305  int big = (vma->node->type != vmm->spg_shift);
306 
307  if (likely(vpgt->refcount[big])) {
308  vpgt->refcount[big]++;
309  continue;
310  }
311 
312  ret = nouveau_vm_map_pgt(vm, pde, vma->node->type);
313  if (ret) {
314  if (pde != fpde)
315  nouveau_vm_unmap_pgt(vm, big, fpde, pde - 1);
316  nouveau_mm_free(&vm->mm, &vma->node);
317  mutex_unlock(&vm->mm.mutex);
318  return ret;
319  }
320  }
321  mutex_unlock(&vm->mm.mutex);
322 
323  vma->vm = vm;
324  vma->offset = (u64)vma->node->offset << 12;
325  vma->access = access;
326  return 0;
327 }
328 
329 void
331 {
332  struct nouveau_vm *vm = vma->vm;
333  struct nouveau_vmmgr *vmm = vm->vmm;
334  u32 fpde, lpde;
335 
336  if (unlikely(vma->node == NULL))
337  return;
338  fpde = (vma->node->offset >> vmm->pgt_bits);
339  lpde = (vma->node->offset + vma->node->length - 1) >> vmm->pgt_bits;
340 
341  mutex_lock(&vm->mm.mutex);
342  nouveau_vm_unmap_pgt(vm, vma->node->type != vmm->spg_shift, fpde, lpde);
343  nouveau_mm_free(&vm->mm, &vma->node);
344  mutex_unlock(&vm->mm.mutex);
345 }
346 
347 int
349  u64 mm_offset, u32 block, struct nouveau_vm **pvm)
350 {
351  struct nouveau_vm *vm;
352  u64 mm_length = (offset + length) - mm_offset;
353  int ret;
354 
355  vm = *pvm = kzalloc(sizeof(*vm), GFP_KERNEL);
356  if (!vm)
357  return -ENOMEM;
358 
359  INIT_LIST_HEAD(&vm->pgd_list);
360  vm->vmm = vmm;
361  vm->refcount = 1;
362  vm->fpde = offset >> (vmm->pgt_bits + 12);
363  vm->lpde = (offset + length - 1) >> (vmm->pgt_bits + 12);
364 
365  vm->pgt = kcalloc(vm->lpde - vm->fpde + 1, sizeof(*vm->pgt), GFP_KERNEL);
366  if (!vm->pgt) {
367  kfree(vm);
368  return -ENOMEM;
369  }
370 
371  ret = nouveau_mm_init(&vm->mm, mm_offset >> 12, mm_length >> 12,
372  block >> 12);
373  if (ret) {
374  kfree(vm->pgt);
375  kfree(vm);
376  return ret;
377  }
378 
379  return 0;
380 }
381 
382 int
384  u64 mm_offset, struct nouveau_vm **pvm)
385 {
386  struct nouveau_vmmgr *vmm = nouveau_vmmgr(device);
387  return vmm->create(vmm, offset, length, mm_offset, pvm);
388 }
389 
390 static int
391 nouveau_vm_link(struct nouveau_vm *vm, struct nouveau_gpuobj *pgd)
392 {
393  struct nouveau_vmmgr *vmm = vm->vmm;
394  struct nouveau_vm_pgd *vpgd;
395  int i;
396 
397  if (!pgd)
398  return 0;
399 
400  vpgd = kzalloc(sizeof(*vpgd), GFP_KERNEL);
401  if (!vpgd)
402  return -ENOMEM;
403 
404  nouveau_gpuobj_ref(pgd, &vpgd->obj);
405 
406  mutex_lock(&vm->mm.mutex);
407  for (i = vm->fpde; i <= vm->lpde; i++)
408  vmm->map_pgt(pgd, i, vm->pgt[i - vm->fpde].obj);
409  list_add(&vpgd->head, &vm->pgd_list);
410  mutex_unlock(&vm->mm.mutex);
411  return 0;
412 }
413 
414 static void
415 nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd)
416 {
417  struct nouveau_vm_pgd *vpgd, *tmp;
418  struct nouveau_gpuobj *pgd = NULL;
419 
420  if (!mpgd)
421  return;
422 
423  mutex_lock(&vm->mm.mutex);
424  list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) {
425  if (vpgd->obj == mpgd) {
426  pgd = vpgd->obj;
427  list_del(&vpgd->head);
428  kfree(vpgd);
429  break;
430  }
431  }
432  mutex_unlock(&vm->mm.mutex);
433 
434  nouveau_gpuobj_ref(NULL, &pgd);
435 }
436 
437 static void
438 nouveau_vm_del(struct nouveau_vm *vm)
439 {
440  struct nouveau_vm_pgd *vpgd, *tmp;
441 
442  list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) {
443  nouveau_vm_unlink(vm, vpgd->obj);
444  }
445 
446  nouveau_mm_fini(&vm->mm);
447  kfree(vm->pgt);
448  kfree(vm);
449 }
450 
451 int
452 nouveau_vm_ref(struct nouveau_vm *ref, struct nouveau_vm **ptr,
453  struct nouveau_gpuobj *pgd)
454 {
455  struct nouveau_vm *vm;
456  int ret;
457 
458  vm = ref;
459  if (vm) {
460  ret = nouveau_vm_link(vm, pgd);
461  if (ret)
462  return ret;
463 
464  vm->refcount++;
465  }
466 
467  vm = *ptr;
468  *ptr = ref;
469 
470  if (vm) {
471  nouveau_vm_unlink(vm, pgd);
472 
473  if (--vm->refcount == 0)
474  nouveau_vm_del(vm);
475  }
476 
477  return 0;
478 }