diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2010-11-02 23:16:18 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2010-12-03 00:11:41 -0500 |
commit | 274fec93cdd627408a799519fa602f2eecb14d2f (patch) | |
tree | 1ffc788a096237583608dfa3f09caccfc500ec82 /drivers/gpu/drm/nouveau/nv50_graph.c | |
parent | 5178d40dff23b5eef7f0a3be2411fa6a347e750d (diff) |
drm/nouveau: tidy+move PGRAPH ISRs to their respective *_graph.c files
Reviewed-by: Francisco Jerez <currojerez@riseup.net>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv50_graph.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_graph.c | 500 |
1 files changed, 498 insertions, 2 deletions
diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index 6785269f778a..b3900788c66d 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c | |||
@@ -32,7 +32,8 @@ | |||
32 | #include "nouveau_dma.h" | 32 | #include "nouveau_dma.h" |
33 | #include "nv50_evo.h" | 33 | #include "nv50_evo.h" |
34 | 34 | ||
35 | static int nv50_graph_register(struct drm_device *); | 35 | static int nv50_graph_register(struct drm_device *); |
36 | static void nv50_graph_isr(struct drm_device *); | ||
36 | 37 | ||
37 | static void | 38 | static void |
38 | nv50_graph_init_reset(struct drm_device *dev) | 39 | nv50_graph_init_reset(struct drm_device *dev) |
@@ -50,6 +51,7 @@ nv50_graph_init_intr(struct drm_device *dev) | |||
50 | { | 51 | { |
51 | NV_DEBUG(dev, "\n"); | 52 | NV_DEBUG(dev, "\n"); |
52 | 53 | ||
54 | nouveau_irq_register(dev, 12, nv50_graph_isr); | ||
53 | nv_wr32(dev, NV03_PGRAPH_INTR, 0xffffffff); | 55 | nv_wr32(dev, NV03_PGRAPH_INTR, 0xffffffff); |
54 | nv_wr32(dev, 0x400138, 0xffffffff); | 56 | nv_wr32(dev, 0x400138, 0xffffffff); |
55 | nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xffffffff); | 57 | nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xffffffff); |
@@ -165,6 +167,8 @@ void | |||
165 | nv50_graph_takedown(struct drm_device *dev) | 167 | nv50_graph_takedown(struct drm_device *dev) |
166 | { | 168 | { |
167 | NV_DEBUG(dev, "\n"); | 169 | NV_DEBUG(dev, "\n"); |
170 | nv_wr32(dev, 0x40013c, 0x00000000); | ||
171 | nouveau_irq_unregister(dev, 12); | ||
168 | } | 172 | } |
169 | 173 | ||
170 | void | 174 | void |
@@ -324,7 +328,7 @@ nv50_graph_unload_context(struct drm_device *dev) | |||
324 | return 0; | 328 | return 0; |
325 | } | 329 | } |
326 | 330 | ||
327 | void | 331 | static void |
328 | nv50_graph_context_switch(struct drm_device *dev) | 332 | nv50_graph_context_switch(struct drm_device *dev) |
329 | { | 333 | { |
330 | uint32_t inst; | 334 | uint32_t inst; |
@@ -512,3 +516,495 @@ nv86_graph_tlb_flush(struct drm_device *dev) | |||
512 | nv_mask(dev, 0x400500, 0x00000001, 0x00000001); | 516 | nv_mask(dev, 0x400500, 0x00000001, 0x00000001); |
513 | spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); | 517 | spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); |
514 | } | 518 | } |
519 | |||
520 | static struct nouveau_enum nv50_mp_exec_error_names[] = | ||
521 | { | ||
522 | { 3, "STACK_UNDERFLOW" }, | ||
523 | { 4, "QUADON_ACTIVE" }, | ||
524 | { 8, "TIMEOUT" }, | ||
525 | { 0x10, "INVALID_OPCODE" }, | ||
526 | { 0x40, "BREAKPOINT" }, | ||
527 | {} | ||
528 | }; | ||
529 | |||
530 | static struct nouveau_bitfield nv50_graph_trap_m2mf[] = { | ||
531 | { 0x00000001, "NOTIFY" }, | ||
532 | { 0x00000002, "IN" }, | ||
533 | { 0x00000004, "OUT" }, | ||
534 | {} | ||
535 | }; | ||
536 | |||
537 | static struct nouveau_bitfield nv50_graph_trap_vfetch[] = { | ||
538 | { 0x00000001, "FAULT" }, | ||
539 | {} | ||
540 | }; | ||
541 | |||
542 | static struct nouveau_bitfield nv50_graph_trap_strmout[] = { | ||
543 | { 0x00000001, "FAULT" }, | ||
544 | {} | ||
545 | }; | ||
546 | |||
547 | static struct nouveau_bitfield nv50_graph_trap_ccache[] = { | ||
548 | { 0x00000001, "FAULT" }, | ||
549 | {} | ||
550 | }; | ||
551 | |||
552 | /* There must be a *lot* of these. Will take some time to gather them up. */ | ||
553 | static struct nouveau_enum nv50_data_error_names[] = { | ||
554 | { 4, "INVALID_VALUE" }, | ||
555 | { 5, "INVALID_ENUM" }, | ||
556 | { 8, "INVALID_OBJECT" }, | ||
557 | { 0xc, "INVALID_BITFIELD" }, | ||
558 | { 0x28, "MP_NO_REG_SPACE" }, | ||
559 | { 0x2b, "MP_BLOCK_SIZE_MISMATCH" }, | ||
560 | {} | ||
561 | }; | ||
562 | |||
563 | static struct nouveau_bitfield nv50_graph_intr[] = { | ||
564 | { 0x00000001, "NOTIFY" }, | ||
565 | { 0x00000002, "COMPUTE_QUERY" }, | ||
566 | { 0x00000010, "ILLEGAL_MTHD" }, | ||
567 | { 0x00000020, "ILLEGAL_CLASS" }, | ||
568 | { 0x00000040, "DOUBLE_NOTIFY" }, | ||
569 | { 0x00001000, "CONTEXT_SWITCH" }, | ||
570 | { 0x00010000, "BUFFER_NOTIFY" }, | ||
571 | { 0x00100000, "DATA_ERROR" }, | ||
572 | { 0x00200000, "TRAP" }, | ||
573 | { 0x01000000, "SINGLE_STEP" }, | ||
574 | {} | ||
575 | }; | ||
576 | |||
577 | static void | ||
578 | nv50_pgraph_mp_trap(struct drm_device *dev, int tpid, int display) | ||
579 | { | ||
580 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
581 | uint32_t units = nv_rd32(dev, 0x1540); | ||
582 | uint32_t addr, mp10, status, pc, oplow, ophigh; | ||
583 | int i; | ||
584 | int mps = 0; | ||
585 | for (i = 0; i < 4; i++) { | ||
586 | if (!(units & 1 << (i+24))) | ||
587 | continue; | ||
588 | if (dev_priv->chipset < 0xa0) | ||
589 | addr = 0x408200 + (tpid << 12) + (i << 7); | ||
590 | else | ||
591 | addr = 0x408100 + (tpid << 11) + (i << 7); | ||
592 | mp10 = nv_rd32(dev, addr + 0x10); | ||
593 | status = nv_rd32(dev, addr + 0x14); | ||
594 | if (!status) | ||
595 | continue; | ||
596 | if (display) { | ||
597 | nv_rd32(dev, addr + 0x20); | ||
598 | pc = nv_rd32(dev, addr + 0x24); | ||
599 | oplow = nv_rd32(dev, addr + 0x70); | ||
600 | ophigh= nv_rd32(dev, addr + 0x74); | ||
601 | NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - " | ||
602 | "TP %d MP %d: ", tpid, i); | ||
603 | nouveau_enum_print(nv50_mp_exec_error_names, status); | ||
604 | printk(" at %06x warp %d, opcode %08x %08x\n", | ||
605 | pc&0xffffff, pc >> 24, | ||
606 | oplow, ophigh); | ||
607 | } | ||
608 | nv_wr32(dev, addr + 0x10, mp10); | ||
609 | nv_wr32(dev, addr + 0x14, 0); | ||
610 | mps++; | ||
611 | } | ||
612 | if (!mps && display) | ||
613 | NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - TP %d: " | ||
614 | "No MPs claiming errors?\n", tpid); | ||
615 | } | ||
616 | |||
617 | static void | ||
618 | nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old, | ||
619 | uint32_t ustatus_new, int display, const char *name) | ||
620 | { | ||
621 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
622 | int tps = 0; | ||
623 | uint32_t units = nv_rd32(dev, 0x1540); | ||
624 | int i, r; | ||
625 | uint32_t ustatus_addr, ustatus; | ||
626 | for (i = 0; i < 16; i++) { | ||
627 | if (!(units & (1 << i))) | ||
628 | continue; | ||
629 | if (dev_priv->chipset < 0xa0) | ||
630 | ustatus_addr = ustatus_old + (i << 12); | ||
631 | else | ||
632 | ustatus_addr = ustatus_new + (i << 11); | ||
633 | ustatus = nv_rd32(dev, ustatus_addr) & 0x7fffffff; | ||
634 | if (!ustatus) | ||
635 | continue; | ||
636 | tps++; | ||
637 | switch (type) { | ||
638 | case 6: /* texture error... unknown for now */ | ||
639 | nv50_fb_vm_trap(dev, display, name); | ||
640 | if (display) { | ||
641 | NV_ERROR(dev, "magic set %d:\n", i); | ||
642 | for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4) | ||
643 | NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, | ||
644 | nv_rd32(dev, r)); | ||
645 | } | ||
646 | break; | ||
647 | case 7: /* MP error */ | ||
648 | if (ustatus & 0x00010000) { | ||
649 | nv50_pgraph_mp_trap(dev, i, display); | ||
650 | ustatus &= ~0x00010000; | ||
651 | } | ||
652 | break; | ||
653 | case 8: /* TPDMA error */ | ||
654 | { | ||
655 | uint32_t e0c = nv_rd32(dev, ustatus_addr + 4); | ||
656 | uint32_t e10 = nv_rd32(dev, ustatus_addr + 8); | ||
657 | uint32_t e14 = nv_rd32(dev, ustatus_addr + 0xc); | ||
658 | uint32_t e18 = nv_rd32(dev, ustatus_addr + 0x10); | ||
659 | uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14); | ||
660 | uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18); | ||
661 | uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c); | ||
662 | nv50_fb_vm_trap(dev, display, name); | ||
663 | /* 2d engine destination */ | ||
664 | if (ustatus & 0x00000010) { | ||
665 | if (display) { | ||
666 | NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - Unknown fault at address %02x%08x\n", | ||
667 | i, e14, e10); | ||
668 | NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", | ||
669 | i, e0c, e18, e1c, e20, e24); | ||
670 | } | ||
671 | ustatus &= ~0x00000010; | ||
672 | } | ||
673 | /* Render target */ | ||
674 | if (ustatus & 0x00000040) { | ||
675 | if (display) { | ||
676 | NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - Unknown fault at address %02x%08x\n", | ||
677 | i, e14, e10); | ||
678 | NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", | ||
679 | i, e0c, e18, e1c, e20, e24); | ||
680 | } | ||
681 | ustatus &= ~0x00000040; | ||
682 | } | ||
683 | /* CUDA memory: l[], g[] or stack. */ | ||
684 | if (ustatus & 0x00000080) { | ||
685 | if (display) { | ||
686 | if (e18 & 0x80000000) { | ||
687 | /* g[] read fault? */ | ||
688 | NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global read fault at address %02x%08x\n", | ||
689 | i, e14, e10 | ((e18 >> 24) & 0x1f)); | ||
690 | e18 &= ~0x1f000000; | ||
691 | } else if (e18 & 0xc) { | ||
692 | /* g[] write fault? */ | ||
693 | NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global write fault at address %02x%08x\n", | ||
694 | i, e14, e10 | ((e18 >> 7) & 0x1f)); | ||
695 | e18 &= ~0x00000f80; | ||
696 | } else { | ||
697 | NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Unknown CUDA fault at address %02x%08x\n", | ||
698 | i, e14, e10); | ||
699 | } | ||
700 | NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", | ||
701 | i, e0c, e18, e1c, e20, e24); | ||
702 | } | ||
703 | ustatus &= ~0x00000080; | ||
704 | } | ||
705 | } | ||
706 | break; | ||
707 | } | ||
708 | if (ustatus) { | ||
709 | if (display) | ||
710 | NV_INFO(dev, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus); | ||
711 | } | ||
712 | nv_wr32(dev, ustatus_addr, 0xc0000000); | ||
713 | } | ||
714 | |||
715 | if (!tps && display) | ||
716 | NV_INFO(dev, "%s - No TPs claiming errors?\n", name); | ||
717 | } | ||
718 | |||
719 | static int | ||
720 | nv50_pgraph_trap_handler(struct drm_device *dev, u32 display, u64 inst, u32 chid) | ||
721 | { | ||
722 | u32 status = nv_rd32(dev, 0x400108); | ||
723 | u32 ustatus; | ||
724 | |||
725 | if (!status && display) { | ||
726 | NV_INFO(dev, "PGRAPH - TRAP: no units reporting traps?\n"); | ||
727 | return 1; | ||
728 | } | ||
729 | |||
730 | /* DISPATCH: Relays commands to other units and handles NOTIFY, | ||
731 | * COND, QUERY. If you get a trap from it, the command is still stuck | ||
732 | * in DISPATCH and you need to do something about it. */ | ||
733 | if (status & 0x001) { | ||
734 | ustatus = nv_rd32(dev, 0x400804) & 0x7fffffff; | ||
735 | if (!ustatus && display) { | ||
736 | NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - no ustatus?\n"); | ||
737 | } | ||
738 | |||
739 | nv_wr32(dev, 0x400500, 0x00000000); | ||
740 | |||
741 | /* Known to be triggered by screwed up NOTIFY and COND... */ | ||
742 | if (ustatus & 0x00000001) { | ||
743 | u32 addr = nv_rd32(dev, 0x400808); | ||
744 | u32 subc = (addr & 0x00070000) >> 16; | ||
745 | u32 mthd = (addr & 0x00001ffc); | ||
746 | u32 datal = nv_rd32(dev, 0x40080c); | ||
747 | u32 datah = nv_rd32(dev, 0x400810); | ||
748 | u32 class = nv_rd32(dev, 0x400814); | ||
749 | u32 r848 = nv_rd32(dev, 0x400848); | ||
750 | |||
751 | NV_INFO(dev, "PGRAPH - TRAP DISPATCH_FAULT\n"); | ||
752 | if (display && (addr & 0x80000000)) { | ||
753 | NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) " | ||
754 | "subc %d class 0x%04x mthd 0x%04x " | ||
755 | "data 0x%08x%08x " | ||
756 | "400808 0x%08x 400848 0x%08x\n", | ||
757 | chid, inst, subc, class, mthd, datah, | ||
758 | datal, addr, r848); | ||
759 | } else | ||
760 | if (display) { | ||
761 | NV_INFO(dev, "PGRAPH - no stuck command?\n"); | ||
762 | } | ||
763 | |||
764 | nv_wr32(dev, 0x400808, 0); | ||
765 | nv_wr32(dev, 0x4008e8, nv_rd32(dev, 0x4008e8) & 3); | ||
766 | nv_wr32(dev, 0x400848, 0); | ||
767 | ustatus &= ~0x00000001; | ||
768 | } | ||
769 | |||
770 | if (ustatus & 0x00000002) { | ||
771 | u32 addr = nv_rd32(dev, 0x40084c); | ||
772 | u32 subc = (addr & 0x00070000) >> 16; | ||
773 | u32 mthd = (addr & 0x00001ffc); | ||
774 | u32 data = nv_rd32(dev, 0x40085c); | ||
775 | u32 class = nv_rd32(dev, 0x400814); | ||
776 | |||
777 | NV_INFO(dev, "PGRAPH - TRAP DISPATCH_QUERY\n"); | ||
778 | if (display && (addr & 0x80000000)) { | ||
779 | NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) " | ||
780 | "subc %d class 0x%04x mthd 0x%04x " | ||
781 | "data 0x%08x 40084c 0x%08x\n", | ||
782 | chid, inst, subc, class, mthd, | ||
783 | data, addr); | ||
784 | } else | ||
785 | if (display) { | ||
786 | NV_INFO(dev, "PGRAPH - no stuck command?\n"); | ||
787 | } | ||
788 | |||
789 | nv_wr32(dev, 0x40084c, 0); | ||
790 | ustatus &= ~0x00000002; | ||
791 | } | ||
792 | |||
793 | if (ustatus && display) { | ||
794 | NV_INFO(dev, "PGRAPH - TRAP_DISPATCH (unknown " | ||
795 | "0x%08x)\n", ustatus); | ||
796 | } | ||
797 | |||
798 | nv_wr32(dev, 0x400804, 0xc0000000); | ||
799 | nv_wr32(dev, 0x400108, 0x001); | ||
800 | status &= ~0x001; | ||
801 | if (!status) | ||
802 | return 0; | ||
803 | } | ||
804 | |||
805 | /* M2MF: Memory to memory copy engine. */ | ||
806 | if (status & 0x002) { | ||
807 | u32 ustatus = nv_rd32(dev, 0x406800) & 0x7fffffff; | ||
808 | if (display) { | ||
809 | NV_INFO(dev, "PGRAPH - TRAP_M2MF"); | ||
810 | nouveau_bitfield_print(nv50_graph_trap_m2mf, ustatus); | ||
811 | printk("\n"); | ||
812 | NV_INFO(dev, "PGRAPH - TRAP_M2MF %08x %08x %08x %08x\n", | ||
813 | nv_rd32(dev, 0x406804), nv_rd32(dev, 0x406808), | ||
814 | nv_rd32(dev, 0x40680c), nv_rd32(dev, 0x406810)); | ||
815 | |||
816 | } | ||
817 | |||
818 | /* No sane way found yet -- just reset the bugger. */ | ||
819 | nv_wr32(dev, 0x400040, 2); | ||
820 | nv_wr32(dev, 0x400040, 0); | ||
821 | nv_wr32(dev, 0x406800, 0xc0000000); | ||
822 | nv_wr32(dev, 0x400108, 0x002); | ||
823 | status &= ~0x002; | ||
824 | } | ||
825 | |||
826 | /* VFETCH: Fetches data from vertex buffers. */ | ||
827 | if (status & 0x004) { | ||
828 | u32 ustatus = nv_rd32(dev, 0x400c04) & 0x7fffffff; | ||
829 | if (display) { | ||
830 | NV_INFO(dev, "PGRAPH - TRAP_VFETCH"); | ||
831 | nouveau_bitfield_print(nv50_graph_trap_vfetch, ustatus); | ||
832 | printk("\n"); | ||
833 | NV_INFO(dev, "PGRAPH - TRAP_VFETCH %08x %08x %08x %08x\n", | ||
834 | nv_rd32(dev, 0x400c00), nv_rd32(dev, 0x400c08), | ||
835 | nv_rd32(dev, 0x400c0c), nv_rd32(dev, 0x400c10)); | ||
836 | } | ||
837 | |||
838 | nv_wr32(dev, 0x400c04, 0xc0000000); | ||
839 | nv_wr32(dev, 0x400108, 0x004); | ||
840 | status &= ~0x004; | ||
841 | } | ||
842 | |||
843 | /* STRMOUT: DirectX streamout / OpenGL transform feedback. */ | ||
844 | if (status & 0x008) { | ||
845 | ustatus = nv_rd32(dev, 0x401800) & 0x7fffffff; | ||
846 | if (display) { | ||
847 | NV_INFO(dev, "PGRAPH - TRAP_STRMOUT"); | ||
848 | nouveau_bitfield_print(nv50_graph_trap_strmout, ustatus); | ||
849 | printk("\n"); | ||
850 | NV_INFO(dev, "PGRAPH - TRAP_STRMOUT %08x %08x %08x %08x\n", | ||
851 | nv_rd32(dev, 0x401804), nv_rd32(dev, 0x401808), | ||
852 | nv_rd32(dev, 0x40180c), nv_rd32(dev, 0x401810)); | ||
853 | |||
854 | } | ||
855 | |||
856 | /* No sane way found yet -- just reset the bugger. */ | ||
857 | nv_wr32(dev, 0x400040, 0x80); | ||
858 | nv_wr32(dev, 0x400040, 0); | ||
859 | nv_wr32(dev, 0x401800, 0xc0000000); | ||
860 | nv_wr32(dev, 0x400108, 0x008); | ||
861 | status &= ~0x008; | ||
862 | } | ||
863 | |||
864 | /* CCACHE: Handles code and c[] caches and fills them. */ | ||
865 | if (status & 0x010) { | ||
866 | ustatus = nv_rd32(dev, 0x405018) & 0x7fffffff; | ||
867 | if (display) { | ||
868 | NV_INFO(dev, "PGRAPH - TRAP_CCACHE"); | ||
869 | nouveau_bitfield_print(nv50_graph_trap_ccache, ustatus); | ||
870 | printk("\n"); | ||
871 | NV_INFO(dev, "PGRAPH - TRAP_CCACHE %08x %08x %08x %08x" | ||
872 | " %08x %08x %08x\n", | ||
873 | nv_rd32(dev, 0x405800), nv_rd32(dev, 0x405804), | ||
874 | nv_rd32(dev, 0x405808), nv_rd32(dev, 0x40580c), | ||
875 | nv_rd32(dev, 0x405810), nv_rd32(dev, 0x405814), | ||
876 | nv_rd32(dev, 0x40581c)); | ||
877 | |||
878 | } | ||
879 | |||
880 | nv_wr32(dev, 0x405018, 0xc0000000); | ||
881 | nv_wr32(dev, 0x400108, 0x010); | ||
882 | status &= ~0x010; | ||
883 | } | ||
884 | |||
885 | /* Unknown, not seen yet... 0x402000 is the only trap status reg | ||
886 | * remaining, so try to handle it anyway. Perhaps related to that | ||
887 | * unknown DMA slot on tesla? */ | ||
888 | if (status & 0x20) { | ||
889 | ustatus = nv_rd32(dev, 0x402000) & 0x7fffffff; | ||
890 | if (display) | ||
891 | NV_INFO(dev, "PGRAPH - TRAP_UNKC04 0x%08x\n", ustatus); | ||
892 | nv_wr32(dev, 0x402000, 0xc0000000); | ||
893 | /* no status modifiction on purpose */ | ||
894 | } | ||
895 | |||
896 | /* TEXTURE: CUDA texturing units */ | ||
897 | if (status & 0x040) { | ||
898 | nv50_pgraph_tp_trap(dev, 6, 0x408900, 0x408600, display, | ||
899 | "PGRAPH - TRAP_TEXTURE"); | ||
900 | nv_wr32(dev, 0x400108, 0x040); | ||
901 | status &= ~0x040; | ||
902 | } | ||
903 | |||
904 | /* MP: CUDA execution engines. */ | ||
905 | if (status & 0x080) { | ||
906 | nv50_pgraph_tp_trap(dev, 7, 0x408314, 0x40831c, display, | ||
907 | "PGRAPH - TRAP_MP"); | ||
908 | nv_wr32(dev, 0x400108, 0x080); | ||
909 | status &= ~0x080; | ||
910 | } | ||
911 | |||
912 | /* TPDMA: Handles TP-initiated uncached memory accesses: | ||
913 | * l[], g[], stack, 2d surfaces, render targets. */ | ||
914 | if (status & 0x100) { | ||
915 | nv50_pgraph_tp_trap(dev, 8, 0x408e08, 0x408708, display, | ||
916 | "PGRAPH - TRAP_TPDMA"); | ||
917 | nv_wr32(dev, 0x400108, 0x100); | ||
918 | status &= ~0x100; | ||
919 | } | ||
920 | |||
921 | if (status) { | ||
922 | if (display) | ||
923 | NV_INFO(dev, "PGRAPH - TRAP: unknown 0x%08x\n", status); | ||
924 | nv_wr32(dev, 0x400108, status); | ||
925 | } | ||
926 | |||
927 | return 1; | ||
928 | } | ||
929 | |||
930 | static int | ||
931 | nv50_graph_isr_chid(struct drm_device *dev, u64 inst) | ||
932 | { | ||
933 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
934 | struct nouveau_channel *chan; | ||
935 | unsigned long flags; | ||
936 | int i; | ||
937 | |||
938 | spin_lock_irqsave(&dev_priv->channels.lock, flags); | ||
939 | for (i = 0; i < dev_priv->engine.fifo.channels; i++) { | ||
940 | chan = dev_priv->channels.ptr[i]; | ||
941 | if (!chan || !chan->ramin) | ||
942 | continue; | ||
943 | |||
944 | if (inst == chan->ramin->vinst) | ||
945 | break; | ||
946 | } | ||
947 | spin_unlock_irqrestore(&dev_priv->channels.lock, flags); | ||
948 | return i; | ||
949 | } | ||
950 | |||
951 | static void | ||
952 | nv50_graph_isr(struct drm_device *dev) | ||
953 | { | ||
954 | u32 stat; | ||
955 | |||
956 | while ((stat = nv_rd32(dev, 0x400100))) { | ||
957 | u64 inst = (u64)(nv_rd32(dev, 0x40032c) & 0x0fffffff) << 12; | ||
958 | u32 chid = nv50_graph_isr_chid(dev, inst); | ||
959 | u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR); | ||
960 | u32 subc = (addr & 0x00070000) >> 16; | ||
961 | u32 mthd = (addr & 0x00001ffc); | ||
962 | u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA); | ||
963 | u32 class = nv_rd32(dev, 0x400814); | ||
964 | u32 show = stat; | ||
965 | |||
966 | if (stat & 0x00000010) { | ||
967 | if (!nouveau_gpuobj_mthd_call2(dev, chid, class, | ||
968 | mthd, data)) | ||
969 | show &= ~0x00000010; | ||
970 | } | ||
971 | |||
972 | if (stat & 0x00001000) { | ||
973 | nv_wr32(dev, 0x400500, 0x00000000); | ||
974 | nv_wr32(dev, 0x400100, 0x00001000); | ||
975 | nv_mask(dev, 0x40013c, 0x00001000, 0x00000000); | ||
976 | nv50_graph_context_switch(dev); | ||
977 | stat &= ~0x00001000; | ||
978 | show &= ~0x00001000; | ||
979 | } | ||
980 | |||
981 | show = (show && nouveau_ratelimit()) ? show : 0; | ||
982 | |||
983 | if (show & 0x00100000) { | ||
984 | u32 ecode = nv_rd32(dev, 0x400110); | ||
985 | NV_INFO(dev, "PGRAPH - DATA_ERROR "); | ||
986 | nouveau_enum_print(nv50_data_error_names, ecode); | ||
987 | printk("\n"); | ||
988 | } | ||
989 | |||
990 | if (stat & 0x00200000) { | ||
991 | if (!nv50_pgraph_trap_handler(dev, show, inst, chid)) | ||
992 | show &= ~0x00200000; | ||
993 | } | ||
994 | |||
995 | nv_wr32(dev, 0x400100, stat); | ||
996 | nv_wr32(dev, 0x400500, 0x00010001); | ||
997 | |||
998 | if (show) { | ||
999 | NV_INFO(dev, "PGRAPH -"); | ||
1000 | nouveau_bitfield_print(nv50_graph_intr, show); | ||
1001 | printk("\n"); | ||
1002 | NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) subc %d " | ||
1003 | "class 0x%04x mthd 0x%04x data 0x%08x\n", | ||
1004 | chid, inst, subc, class, mthd, data); | ||
1005 | } | ||
1006 | } | ||
1007 | |||
1008 | if (nv_rd32(dev, 0x400824) & (1 << 31)) | ||
1009 | nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31)); | ||
1010 | } | ||