nv50_fb.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. #include "drmP.h"
  2. #include "drm.h"
  3. #include "nouveau_drv.h"
  4. #include "nouveau_drm.h"
  5. struct nv50_fb_priv {
  6. struct page *r100c08_page;
  7. dma_addr_t r100c08;
  8. };
  9. static void
  10. nv50_fb_destroy(struct drm_device *dev)
  11. {
  12. struct drm_nouveau_private *dev_priv = dev->dev_private;
  13. struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
  14. struct nv50_fb_priv *priv = pfb->priv;
  15. if (drm_mm_initialized(&pfb->tag_heap))
  16. drm_mm_takedown(&pfb->tag_heap);
  17. if (priv->r100c08_page) {
  18. pci_unmap_page(dev->pdev, priv->r100c08, PAGE_SIZE,
  19. PCI_DMA_BIDIRECTIONAL);
  20. __free_page(priv->r100c08_page);
  21. }
  22. kfree(priv);
  23. pfb->priv = NULL;
  24. }
  25. static int
  26. nv50_fb_create(struct drm_device *dev)
  27. {
  28. struct drm_nouveau_private *dev_priv = dev->dev_private;
  29. struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
  30. struct nv50_fb_priv *priv;
  31. u32 tagmem;
  32. int ret;
  33. priv = kzalloc(sizeof(*priv), GFP_KERNEL);
  34. if (!priv)
  35. return -ENOMEM;
  36. pfb->priv = priv;
  37. priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
  38. if (!priv->r100c08_page) {
  39. nv50_fb_destroy(dev);
  40. return -ENOMEM;
  41. }
  42. priv->r100c08 = pci_map_page(dev->pdev, priv->r100c08_page, 0,
  43. PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
  44. if (pci_dma_mapping_error(dev->pdev, priv->r100c08)) {
  45. nv50_fb_destroy(dev);
  46. return -EFAULT;
  47. }
  48. tagmem = nv_rd32(dev, 0x100320);
  49. NV_DEBUG(dev, "%d tags available\n", tagmem);
  50. ret = drm_mm_init(&pfb->tag_heap, 0, tagmem);
  51. if (ret) {
  52. nv50_fb_destroy(dev);
  53. return ret;
  54. }
  55. return 0;
  56. }
  57. int
  58. nv50_fb_init(struct drm_device *dev)
  59. {
  60. struct drm_nouveau_private *dev_priv = dev->dev_private;
  61. struct nv50_fb_priv *priv;
  62. int ret;
  63. if (!dev_priv->engine.fb.priv) {
  64. ret = nv50_fb_create(dev);
  65. if (ret)
  66. return ret;
  67. }
  68. priv = dev_priv->engine.fb.priv;
  69. /* Not a clue what this is exactly. Without pointing it at a
  70. * scratch page, VRAM->GART blits with M2MF (as in DDX DFS)
  71. * cause IOMMU "read from address 0" errors (rh#561267)
  72. */
  73. nv_wr32(dev, 0x100c08, priv->r100c08 >> 8);
  74. /* This is needed to get meaningful information from 100c90
  75. * on traps. No idea what these values mean exactly. */
  76. switch (dev_priv->chipset) {
  77. case 0x50:
  78. nv_wr32(dev, 0x100c90, 0x000707ff);
  79. break;
  80. case 0xa3:
  81. case 0xa5:
  82. case 0xa8:
  83. nv_wr32(dev, 0x100c90, 0x000d0fff);
  84. break;
  85. case 0xaf:
  86. nv_wr32(dev, 0x100c90, 0x089d1fff);
  87. break;
  88. default:
  89. nv_wr32(dev, 0x100c90, 0x001d07ff);
  90. break;
  91. }
  92. return 0;
  93. }
  94. void
  95. nv50_fb_takedown(struct drm_device *dev)
  96. {
  97. nv50_fb_destroy(dev);
  98. }
  99. static struct nouveau_enum vm_dispatch_subclients[] = {
  100. { 0x00000000, "GRCTX", NULL },
  101. { 0x00000001, "NOTIFY", NULL },
  102. { 0x00000002, "QUERY", NULL },
  103. { 0x00000003, "COND", NULL },
  104. { 0x00000004, "M2M_IN", NULL },
  105. { 0x00000005, "M2M_OUT", NULL },
  106. { 0x00000006, "M2M_NOTIFY", NULL },
  107. {}
  108. };
  109. static struct nouveau_enum vm_ccache_subclients[] = {
  110. { 0x00000000, "CB", NULL },
  111. { 0x00000001, "TIC", NULL },
  112. { 0x00000002, "TSC", NULL },
  113. {}
  114. };
  115. static struct nouveau_enum vm_prop_subclients[] = {
  116. { 0x00000000, "RT0", NULL },
  117. { 0x00000001, "RT1", NULL },
  118. { 0x00000002, "RT2", NULL },
  119. { 0x00000003, "RT3", NULL },
  120. { 0x00000004, "RT4", NULL },
  121. { 0x00000005, "RT5", NULL },
  122. { 0x00000006, "RT6", NULL },
  123. { 0x00000007, "RT7", NULL },
  124. { 0x00000008, "ZETA", NULL },
  125. { 0x00000009, "LOCAL", NULL },
  126. { 0x0000000a, "GLOBAL", NULL },
  127. { 0x0000000b, "STACK", NULL },
  128. { 0x0000000c, "DST2D", NULL },
  129. {}
  130. };
  131. static struct nouveau_enum vm_pfifo_subclients[] = {
  132. { 0x00000000, "PUSHBUF", NULL },
  133. { 0x00000001, "SEMAPHORE", NULL },
  134. {}
  135. };
  136. static struct nouveau_enum vm_bar_subclients[] = {
  137. { 0x00000000, "FB", NULL },
  138. { 0x00000001, "IN", NULL },
  139. {}
  140. };
  141. static struct nouveau_enum vm_client[] = {
  142. { 0x00000000, "STRMOUT", NULL },
  143. { 0x00000003, "DISPATCH", vm_dispatch_subclients },
  144. { 0x00000004, "PFIFO_WRITE", NULL },
  145. { 0x00000005, "CCACHE", vm_ccache_subclients },
  146. { 0x00000006, "PPPP", NULL },
  147. { 0x00000007, "CLIPID", NULL },
  148. { 0x00000008, "PFIFO_READ", NULL },
  149. { 0x00000009, "VFETCH", NULL },
  150. { 0x0000000a, "TEXTURE", NULL },
  151. { 0x0000000b, "PROP", vm_prop_subclients },
  152. { 0x0000000c, "PVP", NULL },
  153. { 0x0000000d, "PBSP", NULL },
  154. { 0x0000000e, "PCRYPT", NULL },
  155. { 0x0000000f, "PCOUNTER", NULL },
  156. { 0x00000011, "PDAEMON", NULL },
  157. {}
  158. };
  159. static struct nouveau_enum vm_engine[] = {
  160. { 0x00000000, "PGRAPH", NULL },
  161. { 0x00000001, "PVP", NULL },
  162. { 0x00000004, "PEEPHOLE", NULL },
  163. { 0x00000005, "PFIFO", vm_pfifo_subclients },
  164. { 0x00000006, "BAR", vm_bar_subclients },
  165. { 0x00000008, "PPPP", NULL },
  166. { 0x00000009, "PBSP", NULL },
  167. { 0x0000000a, "PCRYPT", NULL },
  168. { 0x0000000b, "PCOUNTER", NULL },
  169. { 0x0000000c, "SEMAPHORE_BG", NULL },
  170. { 0x0000000d, "PCOPY", NULL },
  171. { 0x0000000e, "PDAEMON", NULL },
  172. {}
  173. };
  174. static struct nouveau_enum vm_fault[] = {
  175. { 0x00000000, "PT_NOT_PRESENT", NULL },
  176. { 0x00000001, "PT_TOO_SHORT", NULL },
  177. { 0x00000002, "PAGE_NOT_PRESENT", NULL },
  178. { 0x00000003, "PAGE_SYSTEM_ONLY", NULL },
  179. { 0x00000004, "PAGE_READ_ONLY", NULL },
  180. { 0x00000006, "NULL_DMAOBJ", NULL },
  181. { 0x00000007, "WRONG_MEMTYPE", NULL },
  182. { 0x0000000b, "VRAM_LIMIT", NULL },
  183. { 0x0000000f, "DMAOBJ_LIMIT", NULL },
  184. {}
  185. };
  186. void
  187. nv50_fb_vm_trap(struct drm_device *dev, int display)
  188. {
  189. struct drm_nouveau_private *dev_priv = dev->dev_private;
  190. const struct nouveau_enum *en, *cl;
  191. unsigned long flags;
  192. u32 trap[6], idx, chinst;
  193. u8 st0, st1, st2, st3;
  194. int i, ch;
  195. idx = nv_rd32(dev, 0x100c90);
  196. if (!(idx & 0x80000000))
  197. return;
  198. idx &= 0x00ffffff;
  199. for (i = 0; i < 6; i++) {
  200. nv_wr32(dev, 0x100c90, idx | i << 24);
  201. trap[i] = nv_rd32(dev, 0x100c94);
  202. }
  203. nv_wr32(dev, 0x100c90, idx | 0x80000000);
  204. if (!display)
  205. return;
  206. /* lookup channel id */
  207. chinst = (trap[2] << 16) | trap[1];
  208. spin_lock_irqsave(&dev_priv->channels.lock, flags);
  209. for (ch = 0; ch < dev_priv->engine.fifo.channels; ch++) {
  210. struct nouveau_channel *chan = dev_priv->channels.ptr[ch];
  211. if (!chan || !chan->ramin)
  212. continue;
  213. if (chinst == chan->ramin->vinst >> 12)
  214. break;
  215. }
  216. spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
  217. /* decode status bits into something more useful */
  218. if (dev_priv->chipset < 0xa3 ||
  219. dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) {
  220. st0 = (trap[0] & 0x0000000f) >> 0;
  221. st1 = (trap[0] & 0x000000f0) >> 4;
  222. st2 = (trap[0] & 0x00000f00) >> 8;
  223. st3 = (trap[0] & 0x0000f000) >> 12;
  224. } else {
  225. st0 = (trap[0] & 0x000000ff) >> 0;
  226. st1 = (trap[0] & 0x0000ff00) >> 8;
  227. st2 = (trap[0] & 0x00ff0000) >> 16;
  228. st3 = (trap[0] & 0xff000000) >> 24;
  229. }
  230. NV_INFO(dev, "VM: trapped %s at 0x%02x%04x%04x on ch %d [0x%08x] ",
  231. (trap[5] & 0x00000100) ? "read" : "write",
  232. trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, ch, chinst);
  233. en = nouveau_enum_find(vm_engine, st0);
  234. if (en)
  235. printk("%s/", en->name);
  236. else
  237. printk("%02x/", st0);
  238. cl = nouveau_enum_find(vm_client, st2);
  239. if (cl)
  240. printk("%s/", cl->name);
  241. else
  242. printk("%02x/", st2);
  243. if (cl && cl->data) cl = nouveau_enum_find(cl->data, st3);
  244. else if (en && en->data) cl = nouveau_enum_find(en->data, st3);
  245. else cl = NULL;
  246. if (cl)
  247. printk("%s", cl->name);
  248. else
  249. printk("%02x", st3);
  250. printk(" reason: ");
  251. en = nouveau_enum_find(vm_fault, st1);
  252. if (en)
  253. printk("%s\n", en->name);
  254. else
  255. printk("0x%08x\n", st1);
  256. }