diff options
author | Paul Mundt <lethal@linux-sh.org> | 2011-01-12 00:37:42 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2011-01-12 00:37:42 -0500 |
commit | 83eb95b852902f952ba594447a796ad8146b9462 (patch) | |
tree | 33c199aeeae58b69ad8d6d2a33c2d96ba2b98ddf /drivers/gpu/drm/nouveau/nv50_graph.c | |
parent | efb3e34b6176d30c4fe8635fa8e1beb6280cc2cd (diff) | |
parent | 9bbe7b984096ac45586da2adf26c14069ecb79b2 (diff) |
Merge branch 'sh/sdio' into sh-latest
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv50_graph.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_graph.c | 677 |
1 files changed, 635 insertions, 42 deletions
diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index 8b669d0af610..2d7ea75a09d4 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c | |||
@@ -29,6 +29,12 @@ | |||
29 | #include "nouveau_drv.h" | 29 | #include "nouveau_drv.h" |
30 | #include "nouveau_ramht.h" | 30 | #include "nouveau_ramht.h" |
31 | #include "nouveau_grctx.h" | 31 | #include "nouveau_grctx.h" |
32 | #include "nouveau_dma.h" | ||
33 | #include "nouveau_vm.h" | ||
34 | #include "nv50_evo.h" | ||
35 | |||
36 | static int nv50_graph_register(struct drm_device *); | ||
37 | static void nv50_graph_isr(struct drm_device *); | ||
32 | 38 | ||
33 | static void | 39 | static void |
34 | nv50_graph_init_reset(struct drm_device *dev) | 40 | nv50_graph_init_reset(struct drm_device *dev) |
@@ -46,6 +52,7 @@ nv50_graph_init_intr(struct drm_device *dev) | |||
46 | { | 52 | { |
47 | NV_DEBUG(dev, "\n"); | 53 | NV_DEBUG(dev, "\n"); |
48 | 54 | ||
55 | nouveau_irq_register(dev, 12, nv50_graph_isr); | ||
49 | nv_wr32(dev, NV03_PGRAPH_INTR, 0xffffffff); | 56 | nv_wr32(dev, NV03_PGRAPH_INTR, 0xffffffff); |
50 | nv_wr32(dev, 0x400138, 0xffffffff); | 57 | nv_wr32(dev, 0x400138, 0xffffffff); |
51 | nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xffffffff); | 58 | nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xffffffff); |
@@ -145,12 +152,15 @@ nv50_graph_init(struct drm_device *dev) | |||
145 | nv50_graph_init_reset(dev); | 152 | nv50_graph_init_reset(dev); |
146 | nv50_graph_init_regs__nv(dev); | 153 | nv50_graph_init_regs__nv(dev); |
147 | nv50_graph_init_regs(dev); | 154 | nv50_graph_init_regs(dev); |
148 | nv50_graph_init_intr(dev); | ||
149 | 155 | ||
150 | ret = nv50_graph_init_ctxctl(dev); | 156 | ret = nv50_graph_init_ctxctl(dev); |
151 | if (ret) | 157 | if (ret) |
152 | return ret; | 158 | return ret; |
153 | 159 | ||
160 | ret = nv50_graph_register(dev); | ||
161 | if (ret) | ||
162 | return ret; | ||
163 | nv50_graph_init_intr(dev); | ||
154 | return 0; | 164 | return 0; |
155 | } | 165 | } |
156 | 166 | ||
@@ -158,6 +168,8 @@ void | |||
158 | nv50_graph_takedown(struct drm_device *dev) | 168 | nv50_graph_takedown(struct drm_device *dev) |
159 | { | 169 | { |
160 | NV_DEBUG(dev, "\n"); | 170 | NV_DEBUG(dev, "\n"); |
171 | nv_wr32(dev, 0x40013c, 0x00000000); | ||
172 | nouveau_irq_unregister(dev, 12); | ||
161 | } | 173 | } |
162 | 174 | ||
163 | void | 175 | void |
@@ -190,7 +202,7 @@ nv50_graph_channel(struct drm_device *dev) | |||
190 | inst = (inst & NV50_PGRAPH_CTXCTL_CUR_INSTANCE) << 12; | 202 | inst = (inst & NV50_PGRAPH_CTXCTL_CUR_INSTANCE) << 12; |
191 | 203 | ||
192 | for (i = 0; i < dev_priv->engine.fifo.channels; i++) { | 204 | for (i = 0; i < dev_priv->engine.fifo.channels; i++) { |
193 | struct nouveau_channel *chan = dev_priv->fifos[i]; | 205 | struct nouveau_channel *chan = dev_priv->channels.ptr[i]; |
194 | 206 | ||
195 | if (chan && chan->ramin && chan->ramin->vinst == inst) | 207 | if (chan && chan->ramin && chan->ramin->vinst == inst) |
196 | return chan; | 208 | return chan; |
@@ -211,7 +223,7 @@ nv50_graph_create_context(struct nouveau_channel *chan) | |||
211 | 223 | ||
212 | NV_DEBUG(dev, "ch%d\n", chan->id); | 224 | NV_DEBUG(dev, "ch%d\n", chan->id); |
213 | 225 | ||
214 | ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 0x1000, | 226 | ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 0, |
215 | NVOBJ_FLAG_ZERO_ALLOC | | 227 | NVOBJ_FLAG_ZERO_ALLOC | |
216 | NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx); | 228 | NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx); |
217 | if (ret) | 229 | if (ret) |
@@ -234,6 +246,7 @@ nv50_graph_create_context(struct nouveau_channel *chan) | |||
234 | nv_wo32(chan->ramin_grctx, 0x00000, chan->ramin->vinst >> 12); | 246 | nv_wo32(chan->ramin_grctx, 0x00000, chan->ramin->vinst >> 12); |
235 | 247 | ||
236 | dev_priv->engine.instmem.flush(dev); | 248 | dev_priv->engine.instmem.flush(dev); |
249 | atomic_inc(&chan->vm->pgraph_refs); | ||
237 | return 0; | 250 | return 0; |
238 | } | 251 | } |
239 | 252 | ||
@@ -242,18 +255,31 @@ nv50_graph_destroy_context(struct nouveau_channel *chan) | |||
242 | { | 255 | { |
243 | struct drm_device *dev = chan->dev; | 256 | struct drm_device *dev = chan->dev; |
244 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 257 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
258 | struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; | ||
245 | int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20; | 259 | int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20; |
260 | unsigned long flags; | ||
246 | 261 | ||
247 | NV_DEBUG(dev, "ch%d\n", chan->id); | 262 | NV_DEBUG(dev, "ch%d\n", chan->id); |
248 | 263 | ||
249 | if (!chan->ramin) | 264 | if (!chan->ramin) |
250 | return; | 265 | return; |
251 | 266 | ||
267 | spin_lock_irqsave(&dev_priv->context_switch_lock, flags); | ||
268 | pgraph->fifo_access(dev, false); | ||
269 | |||
270 | if (pgraph->channel(dev) == chan) | ||
271 | pgraph->unload_context(dev); | ||
272 | |||
252 | for (i = hdr; i < hdr + 24; i += 4) | 273 | for (i = hdr; i < hdr + 24; i += 4) |
253 | nv_wo32(chan->ramin, i, 0); | 274 | nv_wo32(chan->ramin, i, 0); |
254 | dev_priv->engine.instmem.flush(dev); | 275 | dev_priv->engine.instmem.flush(dev); |
255 | 276 | ||
277 | pgraph->fifo_access(dev, true); | ||
278 | spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); | ||
279 | |||
256 | nouveau_gpuobj_ref(NULL, &chan->ramin_grctx); | 280 | nouveau_gpuobj_ref(NULL, &chan->ramin_grctx); |
281 | |||
282 | atomic_dec(&chan->vm->pgraph_refs); | ||
257 | } | 283 | } |
258 | 284 | ||
259 | static int | 285 | static int |
@@ -306,7 +332,7 @@ nv50_graph_unload_context(struct drm_device *dev) | |||
306 | return 0; | 332 | return 0; |
307 | } | 333 | } |
308 | 334 | ||
309 | void | 335 | static void |
310 | nv50_graph_context_switch(struct drm_device *dev) | 336 | nv50_graph_context_switch(struct drm_device *dev) |
311 | { | 337 | { |
312 | uint32_t inst; | 338 | uint32_t inst; |
@@ -322,8 +348,8 @@ nv50_graph_context_switch(struct drm_device *dev) | |||
322 | } | 348 | } |
323 | 349 | ||
324 | static int | 350 | static int |
325 | nv50_graph_nvsw_dma_vblsem(struct nouveau_channel *chan, int grclass, | 351 | nv50_graph_nvsw_dma_vblsem(struct nouveau_channel *chan, |
326 | int mthd, uint32_t data) | 352 | u32 class, u32 mthd, u32 data) |
327 | { | 353 | { |
328 | struct nouveau_gpuobj *gpuobj; | 354 | struct nouveau_gpuobj *gpuobj; |
329 | 355 | ||
@@ -340,8 +366,8 @@ nv50_graph_nvsw_dma_vblsem(struct nouveau_channel *chan, int grclass, | |||
340 | } | 366 | } |
341 | 367 | ||
342 | static int | 368 | static int |
343 | nv50_graph_nvsw_vblsem_offset(struct nouveau_channel *chan, int grclass, | 369 | nv50_graph_nvsw_vblsem_offset(struct nouveau_channel *chan, |
344 | int mthd, uint32_t data) | 370 | u32 class, u32 mthd, u32 data) |
345 | { | 371 | { |
346 | if (nouveau_notifier_offset(chan->nvsw.vblsem, &data)) | 372 | if (nouveau_notifier_offset(chan->nvsw.vblsem, &data)) |
347 | return -ERANGE; | 373 | return -ERANGE; |
@@ -351,16 +377,16 @@ nv50_graph_nvsw_vblsem_offset(struct nouveau_channel *chan, int grclass, | |||
351 | } | 377 | } |
352 | 378 | ||
353 | static int | 379 | static int |
354 | nv50_graph_nvsw_vblsem_release_val(struct nouveau_channel *chan, int grclass, | 380 | nv50_graph_nvsw_vblsem_release_val(struct nouveau_channel *chan, |
355 | int mthd, uint32_t data) | 381 | u32 class, u32 mthd, u32 data) |
356 | { | 382 | { |
357 | chan->nvsw.vblsem_rval = data; | 383 | chan->nvsw.vblsem_rval = data; |
358 | return 0; | 384 | return 0; |
359 | } | 385 | } |
360 | 386 | ||
361 | static int | 387 | static int |
362 | nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan, int grclass, | 388 | nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan, |
363 | int mthd, uint32_t data) | 389 | u32 class, u32 mthd, u32 data) |
364 | { | 390 | { |
365 | struct drm_device *dev = chan->dev; | 391 | struct drm_device *dev = chan->dev; |
366 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 392 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
@@ -368,45 +394,85 @@ nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan, int grclass, | |||
368 | if (!chan->nvsw.vblsem || chan->nvsw.vblsem_offset == ~0 || data > 1) | 394 | if (!chan->nvsw.vblsem || chan->nvsw.vblsem_offset == ~0 || data > 1) |
369 | return -EINVAL; | 395 | return -EINVAL; |
370 | 396 | ||
371 | if (!(nv_rd32(dev, NV50_PDISPLAY_INTR_EN) & | 397 | drm_vblank_get(dev, data); |
372 | NV50_PDISPLAY_INTR_EN_VBLANK_CRTC_(data))) { | ||
373 | nv_wr32(dev, NV50_PDISPLAY_INTR_1, | ||
374 | NV50_PDISPLAY_INTR_1_VBLANK_CRTC_(data)); | ||
375 | nv_wr32(dev, NV50_PDISPLAY_INTR_EN, nv_rd32(dev, | ||
376 | NV50_PDISPLAY_INTR_EN) | | ||
377 | NV50_PDISPLAY_INTR_EN_VBLANK_CRTC_(data)); | ||
378 | } | ||
379 | 398 | ||
399 | chan->nvsw.vblsem_head = data; | ||
380 | list_add(&chan->nvsw.vbl_wait, &dev_priv->vbl_waiting); | 400 | list_add(&chan->nvsw.vbl_wait, &dev_priv->vbl_waiting); |
401 | |||
381 | return 0; | 402 | return 0; |
382 | } | 403 | } |
383 | 404 | ||
384 | static struct nouveau_pgraph_object_method nv50_graph_nvsw_methods[] = { | 405 | static int |
385 | { 0x018c, nv50_graph_nvsw_dma_vblsem }, | 406 | nv50_graph_nvsw_mthd_page_flip(struct nouveau_channel *chan, |
386 | { 0x0400, nv50_graph_nvsw_vblsem_offset }, | 407 | u32 class, u32 mthd, u32 data) |
387 | { 0x0404, nv50_graph_nvsw_vblsem_release_val }, | 408 | { |
388 | { 0x0408, nv50_graph_nvsw_vblsem_release }, | 409 | struct nouveau_page_flip_state s; |
389 | {} | ||
390 | }; | ||
391 | 410 | ||
392 | struct nouveau_pgraph_object_class nv50_graph_grclass[] = { | 411 | if (!nouveau_finish_page_flip(chan, &s)) { |
393 | { 0x506e, true, nv50_graph_nvsw_methods }, /* nvsw */ | 412 | /* XXX - Do something here */ |
394 | { 0x0030, false, NULL }, /* null */ | 413 | } |
395 | { 0x5039, false, NULL }, /* m2mf */ | 414 | |
396 | { 0x502d, false, NULL }, /* 2d */ | 415 | return 0; |
397 | { 0x50c0, false, NULL }, /* compute */ | 416 | } |
398 | { 0x85c0, false, NULL }, /* compute (nva3, nva5, nva8) */ | 417 | |
399 | { 0x5097, false, NULL }, /* tesla (nv50) */ | 418 | static int |
400 | { 0x8297, false, NULL }, /* tesla (nv8x/nv9x) */ | 419 | nv50_graph_register(struct drm_device *dev) |
401 | { 0x8397, false, NULL }, /* tesla (nva0, nvaa, nvac) */ | 420 | { |
402 | { 0x8597, false, NULL }, /* tesla (nva3, nva5, nva8) */ | 421 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
403 | {} | 422 | |
404 | }; | 423 | if (dev_priv->engine.graph.registered) |
424 | return 0; | ||
425 | |||
426 | NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */ | ||
427 | NVOBJ_MTHD (dev, 0x506e, 0x018c, nv50_graph_nvsw_dma_vblsem); | ||
428 | NVOBJ_MTHD (dev, 0x506e, 0x0400, nv50_graph_nvsw_vblsem_offset); | ||
429 | NVOBJ_MTHD (dev, 0x506e, 0x0404, nv50_graph_nvsw_vblsem_release_val); | ||
430 | NVOBJ_MTHD (dev, 0x506e, 0x0408, nv50_graph_nvsw_vblsem_release); | ||
431 | NVOBJ_MTHD (dev, 0x506e, 0x0500, nv50_graph_nvsw_mthd_page_flip); | ||
432 | |||
433 | NVOBJ_CLASS(dev, 0x0030, GR); /* null */ | ||
434 | NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */ | ||
435 | NVOBJ_CLASS(dev, 0x502d, GR); /* 2d */ | ||
436 | |||
437 | /* tesla */ | ||
438 | if (dev_priv->chipset == 0x50) | ||
439 | NVOBJ_CLASS(dev, 0x5097, GR); /* tesla (nv50) */ | ||
440 | else | ||
441 | if (dev_priv->chipset < 0xa0) | ||
442 | NVOBJ_CLASS(dev, 0x8297, GR); /* tesla (nv8x/nv9x) */ | ||
443 | else { | ||
444 | switch (dev_priv->chipset) { | ||
445 | case 0xa0: | ||
446 | case 0xaa: | ||
447 | case 0xac: | ||
448 | NVOBJ_CLASS(dev, 0x8397, GR); | ||
449 | break; | ||
450 | case 0xa3: | ||
451 | case 0xa5: | ||
452 | case 0xa8: | ||
453 | NVOBJ_CLASS(dev, 0x8597, GR); | ||
454 | break; | ||
455 | case 0xaf: | ||
456 | NVOBJ_CLASS(dev, 0x8697, GR); | ||
457 | break; | ||
458 | } | ||
459 | } | ||
460 | |||
461 | /* compute */ | ||
462 | NVOBJ_CLASS(dev, 0x50c0, GR); | ||
463 | if (dev_priv->chipset > 0xa0 && | ||
464 | dev_priv->chipset != 0xaa && | ||
465 | dev_priv->chipset != 0xac) | ||
466 | NVOBJ_CLASS(dev, 0x85c0, GR); | ||
467 | |||
468 | dev_priv->engine.graph.registered = true; | ||
469 | return 0; | ||
470 | } | ||
405 | 471 | ||
406 | void | 472 | void |
407 | nv50_graph_tlb_flush(struct drm_device *dev) | 473 | nv50_graph_tlb_flush(struct drm_device *dev) |
408 | { | 474 | { |
409 | nv50_vm_flush(dev, 0); | 475 | nv50_vm_flush_engine(dev, 0); |
410 | } | 476 | } |
411 | 477 | ||
412 | void | 478 | void |
@@ -449,8 +515,535 @@ nv86_graph_tlb_flush(struct drm_device *dev) | |||
449 | nv_rd32(dev, 0x400384), nv_rd32(dev, 0x400388)); | 515 | nv_rd32(dev, 0x400384), nv_rd32(dev, 0x400388)); |
450 | } | 516 | } |
451 | 517 | ||
452 | nv50_vm_flush(dev, 0); | 518 | nv50_vm_flush_engine(dev, 0); |
453 | 519 | ||
454 | nv_mask(dev, 0x400500, 0x00000001, 0x00000001); | 520 | nv_mask(dev, 0x400500, 0x00000001, 0x00000001); |
455 | spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); | 521 | spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); |
456 | } | 522 | } |
523 | |||
524 | static struct nouveau_enum nv50_mp_exec_error_names[] = | ||
525 | { | ||
526 | { 3, "STACK_UNDERFLOW" }, | ||
527 | { 4, "QUADON_ACTIVE" }, | ||
528 | { 8, "TIMEOUT" }, | ||
529 | { 0x10, "INVALID_OPCODE" }, | ||
530 | { 0x40, "BREAKPOINT" }, | ||
531 | {} | ||
532 | }; | ||
533 | |||
534 | static struct nouveau_bitfield nv50_graph_trap_m2mf[] = { | ||
535 | { 0x00000001, "NOTIFY" }, | ||
536 | { 0x00000002, "IN" }, | ||
537 | { 0x00000004, "OUT" }, | ||
538 | {} | ||
539 | }; | ||
540 | |||
541 | static struct nouveau_bitfield nv50_graph_trap_vfetch[] = { | ||
542 | { 0x00000001, "FAULT" }, | ||
543 | {} | ||
544 | }; | ||
545 | |||
546 | static struct nouveau_bitfield nv50_graph_trap_strmout[] = { | ||
547 | { 0x00000001, "FAULT" }, | ||
548 | {} | ||
549 | }; | ||
550 | |||
551 | static struct nouveau_bitfield nv50_graph_trap_ccache[] = { | ||
552 | { 0x00000001, "FAULT" }, | ||
553 | {} | ||
554 | }; | ||
555 | |||
556 | /* There must be a *lot* of these. Will take some time to gather them up. */ | ||
557 | struct nouveau_enum nv50_data_error_names[] = { | ||
558 | { 0x00000003, "INVALID_QUERY_OR_TEXTURE" }, | ||
559 | { 0x00000004, "INVALID_VALUE" }, | ||
560 | { 0x00000005, "INVALID_ENUM" }, | ||
561 | { 0x00000008, "INVALID_OBJECT" }, | ||
562 | { 0x00000009, "READ_ONLY_OBJECT" }, | ||
563 | { 0x0000000a, "SUPERVISOR_OBJECT" }, | ||
564 | { 0x0000000b, "INVALID_ADDRESS_ALIGNMENT" }, | ||
565 | { 0x0000000c, "INVALID_BITFIELD" }, | ||
566 | { 0x0000000d, "BEGIN_END_ACTIVE" }, | ||
567 | { 0x0000000e, "SEMANTIC_COLOR_BACK_OVER_LIMIT" }, | ||
568 | { 0x0000000f, "VIEWPORT_ID_NEEDS_GP" }, | ||
569 | { 0x00000010, "RT_DOUBLE_BIND" }, | ||
570 | { 0x00000011, "RT_TYPES_MISMATCH" }, | ||
571 | { 0x00000012, "RT_LINEAR_WITH_ZETA" }, | ||
572 | { 0x00000015, "FP_TOO_FEW_REGS" }, | ||
573 | { 0x00000016, "ZETA_FORMAT_CSAA_MISMATCH" }, | ||
574 | { 0x00000017, "RT_LINEAR_WITH_MSAA" }, | ||
575 | { 0x00000018, "FP_INTERPOLANT_START_OVER_LIMIT" }, | ||
576 | { 0x00000019, "SEMANTIC_LAYER_OVER_LIMIT" }, | ||
577 | { 0x0000001a, "RT_INVALID_ALIGNMENT" }, | ||
578 | { 0x0000001b, "SAMPLER_OVER_LIMIT" }, | ||
579 | { 0x0000001c, "TEXTURE_OVER_LIMIT" }, | ||
580 | { 0x0000001e, "GP_TOO_MANY_OUTPUTS" }, | ||
581 | { 0x0000001f, "RT_BPP128_WITH_MS8" }, | ||
582 | { 0x00000021, "Z_OUT_OF_BOUNDS" }, | ||
583 | { 0x00000023, "XY_OUT_OF_BOUNDS" }, | ||
584 | { 0x00000027, "CP_MORE_PARAMS_THAN_SHARED" }, | ||
585 | { 0x00000028, "CP_NO_REG_SPACE_STRIPED" }, | ||
586 | { 0x00000029, "CP_NO_REG_SPACE_PACKED" }, | ||
587 | { 0x0000002a, "CP_NOT_ENOUGH_WARPS" }, | ||
588 | { 0x0000002b, "CP_BLOCK_SIZE_MISMATCH" }, | ||
589 | { 0x0000002c, "CP_NOT_ENOUGH_LOCAL_WARPS" }, | ||
590 | { 0x0000002d, "CP_NOT_ENOUGH_STACK_WARPS" }, | ||
591 | { 0x0000002e, "CP_NO_BLOCKDIM_LATCH" }, | ||
592 | { 0x00000031, "ENG2D_FORMAT_MISMATCH" }, | ||
593 | { 0x0000003f, "PRIMITIVE_ID_NEEDS_GP" }, | ||
594 | { 0x00000044, "SEMANTIC_VIEWPORT_OVER_LIMIT" }, | ||
595 | { 0x00000045, "SEMANTIC_COLOR_FRONT_OVER_LIMIT" }, | ||
596 | { 0x00000046, "LAYER_ID_NEEDS_GP" }, | ||
597 | { 0x00000047, "SEMANTIC_CLIP_OVER_LIMIT" }, | ||
598 | { 0x00000048, "SEMANTIC_PTSZ_OVER_LIMIT" }, | ||
599 | {} | ||
600 | }; | ||
601 | |||
602 | static struct nouveau_bitfield nv50_graph_intr[] = { | ||
603 | { 0x00000001, "NOTIFY" }, | ||
604 | { 0x00000002, "COMPUTE_QUERY" }, | ||
605 | { 0x00000010, "ILLEGAL_MTHD" }, | ||
606 | { 0x00000020, "ILLEGAL_CLASS" }, | ||
607 | { 0x00000040, "DOUBLE_NOTIFY" }, | ||
608 | { 0x00001000, "CONTEXT_SWITCH" }, | ||
609 | { 0x00010000, "BUFFER_NOTIFY" }, | ||
610 | { 0x00100000, "DATA_ERROR" }, | ||
611 | { 0x00200000, "TRAP" }, | ||
612 | { 0x01000000, "SINGLE_STEP" }, | ||
613 | {} | ||
614 | }; | ||
615 | |||
616 | static void | ||
617 | nv50_pgraph_mp_trap(struct drm_device *dev, int tpid, int display) | ||
618 | { | ||
619 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
620 | uint32_t units = nv_rd32(dev, 0x1540); | ||
621 | uint32_t addr, mp10, status, pc, oplow, ophigh; | ||
622 | int i; | ||
623 | int mps = 0; | ||
624 | for (i = 0; i < 4; i++) { | ||
625 | if (!(units & 1 << (i+24))) | ||
626 | continue; | ||
627 | if (dev_priv->chipset < 0xa0) | ||
628 | addr = 0x408200 + (tpid << 12) + (i << 7); | ||
629 | else | ||
630 | addr = 0x408100 + (tpid << 11) + (i << 7); | ||
631 | mp10 = nv_rd32(dev, addr + 0x10); | ||
632 | status = nv_rd32(dev, addr + 0x14); | ||
633 | if (!status) | ||
634 | continue; | ||
635 | if (display) { | ||
636 | nv_rd32(dev, addr + 0x20); | ||
637 | pc = nv_rd32(dev, addr + 0x24); | ||
638 | oplow = nv_rd32(dev, addr + 0x70); | ||
639 | ophigh= nv_rd32(dev, addr + 0x74); | ||
640 | NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - " | ||
641 | "TP %d MP %d: ", tpid, i); | ||
642 | nouveau_enum_print(nv50_mp_exec_error_names, status); | ||
643 | printk(" at %06x warp %d, opcode %08x %08x\n", | ||
644 | pc&0xffffff, pc >> 24, | ||
645 | oplow, ophigh); | ||
646 | } | ||
647 | nv_wr32(dev, addr + 0x10, mp10); | ||
648 | nv_wr32(dev, addr + 0x14, 0); | ||
649 | mps++; | ||
650 | } | ||
651 | if (!mps && display) | ||
652 | NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - TP %d: " | ||
653 | "No MPs claiming errors?\n", tpid); | ||
654 | } | ||
655 | |||
656 | static void | ||
657 | nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old, | ||
658 | uint32_t ustatus_new, int display, const char *name) | ||
659 | { | ||
660 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
661 | int tps = 0; | ||
662 | uint32_t units = nv_rd32(dev, 0x1540); | ||
663 | int i, r; | ||
664 | uint32_t ustatus_addr, ustatus; | ||
665 | for (i = 0; i < 16; i++) { | ||
666 | if (!(units & (1 << i))) | ||
667 | continue; | ||
668 | if (dev_priv->chipset < 0xa0) | ||
669 | ustatus_addr = ustatus_old + (i << 12); | ||
670 | else | ||
671 | ustatus_addr = ustatus_new + (i << 11); | ||
672 | ustatus = nv_rd32(dev, ustatus_addr) & 0x7fffffff; | ||
673 | if (!ustatus) | ||
674 | continue; | ||
675 | tps++; | ||
676 | switch (type) { | ||
677 | case 6: /* texture error... unknown for now */ | ||
678 | nv50_fb_vm_trap(dev, display, name); | ||
679 | if (display) { | ||
680 | NV_ERROR(dev, "magic set %d:\n", i); | ||
681 | for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4) | ||
682 | NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, | ||
683 | nv_rd32(dev, r)); | ||
684 | } | ||
685 | break; | ||
686 | case 7: /* MP error */ | ||
687 | if (ustatus & 0x00010000) { | ||
688 | nv50_pgraph_mp_trap(dev, i, display); | ||
689 | ustatus &= ~0x00010000; | ||
690 | } | ||
691 | break; | ||
692 | case 8: /* TPDMA error */ | ||
693 | { | ||
694 | uint32_t e0c = nv_rd32(dev, ustatus_addr + 4); | ||
695 | uint32_t e10 = nv_rd32(dev, ustatus_addr + 8); | ||
696 | uint32_t e14 = nv_rd32(dev, ustatus_addr + 0xc); | ||
697 | uint32_t e18 = nv_rd32(dev, ustatus_addr + 0x10); | ||
698 | uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14); | ||
699 | uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18); | ||
700 | uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c); | ||
701 | nv50_fb_vm_trap(dev, display, name); | ||
702 | /* 2d engine destination */ | ||
703 | if (ustatus & 0x00000010) { | ||
704 | if (display) { | ||
705 | NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - Unknown fault at address %02x%08x\n", | ||
706 | i, e14, e10); | ||
707 | NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", | ||
708 | i, e0c, e18, e1c, e20, e24); | ||
709 | } | ||
710 | ustatus &= ~0x00000010; | ||
711 | } | ||
712 | /* Render target */ | ||
713 | if (ustatus & 0x00000040) { | ||
714 | if (display) { | ||
715 | NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - Unknown fault at address %02x%08x\n", | ||
716 | i, e14, e10); | ||
717 | NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", | ||
718 | i, e0c, e18, e1c, e20, e24); | ||
719 | } | ||
720 | ustatus &= ~0x00000040; | ||
721 | } | ||
722 | /* CUDA memory: l[], g[] or stack. */ | ||
723 | if (ustatus & 0x00000080) { | ||
724 | if (display) { | ||
725 | if (e18 & 0x80000000) { | ||
726 | /* g[] read fault? */ | ||
727 | NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global read fault at address %02x%08x\n", | ||
728 | i, e14, e10 | ((e18 >> 24) & 0x1f)); | ||
729 | e18 &= ~0x1f000000; | ||
730 | } else if (e18 & 0xc) { | ||
731 | /* g[] write fault? */ | ||
732 | NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global write fault at address %02x%08x\n", | ||
733 | i, e14, e10 | ((e18 >> 7) & 0x1f)); | ||
734 | e18 &= ~0x00000f80; | ||
735 | } else { | ||
736 | NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Unknown CUDA fault at address %02x%08x\n", | ||
737 | i, e14, e10); | ||
738 | } | ||
739 | NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", | ||
740 | i, e0c, e18, e1c, e20, e24); | ||
741 | } | ||
742 | ustatus &= ~0x00000080; | ||
743 | } | ||
744 | } | ||
745 | break; | ||
746 | } | ||
747 | if (ustatus) { | ||
748 | if (display) | ||
749 | NV_INFO(dev, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus); | ||
750 | } | ||
751 | nv_wr32(dev, ustatus_addr, 0xc0000000); | ||
752 | } | ||
753 | |||
754 | if (!tps && display) | ||
755 | NV_INFO(dev, "%s - No TPs claiming errors?\n", name); | ||
756 | } | ||
757 | |||
758 | static int | ||
759 | nv50_pgraph_trap_handler(struct drm_device *dev, u32 display, u64 inst, u32 chid) | ||
760 | { | ||
761 | u32 status = nv_rd32(dev, 0x400108); | ||
762 | u32 ustatus; | ||
763 | |||
764 | if (!status && display) { | ||
765 | NV_INFO(dev, "PGRAPH - TRAP: no units reporting traps?\n"); | ||
766 | return 1; | ||
767 | } | ||
768 | |||
769 | /* DISPATCH: Relays commands to other units and handles NOTIFY, | ||
770 | * COND, QUERY. If you get a trap from it, the command is still stuck | ||
771 | * in DISPATCH and you need to do something about it. */ | ||
772 | if (status & 0x001) { | ||
773 | ustatus = nv_rd32(dev, 0x400804) & 0x7fffffff; | ||
774 | if (!ustatus && display) { | ||
775 | NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - no ustatus?\n"); | ||
776 | } | ||
777 | |||
778 | nv_wr32(dev, 0x400500, 0x00000000); | ||
779 | |||
780 | /* Known to be triggered by screwed up NOTIFY and COND... */ | ||
781 | if (ustatus & 0x00000001) { | ||
782 | u32 addr = nv_rd32(dev, 0x400808); | ||
783 | u32 subc = (addr & 0x00070000) >> 16; | ||
784 | u32 mthd = (addr & 0x00001ffc); | ||
785 | u32 datal = nv_rd32(dev, 0x40080c); | ||
786 | u32 datah = nv_rd32(dev, 0x400810); | ||
787 | u32 class = nv_rd32(dev, 0x400814); | ||
788 | u32 r848 = nv_rd32(dev, 0x400848); | ||
789 | |||
790 | NV_INFO(dev, "PGRAPH - TRAP DISPATCH_FAULT\n"); | ||
791 | if (display && (addr & 0x80000000)) { | ||
792 | NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) " | ||
793 | "subc %d class 0x%04x mthd 0x%04x " | ||
794 | "data 0x%08x%08x " | ||
795 | "400808 0x%08x 400848 0x%08x\n", | ||
796 | chid, inst, subc, class, mthd, datah, | ||
797 | datal, addr, r848); | ||
798 | } else | ||
799 | if (display) { | ||
800 | NV_INFO(dev, "PGRAPH - no stuck command?\n"); | ||
801 | } | ||
802 | |||
803 | nv_wr32(dev, 0x400808, 0); | ||
804 | nv_wr32(dev, 0x4008e8, nv_rd32(dev, 0x4008e8) & 3); | ||
805 | nv_wr32(dev, 0x400848, 0); | ||
806 | ustatus &= ~0x00000001; | ||
807 | } | ||
808 | |||
809 | if (ustatus & 0x00000002) { | ||
810 | u32 addr = nv_rd32(dev, 0x40084c); | ||
811 | u32 subc = (addr & 0x00070000) >> 16; | ||
812 | u32 mthd = (addr & 0x00001ffc); | ||
813 | u32 data = nv_rd32(dev, 0x40085c); | ||
814 | u32 class = nv_rd32(dev, 0x400814); | ||
815 | |||
816 | NV_INFO(dev, "PGRAPH - TRAP DISPATCH_QUERY\n"); | ||
817 | if (display && (addr & 0x80000000)) { | ||
818 | NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) " | ||
819 | "subc %d class 0x%04x mthd 0x%04x " | ||
820 | "data 0x%08x 40084c 0x%08x\n", | ||
821 | chid, inst, subc, class, mthd, | ||
822 | data, addr); | ||
823 | } else | ||
824 | if (display) { | ||
825 | NV_INFO(dev, "PGRAPH - no stuck command?\n"); | ||
826 | } | ||
827 | |||
828 | nv_wr32(dev, 0x40084c, 0); | ||
829 | ustatus &= ~0x00000002; | ||
830 | } | ||
831 | |||
832 | if (ustatus && display) { | ||
833 | NV_INFO(dev, "PGRAPH - TRAP_DISPATCH (unknown " | ||
834 | "0x%08x)\n", ustatus); | ||
835 | } | ||
836 | |||
837 | nv_wr32(dev, 0x400804, 0xc0000000); | ||
838 | nv_wr32(dev, 0x400108, 0x001); | ||
839 | status &= ~0x001; | ||
840 | if (!status) | ||
841 | return 0; | ||
842 | } | ||
843 | |||
844 | /* M2MF: Memory to memory copy engine. */ | ||
845 | if (status & 0x002) { | ||
846 | u32 ustatus = nv_rd32(dev, 0x406800) & 0x7fffffff; | ||
847 | if (display) { | ||
848 | NV_INFO(dev, "PGRAPH - TRAP_M2MF"); | ||
849 | nouveau_bitfield_print(nv50_graph_trap_m2mf, ustatus); | ||
850 | printk("\n"); | ||
851 | NV_INFO(dev, "PGRAPH - TRAP_M2MF %08x %08x %08x %08x\n", | ||
852 | nv_rd32(dev, 0x406804), nv_rd32(dev, 0x406808), | ||
853 | nv_rd32(dev, 0x40680c), nv_rd32(dev, 0x406810)); | ||
854 | |||
855 | } | ||
856 | |||
857 | /* No sane way found yet -- just reset the bugger. */ | ||
858 | nv_wr32(dev, 0x400040, 2); | ||
859 | nv_wr32(dev, 0x400040, 0); | ||
860 | nv_wr32(dev, 0x406800, 0xc0000000); | ||
861 | nv_wr32(dev, 0x400108, 0x002); | ||
862 | status &= ~0x002; | ||
863 | } | ||
864 | |||
865 | /* VFETCH: Fetches data from vertex buffers. */ | ||
866 | if (status & 0x004) { | ||
867 | u32 ustatus = nv_rd32(dev, 0x400c04) & 0x7fffffff; | ||
868 | if (display) { | ||
869 | NV_INFO(dev, "PGRAPH - TRAP_VFETCH"); | ||
870 | nouveau_bitfield_print(nv50_graph_trap_vfetch, ustatus); | ||
871 | printk("\n"); | ||
872 | NV_INFO(dev, "PGRAPH - TRAP_VFETCH %08x %08x %08x %08x\n", | ||
873 | nv_rd32(dev, 0x400c00), nv_rd32(dev, 0x400c08), | ||
874 | nv_rd32(dev, 0x400c0c), nv_rd32(dev, 0x400c10)); | ||
875 | } | ||
876 | |||
877 | nv_wr32(dev, 0x400c04, 0xc0000000); | ||
878 | nv_wr32(dev, 0x400108, 0x004); | ||
879 | status &= ~0x004; | ||
880 | } | ||
881 | |||
882 | /* STRMOUT: DirectX streamout / OpenGL transform feedback. */ | ||
883 | if (status & 0x008) { | ||
884 | ustatus = nv_rd32(dev, 0x401800) & 0x7fffffff; | ||
885 | if (display) { | ||
886 | NV_INFO(dev, "PGRAPH - TRAP_STRMOUT"); | ||
887 | nouveau_bitfield_print(nv50_graph_trap_strmout, ustatus); | ||
888 | printk("\n"); | ||
889 | NV_INFO(dev, "PGRAPH - TRAP_STRMOUT %08x %08x %08x %08x\n", | ||
890 | nv_rd32(dev, 0x401804), nv_rd32(dev, 0x401808), | ||
891 | nv_rd32(dev, 0x40180c), nv_rd32(dev, 0x401810)); | ||
892 | |||
893 | } | ||
894 | |||
895 | /* No sane way found yet -- just reset the bugger. */ | ||
896 | nv_wr32(dev, 0x400040, 0x80); | ||
897 | nv_wr32(dev, 0x400040, 0); | ||
898 | nv_wr32(dev, 0x401800, 0xc0000000); | ||
899 | nv_wr32(dev, 0x400108, 0x008); | ||
900 | status &= ~0x008; | ||
901 | } | ||
902 | |||
903 | /* CCACHE: Handles code and c[] caches and fills them. */ | ||
904 | if (status & 0x010) { | ||
905 | ustatus = nv_rd32(dev, 0x405018) & 0x7fffffff; | ||
906 | if (display) { | ||
907 | NV_INFO(dev, "PGRAPH - TRAP_CCACHE"); | ||
908 | nouveau_bitfield_print(nv50_graph_trap_ccache, ustatus); | ||
909 | printk("\n"); | ||
910 | NV_INFO(dev, "PGRAPH - TRAP_CCACHE %08x %08x %08x %08x" | ||
911 | " %08x %08x %08x\n", | ||
912 | nv_rd32(dev, 0x405800), nv_rd32(dev, 0x405804), | ||
913 | nv_rd32(dev, 0x405808), nv_rd32(dev, 0x40580c), | ||
914 | nv_rd32(dev, 0x405810), nv_rd32(dev, 0x405814), | ||
915 | nv_rd32(dev, 0x40581c)); | ||
916 | |||
917 | } | ||
918 | |||
919 | nv_wr32(dev, 0x405018, 0xc0000000); | ||
920 | nv_wr32(dev, 0x400108, 0x010); | ||
921 | status &= ~0x010; | ||
922 | } | ||
923 | |||
924 | /* Unknown, not seen yet... 0x402000 is the only trap status reg | ||
925 | * remaining, so try to handle it anyway. Perhaps related to that | ||
926 | * unknown DMA slot on tesla? */ | ||
927 | if (status & 0x20) { | ||
928 | ustatus = nv_rd32(dev, 0x402000) & 0x7fffffff; | ||
929 | if (display) | ||
930 | NV_INFO(dev, "PGRAPH - TRAP_UNKC04 0x%08x\n", ustatus); | ||
931 | nv_wr32(dev, 0x402000, 0xc0000000); | ||
932 | /* no status modifiction on purpose */ | ||
933 | } | ||
934 | |||
935 | /* TEXTURE: CUDA texturing units */ | ||
936 | if (status & 0x040) { | ||
937 | nv50_pgraph_tp_trap(dev, 6, 0x408900, 0x408600, display, | ||
938 | "PGRAPH - TRAP_TEXTURE"); | ||
939 | nv_wr32(dev, 0x400108, 0x040); | ||
940 | status &= ~0x040; | ||
941 | } | ||
942 | |||
943 | /* MP: CUDA execution engines. */ | ||
944 | if (status & 0x080) { | ||
945 | nv50_pgraph_tp_trap(dev, 7, 0x408314, 0x40831c, display, | ||
946 | "PGRAPH - TRAP_MP"); | ||
947 | nv_wr32(dev, 0x400108, 0x080); | ||
948 | status &= ~0x080; | ||
949 | } | ||
950 | |||
951 | /* TPDMA: Handles TP-initiated uncached memory accesses: | ||
952 | * l[], g[], stack, 2d surfaces, render targets. */ | ||
953 | if (status & 0x100) { | ||
954 | nv50_pgraph_tp_trap(dev, 8, 0x408e08, 0x408708, display, | ||
955 | "PGRAPH - TRAP_TPDMA"); | ||
956 | nv_wr32(dev, 0x400108, 0x100); | ||
957 | status &= ~0x100; | ||
958 | } | ||
959 | |||
960 | if (status) { | ||
961 | if (display) | ||
962 | NV_INFO(dev, "PGRAPH - TRAP: unknown 0x%08x\n", status); | ||
963 | nv_wr32(dev, 0x400108, status); | ||
964 | } | ||
965 | |||
966 | return 1; | ||
967 | } | ||
968 | |||
969 | static int | ||
970 | nv50_graph_isr_chid(struct drm_device *dev, u64 inst) | ||
971 | { | ||
972 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
973 | struct nouveau_channel *chan; | ||
974 | unsigned long flags; | ||
975 | int i; | ||
976 | |||
977 | spin_lock_irqsave(&dev_priv->channels.lock, flags); | ||
978 | for (i = 0; i < dev_priv->engine.fifo.channels; i++) { | ||
979 | chan = dev_priv->channels.ptr[i]; | ||
980 | if (!chan || !chan->ramin) | ||
981 | continue; | ||
982 | |||
983 | if (inst == chan->ramin->vinst) | ||
984 | break; | ||
985 | } | ||
986 | spin_unlock_irqrestore(&dev_priv->channels.lock, flags); | ||
987 | return i; | ||
988 | } | ||
989 | |||
990 | static void | ||
991 | nv50_graph_isr(struct drm_device *dev) | ||
992 | { | ||
993 | u32 stat; | ||
994 | |||
995 | while ((stat = nv_rd32(dev, 0x400100))) { | ||
996 | u64 inst = (u64)(nv_rd32(dev, 0x40032c) & 0x0fffffff) << 12; | ||
997 | u32 chid = nv50_graph_isr_chid(dev, inst); | ||
998 | u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR); | ||
999 | u32 subc = (addr & 0x00070000) >> 16; | ||
1000 | u32 mthd = (addr & 0x00001ffc); | ||
1001 | u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA); | ||
1002 | u32 class = nv_rd32(dev, 0x400814); | ||
1003 | u32 show = stat; | ||
1004 | |||
1005 | if (stat & 0x00000010) { | ||
1006 | if (!nouveau_gpuobj_mthd_call2(dev, chid, class, | ||
1007 | mthd, data)) | ||
1008 | show &= ~0x00000010; | ||
1009 | } | ||
1010 | |||
1011 | if (stat & 0x00001000) { | ||
1012 | nv_wr32(dev, 0x400500, 0x00000000); | ||
1013 | nv_wr32(dev, 0x400100, 0x00001000); | ||
1014 | nv_mask(dev, 0x40013c, 0x00001000, 0x00000000); | ||
1015 | nv50_graph_context_switch(dev); | ||
1016 | stat &= ~0x00001000; | ||
1017 | show &= ~0x00001000; | ||
1018 | } | ||
1019 | |||
1020 | show = (show && nouveau_ratelimit()) ? show : 0; | ||
1021 | |||
1022 | if (show & 0x00100000) { | ||
1023 | u32 ecode = nv_rd32(dev, 0x400110); | ||
1024 | NV_INFO(dev, "PGRAPH - DATA_ERROR "); | ||
1025 | nouveau_enum_print(nv50_data_error_names, ecode); | ||
1026 | printk("\n"); | ||
1027 | } | ||
1028 | |||
1029 | if (stat & 0x00200000) { | ||
1030 | if (!nv50_pgraph_trap_handler(dev, show, inst, chid)) | ||
1031 | show &= ~0x00200000; | ||
1032 | } | ||
1033 | |||
1034 | nv_wr32(dev, 0x400100, stat); | ||
1035 | nv_wr32(dev, 0x400500, 0x00010001); | ||
1036 | |||
1037 | if (show) { | ||
1038 | NV_INFO(dev, "PGRAPH -"); | ||
1039 | nouveau_bitfield_print(nv50_graph_intr, show); | ||
1040 | printk("\n"); | ||
1041 | NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) subc %d " | ||
1042 | "class 0x%04x mthd 0x%04x data 0x%08x\n", | ||
1043 | chid, inst, subc, class, mthd, data); | ||
1044 | } | ||
1045 | } | ||
1046 | |||
1047 | if (nv_rd32(dev, 0x400824) & (1 << 31)) | ||
1048 | nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31)); | ||
1049 | } | ||