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