diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2011-03-07 18:50:06 -0500 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2011-03-14 02:32:29 -0400 |
commit | 312d1d5fe9b832899b02c620c143bc7eb5a3bdb1 (patch) | |
tree | cc2ae5ef6c19b4c4bbf04aa7f17bb382393f982a | |
parent | bb9b18a390db4a15cd46bbd7472510feb7d4c168 (diff) |
drm/nv50: decode vm faults some more
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_fb.c | 148 |
1 files changed, 142 insertions, 6 deletions
diff --git a/drivers/gpu/drm/nouveau/nv50_fb.c b/drivers/gpu/drm/nouveau/nv50_fb.c index ed411d88451d..705f59743db8 100644 --- a/drivers/gpu/drm/nouveau/nv50_fb.c +++ b/drivers/gpu/drm/nouveau/nv50_fb.c | |||
@@ -114,12 +114,109 @@ nv50_fb_takedown(struct drm_device *dev) | |||
114 | nv50_fb_destroy(dev); | 114 | nv50_fb_destroy(dev); |
115 | } | 115 | } |
116 | 116 | ||
117 | static 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 | |||
128 | static struct nouveau_enum vm_ccache_subclients[] = { | ||
129 | { 0x00000000, "CB", NULL }, | ||
130 | { 0x00000001, "TIC", NULL }, | ||
131 | { 0x00000002, "TSC", NULL }, | ||
132 | {} | ||
133 | }; | ||
134 | |||
135 | static 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 | |||
152 | static struct nouveau_enum vm_pfifo_subclients[] = { | ||
153 | { 0x00000000, "PUSHBUF", NULL }, | ||
154 | { 0x00000001, "SEMAPHORE", NULL }, | ||
155 | {} | ||
156 | }; | ||
157 | |||
158 | static struct nouveau_enum vm_bar_subclients[] = { | ||
159 | { 0x00000000, "FB", NULL }, | ||
160 | { 0x00000001, "IN", NULL }, | ||
161 | {} | ||
162 | }; | ||
163 | |||
164 | static 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 | |||
183 | static 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 | |||
199 | static 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 | |||
117 | void | 212 | void |
118 | nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name) | 213 | nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name) |
119 | { | 214 | { |
120 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 215 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
216 | const struct nouveau_enum *en, *cl; | ||
121 | unsigned long flags; | 217 | unsigned long flags; |
122 | u32 trap[6], idx, chinst; | 218 | u32 trap[6], idx, chinst; |
219 | u8 st0, st1, st2, st3; | ||
123 | int i, ch; | 220 | int i, ch; |
124 | 221 | ||
125 | idx = nv_rd32(dev, 0x100c90); | 222 | idx = nv_rd32(dev, 0x100c90); |
@@ -136,8 +233,8 @@ nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name) | |||
136 | if (!display) | 233 | if (!display) |
137 | return; | 234 | return; |
138 | 235 | ||
236 | /* lookup channel id */ | ||
139 | chinst = (trap[2] << 16) | trap[1]; | 237 | chinst = (trap[2] << 16) | trap[1]; |
140 | |||
141 | spin_lock_irqsave(&dev_priv->channels.lock, flags); | 238 | spin_lock_irqsave(&dev_priv->channels.lock, flags); |
142 | for (ch = 0; ch < dev_priv->engine.fifo.channels; ch++) { | 239 | for (ch = 0; ch < dev_priv->engine.fifo.channels; ch++) { |
143 | struct nouveau_channel *chan = dev_priv->channels.ptr[ch]; | 240 | struct nouveau_channel *chan = dev_priv->channels.ptr[ch]; |
@@ -150,9 +247,48 @@ nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name) | |||
150 | } | 247 | } |
151 | spin_unlock_irqrestore(&dev_priv->channels.lock, flags); | 248 | spin_unlock_irqrestore(&dev_priv->channels.lock, flags); |
152 | 249 | ||
153 | NV_INFO(dev, "%s - VM: Trapped %s at %02x%04x%04x status %08x " | 250 | /* decode status bits into something more useful */ |
154 | "channel %d (0x%08x)\n", | 251 | if (dev_priv->chipset < 0xa3 || |
155 | name, (trap[5] & 0x100 ? "read" : "write"), | 252 | dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) { |
156 | trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, | 253 | st0 = (trap[0] & 0x0000000f) >> 0; |
157 | trap[0], ch, chinst); | 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); | ||
158 | } | 294 | } |