nv44.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /*
  2. * Copyright 2012 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. #include "nv04.h"
  25. #include <core/gpuobj.h>
  26. #include <core/option.h>
  27. #include <subdev/timer.h>
  28. #define NV44_GART_SIZE (512 * 1024 * 1024)
  29. #define NV44_GART_PAGE ( 4 * 1024)
  30. /*******************************************************************************
  31. * VM map/unmap callbacks
  32. ******************************************************************************/
  33. static void
  34. nv44_vm_fill(struct nvkm_memory *pgt, dma_addr_t null,
  35. dma_addr_t *list, u32 pte, u32 cnt)
  36. {
  37. u32 base = (pte << 2) & ~0x0000000f;
  38. u32 tmp[4];
  39. tmp[0] = nvkm_ro32(pgt, base + 0x0);
  40. tmp[1] = nvkm_ro32(pgt, base + 0x4);
  41. tmp[2] = nvkm_ro32(pgt, base + 0x8);
  42. tmp[3] = nvkm_ro32(pgt, base + 0xc);
  43. while (cnt--) {
  44. u32 addr = list ? (*list++ >> 12) : (null >> 12);
  45. switch (pte++ & 0x3) {
  46. case 0:
  47. tmp[0] &= ~0x07ffffff;
  48. tmp[0] |= addr;
  49. break;
  50. case 1:
  51. tmp[0] &= ~0xf8000000;
  52. tmp[0] |= addr << 27;
  53. tmp[1] &= ~0x003fffff;
  54. tmp[1] |= addr >> 5;
  55. break;
  56. case 2:
  57. tmp[1] &= ~0xffc00000;
  58. tmp[1] |= addr << 22;
  59. tmp[2] &= ~0x0001ffff;
  60. tmp[2] |= addr >> 10;
  61. break;
  62. case 3:
  63. tmp[2] &= ~0xfffe0000;
  64. tmp[2] |= addr << 17;
  65. tmp[3] &= ~0x00000fff;
  66. tmp[3] |= addr >> 15;
  67. break;
  68. }
  69. }
  70. nvkm_wo32(pgt, base + 0x0, tmp[0]);
  71. nvkm_wo32(pgt, base + 0x4, tmp[1]);
  72. nvkm_wo32(pgt, base + 0x8, tmp[2]);
  73. nvkm_wo32(pgt, base + 0xc, tmp[3] | 0x40000000);
  74. }
  75. static void
  76. nv44_vm_map_sg(struct nvkm_vma *vma, struct nvkm_memory *pgt,
  77. struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
  78. {
  79. struct nv04_mmu *mmu = nv04_mmu(vma->vm->mmu);
  80. u32 tmp[4];
  81. int i;
  82. nvkm_kmap(pgt);
  83. if (pte & 3) {
  84. u32 max = 4 - (pte & 3);
  85. u32 part = (cnt > max) ? max : cnt;
  86. nv44_vm_fill(pgt, mmu->null, list, pte, part);
  87. pte += part;
  88. list += part;
  89. cnt -= part;
  90. }
  91. while (cnt >= 4) {
  92. for (i = 0; i < 4; i++)
  93. tmp[i] = *list++ >> 12;
  94. nvkm_wo32(pgt, pte++ * 4, tmp[0] >> 0 | tmp[1] << 27);
  95. nvkm_wo32(pgt, pte++ * 4, tmp[1] >> 5 | tmp[2] << 22);
  96. nvkm_wo32(pgt, pte++ * 4, tmp[2] >> 10 | tmp[3] << 17);
  97. nvkm_wo32(pgt, pte++ * 4, tmp[3] >> 15 | 0x40000000);
  98. cnt -= 4;
  99. }
  100. if (cnt)
  101. nv44_vm_fill(pgt, mmu->null, list, pte, cnt);
  102. nvkm_done(pgt);
  103. }
  104. static void
  105. nv44_vm_unmap(struct nvkm_vma *vma, struct nvkm_memory *pgt, u32 pte, u32 cnt)
  106. {
  107. struct nv04_mmu *mmu = nv04_mmu(vma->vm->mmu);
  108. nvkm_kmap(pgt);
  109. if (pte & 3) {
  110. u32 max = 4 - (pte & 3);
  111. u32 part = (cnt > max) ? max : cnt;
  112. nv44_vm_fill(pgt, mmu->null, NULL, pte, part);
  113. pte += part;
  114. cnt -= part;
  115. }
  116. while (cnt >= 4) {
  117. nvkm_wo32(pgt, pte++ * 4, 0x00000000);
  118. nvkm_wo32(pgt, pte++ * 4, 0x00000000);
  119. nvkm_wo32(pgt, pte++ * 4, 0x00000000);
  120. nvkm_wo32(pgt, pte++ * 4, 0x00000000);
  121. cnt -= 4;
  122. }
  123. if (cnt)
  124. nv44_vm_fill(pgt, mmu->null, NULL, pte, cnt);
  125. nvkm_done(pgt);
  126. }
  127. static void
  128. nv44_vm_flush(struct nvkm_vm *vm)
  129. {
  130. struct nv04_mmu *mmu = nv04_mmu(vm->mmu);
  131. struct nvkm_device *device = mmu->base.subdev.device;
  132. nvkm_wr32(device, 0x100814, mmu->base.limit - NV44_GART_PAGE);
  133. nvkm_wr32(device, 0x100808, 0x00000020);
  134. nvkm_msec(device, 2000,
  135. if (nvkm_rd32(device, 0x100808) & 0x00000001)
  136. break;
  137. );
  138. nvkm_wr32(device, 0x100808, 0x00000000);
  139. }
  140. /*******************************************************************************
  141. * MMU subdev
  142. ******************************************************************************/
  143. static int
  144. nv44_mmu_oneinit(struct nvkm_mmu *base)
  145. {
  146. struct nv04_mmu *mmu = nv04_mmu(base);
  147. struct nvkm_device *device = mmu->base.subdev.device;
  148. int ret;
  149. mmu->nullp = dma_alloc_coherent(device->dev, 16 * 1024,
  150. &mmu->null, GFP_KERNEL);
  151. if (!mmu->nullp) {
  152. nvkm_warn(&mmu->base.subdev, "unable to allocate dummy pages\n");
  153. mmu->null = 0;
  154. }
  155. ret = nvkm_vm_create(&mmu->base, 0, NV44_GART_SIZE, 0, 4096, NULL,
  156. &mmu->vm);
  157. if (ret)
  158. return ret;
  159. ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST,
  160. (NV44_GART_SIZE / NV44_GART_PAGE) * 4,
  161. 512 * 1024, true,
  162. &mmu->vm->pgt[0].mem[0]);
  163. mmu->vm->pgt[0].refcount[0] = 1;
  164. return ret;
  165. }
  166. static void
  167. nv44_mmu_init(struct nvkm_mmu *base)
  168. {
  169. struct nv04_mmu *mmu = nv04_mmu(base);
  170. struct nvkm_device *device = mmu->base.subdev.device;
  171. struct nvkm_memory *gart = mmu->vm->pgt[0].mem[0];
  172. u32 addr;
  173. /* calculate vram address of this PRAMIN block, object must be
  174. * allocated on 512KiB alignment, and not exceed a total size
  175. * of 512KiB for this to work correctly
  176. */
  177. addr = nvkm_rd32(device, 0x10020c);
  178. addr -= ((nvkm_memory_addr(gart) >> 19) + 1) << 19;
  179. nvkm_wr32(device, 0x100850, 0x80000000);
  180. nvkm_wr32(device, 0x100818, mmu->null);
  181. nvkm_wr32(device, 0x100804, NV44_GART_SIZE);
  182. nvkm_wr32(device, 0x100850, 0x00008000);
  183. nvkm_mask(device, 0x10008c, 0x00000200, 0x00000200);
  184. nvkm_wr32(device, 0x100820, 0x00000000);
  185. nvkm_wr32(device, 0x10082c, 0x00000001);
  186. nvkm_wr32(device, 0x100800, addr | 0x00000010);
  187. }
  188. static const struct nvkm_mmu_func
  189. nv44_mmu = {
  190. .dtor = nv04_mmu_dtor,
  191. .oneinit = nv44_mmu_oneinit,
  192. .init = nv44_mmu_init,
  193. .limit = NV44_GART_SIZE,
  194. .dma_bits = 39,
  195. .pgt_bits = 32 - 12,
  196. .spg_shift = 12,
  197. .lpg_shift = 12,
  198. .map_sg = nv44_vm_map_sg,
  199. .unmap = nv44_vm_unmap,
  200. .flush = nv44_vm_flush,
  201. };
  202. int
  203. nv44_mmu_new(struct nvkm_device *device, int index, struct nvkm_mmu **pmmu)
  204. {
  205. if (device->type == NVKM_DEVICE_AGP ||
  206. !nvkm_boolopt(device->cfgopt, "NvPCIE", true))
  207. return nv04_mmu_new(device, index, pmmu);
  208. return nv04_mmu_new_(&nv44_mmu, device, index, pmmu);
  209. }