aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMarcin Koƛcielnicki <koriakin@0x04.net>2010-02-28 19:18:39 -0500
committerBen Skeggs <bskeggs@redhat.com>2010-03-10 01:07:02 -0500
commit304424e17dd904cef048ef8966d9f54618a915cc (patch)
tree43bc2c01d700eb8225380eaa0ba2cab637d6c3c1 /drivers
parent3bf777bf0ab112527cea103c3681934a9f41c03d (diff)
drm/nv50: Improve PGRAPH interrupt handling.
This makes nouveau recognise and report more kinds of PGRAPH errors, as well as prevent GPU lockups resulting from some of them. Lots of guesswork was involved and some part of this is probably incorrect. Some potential-lockuop situations are handled by just resetting a whole PGRAPH subunit, which doesn't sound like a "proper" solution, but seems to work just fine... for now. Signed-off-by: Marcin Koƛcielnicki <koriakin@0x04.net> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/nouveau/Makefile2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_irq.c609
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c5
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fb.c32
-rw-r--r--drivers/gpu/drm/nouveau/nv50_graph.c18
-rw-r--r--drivers/gpu/drm/nouveau/nv50_grctx.c8
7 files changed, 622 insertions, 56 deletions
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index 32db806f3b5a..7f0d807a0d0d 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -12,7 +12,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
12 nouveau_dp.o nouveau_grctx.o \ 12 nouveau_dp.o nouveau_grctx.o \
13 nv04_timer.o \ 13 nv04_timer.o \
14 nv04_mc.o nv40_mc.o nv50_mc.o \ 14 nv04_mc.o nv40_mc.o nv50_mc.o \
15 nv04_fb.o nv10_fb.o nv40_fb.o \ 15 nv04_fb.o nv10_fb.o nv40_fb.o nv50_fb.o \
16 nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \ 16 nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \
17 nv04_graph.o nv10_graph.o nv20_graph.o \ 17 nv04_graph.o nv10_graph.o nv20_graph.o \
18 nv40_graph.o nv50_graph.o \ 18 nv40_graph.o nv50_graph.o \
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 2f8ce42f0725..ad2d75d5dd98 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -930,6 +930,10 @@ extern void nv40_fb_takedown(struct drm_device *);
930extern void nv40_fb_set_region_tiling(struct drm_device *, int, uint32_t, 930extern void nv40_fb_set_region_tiling(struct drm_device *, int, uint32_t,
931 uint32_t, uint32_t); 931 uint32_t, uint32_t);
932 932
933/* nv50_fb.c */
934extern int nv50_fb_init(struct drm_device *);
935extern void nv50_fb_takedown(struct drm_device *);
936
933/* nv04_fifo.c */ 937/* nv04_fifo.c */
934extern int nv04_fifo_init(struct drm_device *); 938extern int nv04_fifo_init(struct drm_device *);
935extern void nv04_fifo_disable(struct drm_device *); 939extern void nv04_fifo_disable(struct drm_device *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c
index 95220ddebb45..2bd59a92fee5 100644
--- a/drivers/gpu/drm/nouveau/nouveau_irq.c
+++ b/drivers/gpu/drm/nouveau/nouveau_irq.c
@@ -311,6 +311,31 @@ nouveau_print_bitfield_names_(uint32_t value,
311#define nouveau_print_bitfield_names(val, namelist) \ 311#define nouveau_print_bitfield_names(val, namelist) \
312 nouveau_print_bitfield_names_((val), (namelist), ARRAY_SIZE(namelist)) 312 nouveau_print_bitfield_names_((val), (namelist), ARRAY_SIZE(namelist))
313 313
314struct nouveau_enum_names {
315 uint32_t value;
316 const char *name;
317};
318
319static void
320nouveau_print_enum_names_(uint32_t value,
321 const struct nouveau_enum_names *namelist,
322 const int namelist_len)
323{
324 /*
325 * Caller must have already printed the KERN_* log level for us.
326 * Also the caller is responsible for adding the newline.
327 */
328 int i;
329 for (i = 0; i < namelist_len; ++i) {
330 if (value == namelist[i].value) {
331 printk("%s", namelist[i].name);
332 return;
333 }
334 }
335 printk("unknown value 0x%08x", value);
336}
337#define nouveau_print_enum_names(val, namelist) \
338 nouveau_print_enum_names_((val), (namelist), ARRAY_SIZE(namelist))
314 339
315static int 340static int
316nouveau_graph_chid_from_grctx(struct drm_device *dev) 341nouveau_graph_chid_from_grctx(struct drm_device *dev)
@@ -427,14 +452,16 @@ nouveau_graph_dump_trap_info(struct drm_device *dev, const char *id,
427 struct drm_nouveau_private *dev_priv = dev->dev_private; 452 struct drm_nouveau_private *dev_priv = dev->dev_private;
428 uint32_t nsource = trap->nsource, nstatus = trap->nstatus; 453 uint32_t nsource = trap->nsource, nstatus = trap->nstatus;
429 454
430 NV_INFO(dev, "%s - nSource:", id); 455 if (dev_priv->card_type < NV_50) {
431 nouveau_print_bitfield_names(nsource, nsource_names); 456 NV_INFO(dev, "%s - nSource:", id);
432 printk(", nStatus:"); 457 nouveau_print_bitfield_names(nsource, nsource_names);
433 if (dev_priv->card_type < NV_10) 458 printk(", nStatus:");
434 nouveau_print_bitfield_names(nstatus, nstatus_names); 459 if (dev_priv->card_type < NV_10)
435 else 460 nouveau_print_bitfield_names(nstatus, nstatus_names);
436 nouveau_print_bitfield_names(nstatus, nstatus_names_nv10); 461 else
437 printk("\n"); 462 nouveau_print_bitfield_names(nstatus, nstatus_names_nv10);
463 printk("\n");
464 }
438 465
439 NV_INFO(dev, "%s - Ch %d/%d Class 0x%04x Mthd 0x%04x " 466 NV_INFO(dev, "%s - Ch %d/%d Class 0x%04x Mthd 0x%04x "
440 "Data 0x%08x:0x%08x\n", 467 "Data 0x%08x:0x%08x\n",
@@ -578,27 +605,502 @@ nouveau_pgraph_irq_handler(struct drm_device *dev)
578} 605}
579 606
580static void 607static void
608nv50_pfb_vm_trap(struct drm_device *dev, int display, const char *name)
609{
610 struct drm_nouveau_private *dev_priv = dev->dev_private;
611 uint32_t trap[6];
612 int i, ch;
613 uint32_t idx = nv_rd32(dev, 0x100c90);
614 if (idx & 0x80000000) {
615 idx &= 0xffffff;
616 if (display) {
617 for (i = 0; i < 6; i++) {
618 nv_wr32(dev, 0x100c90, idx | i << 24);
619 trap[i] = nv_rd32(dev, 0x100c94);
620 }
621 for (ch = 0; ch < dev_priv->engine.fifo.channels; ch++) {
622 struct nouveau_channel *chan = dev_priv->fifos[ch];
623
624 if (!chan || !chan->ramin)
625 continue;
626
627 if (trap[1] == chan->ramin->instance >> 12)
628 break;
629 }
630 NV_INFO(dev, "%s - VM: Trapped %s at %02x%04x%04x status %08x %08x channel %d\n",
631 name, (trap[5]&0x100?"read":"write"),
632 trap[5]&0xff, trap[4]&0xffff,
633 trap[3]&0xffff, trap[0], trap[2], ch);
634 }
635 nv_wr32(dev, 0x100c90, idx | 0x80000000);
636 } else if (display) {
637 NV_INFO(dev, "%s - no VM fault?\n", name);
638 }
639}
640
641static struct nouveau_enum_names nv50_mp_exec_error_names[] =
642{
643 { 3, "STACK_UNDERFLOW" },
644 { 4, "QUADON_ACTIVE" },
645 { 8, "TIMEOUT" },
646 { 0x10, "INVALID_OPCODE" },
647 { 0x40, "BREAKPOINT" },
648};
649
650static void
651nv50_pgraph_mp_trap(struct drm_device *dev, int tpid, int display)
652{
653 struct drm_nouveau_private *dev_priv = dev->dev_private;
654 uint32_t units = nv_rd32(dev, 0x1540);
655 uint32_t addr, mp10, status, pc, oplow, ophigh;
656 int i;
657 int mps = 0;
658 for (i = 0; i < 4; i++) {
659 if (!(units & 1 << (i+24)))
660 continue;
661 if (dev_priv->chipset < 0xa0)
662 addr = 0x408200 + (tpid << 12) + (i << 7);
663 else
664 addr = 0x408100 + (tpid << 11) + (i << 7);
665 mp10 = nv_rd32(dev, addr + 0x10);
666 status = nv_rd32(dev, addr + 0x14);
667 if (!status)
668 continue;
669 if (display) {
670 nv_rd32(dev, addr + 0x20);
671 pc = nv_rd32(dev, addr + 0x24);
672 oplow = nv_rd32(dev, addr + 0x70);
673 ophigh= nv_rd32(dev, addr + 0x74);
674 NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - "
675 "TP %d MP %d: ", tpid, i);
676 nouveau_print_enum_names(status,
677 nv50_mp_exec_error_names);
678 printk(" at %06x warp %d, opcode %08x %08x\n",
679 pc&0xffffff, pc >> 24,
680 oplow, ophigh);
681 }
682 nv_wr32(dev, addr + 0x10, mp10);
683 nv_wr32(dev, addr + 0x14, 0);
684 mps++;
685 }
686 if (!mps && display)
687 NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - TP %d: "
688 "No MPs claiming errors?\n", tpid);
689}
690
691static void
692nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old,
693 uint32_t ustatus_new, int display, const char *name)
694{
695 struct drm_nouveau_private *dev_priv = dev->dev_private;
696 int tps = 0;
697 uint32_t units = nv_rd32(dev, 0x1540);
698 int i, r;
699 uint32_t ustatus_addr, ustatus;
700 for (i = 0; i < 16; i++) {
701 if (!(units & (1 << i)))
702 continue;
703 if (dev_priv->chipset < 0xa0)
704 ustatus_addr = ustatus_old + (i << 12);
705 else
706 ustatus_addr = ustatus_new + (i << 11);
707 ustatus = nv_rd32(dev, ustatus_addr) & 0x7fffffff;
708 if (!ustatus)
709 continue;
710 tps++;
711 switch (type) {
712 case 6: /* texture error... unknown for now */
713 nv50_pfb_vm_trap(dev, display, name);
714 if (display) {
715 NV_ERROR(dev, "magic set %d:\n", i);
716 for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4)
717 NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r,
718 nv_rd32(dev, r));
719 }
720 break;
721 case 7: /* MP error */
722 if (ustatus & 0x00010000) {
723 nv50_pgraph_mp_trap(dev, i, display);
724 ustatus &= ~0x00010000;
725 }
726 break;
727 case 8: /* TPDMA error */
728 {
729 uint32_t e0c = nv_rd32(dev, ustatus_addr + 4);
730 uint32_t e10 = nv_rd32(dev, ustatus_addr + 8);
731 uint32_t e14 = nv_rd32(dev, ustatus_addr + 0xc);
732 uint32_t e18 = nv_rd32(dev, ustatus_addr + 0x10);
733 uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14);
734 uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18);
735 uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c);
736 nv50_pfb_vm_trap(dev, display, name);
737 /* 2d engine destination */
738 if (ustatus & 0x00000010) {
739 if (display) {
740 NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - Unknown fault at address %02x%08x\n",
741 i, e14, e10);
742 NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
743 i, e0c, e18, e1c, e20, e24);
744 }
745 ustatus &= ~0x00000010;
746 }
747 /* Render target */
748 if (ustatus & 0x00000040) {
749 if (display) {
750 NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - Unknown fault at address %02x%08x\n",
751 i, e14, e10);
752 NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
753 i, e0c, e18, e1c, e20, e24);
754 }
755 ustatus &= ~0x00000040;
756 }
757 /* CUDA memory: l[], g[] or stack. */
758 if (ustatus & 0x00000080) {
759 if (display) {
760 if (e18 & 0x80000000) {
761 /* g[] read fault? */
762 NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global read fault at address %02x%08x\n",
763 i, e14, e10 | ((e18 >> 24) & 0x1f));
764 e18 &= ~0x1f000000;
765 } else if (e18 & 0xc) {
766 /* g[] write fault? */
767 NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global write fault at address %02x%08x\n",
768 i, e14, e10 | ((e18 >> 7) & 0x1f));
769 e18 &= ~0x00000f80;
770 } else {
771 NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Unknown CUDA fault at address %02x%08x\n",
772 i, e14, e10);
773 }
774 NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
775 i, e0c, e18, e1c, e20, e24);
776 }
777 ustatus &= ~0x00000080;
778 }
779 }
780 break;
781 }
782 if (ustatus) {
783 if (display)
784 NV_INFO(dev, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus);
785 }
786 nv_wr32(dev, ustatus_addr, 0xc0000000);
787 }
788
789 if (!tps && display)
790 NV_INFO(dev, "%s - No TPs claiming errors?\n", name);
791}
792
793static void
794nv50_pgraph_trap_handler(struct drm_device *dev)
795{
796 struct nouveau_pgraph_trap trap;
797 uint32_t status = nv_rd32(dev, 0x400108);
798 uint32_t ustatus;
799 int display = nouveau_ratelimit();
800
801
802 if (!status && display) {
803 nouveau_graph_trap_info(dev, &trap);
804 nouveau_graph_dump_trap_info(dev, "PGRAPH_TRAP", &trap);
805 NV_INFO(dev, "PGRAPH_TRAP - no units reporting traps?\n");
806 }
807
808 /* DISPATCH: Relays commands to other units and handles NOTIFY,
809 * COND, QUERY. If you get a trap from it, the command is still stuck
810 * in DISPATCH and you need to do something about it. */
811 if (status & 0x001) {
812 ustatus = nv_rd32(dev, 0x400804) & 0x7fffffff;
813 if (!ustatus && display) {
814 NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - no ustatus?\n");
815 }
816
817 /* Known to be triggered by screwed up NOTIFY and COND... */
818 if (ustatus & 0x00000001) {
819 nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_FAULT");
820 nv_wr32(dev, 0x400500, 0);
821 if (nv_rd32(dev, 0x400808) & 0x80000000) {
822 if (display) {
823 if (nouveau_graph_trapped_channel(dev, &trap.channel))
824 trap.channel = -1;
825 trap.class = nv_rd32(dev, 0x400814);
826 trap.mthd = nv_rd32(dev, 0x400808) & 0x1ffc;
827 trap.subc = (nv_rd32(dev, 0x400808) >> 16) & 0x7;
828 trap.data = nv_rd32(dev, 0x40080c);
829 trap.data2 = nv_rd32(dev, 0x400810);
830 nouveau_graph_dump_trap_info(dev,
831 "PGRAPH_TRAP_DISPATCH_FAULT", &trap);
832 NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_FAULT - 400808: %08x\n", nv_rd32(dev, 0x400808));
833 NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_FAULT - 400848: %08x\n", nv_rd32(dev, 0x400848));
834 }
835 nv_wr32(dev, 0x400808, 0);
836 } else if (display) {
837 NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_FAULT - No stuck command?\n");
838 }
839 nv_wr32(dev, 0x4008e8, nv_rd32(dev, 0x4008e8) & 3);
840 nv_wr32(dev, 0x400848, 0);
841 ustatus &= ~0x00000001;
842 }
843 if (ustatus & 0x00000002) {
844 nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_QUERY");
845 nv_wr32(dev, 0x400500, 0);
846 if (nv_rd32(dev, 0x40084c) & 0x80000000) {
847 if (display) {
848 if (nouveau_graph_trapped_channel(dev, &trap.channel))
849 trap.channel = -1;
850 trap.class = nv_rd32(dev, 0x400814);
851 trap.mthd = nv_rd32(dev, 0x40084c) & 0x1ffc;
852 trap.subc = (nv_rd32(dev, 0x40084c) >> 16) & 0x7;
853 trap.data = nv_rd32(dev, 0x40085c);
854 trap.data2 = 0;
855 nouveau_graph_dump_trap_info(dev,
856 "PGRAPH_TRAP_DISPATCH_QUERY", &trap);
857 NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_QUERY - 40084c: %08x\n", nv_rd32(dev, 0x40084c));
858 }
859 nv_wr32(dev, 0x40084c, 0);
860 } else if (display) {
861 NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_QUERY - No stuck command?\n");
862 }
863 ustatus &= ~0x00000002;
864 }
865 if (ustatus && display)
866 NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - Unhandled ustatus 0x%08x\n", ustatus);
867 nv_wr32(dev, 0x400804, 0xc0000000);
868 nv_wr32(dev, 0x400108, 0x001);
869 status &= ~0x001;
870 }
871
872 /* TRAPs other than dispatch use the "normal" trap regs. */
873 if (status && display) {
874 nouveau_graph_trap_info(dev, &trap);
875 nouveau_graph_dump_trap_info(dev,
876 "PGRAPH_TRAP", &trap);
877 }
878
879 /* M2MF: Memory to memory copy engine. */
880 if (status & 0x002) {
881 ustatus = nv_rd32(dev, 0x406800) & 0x7fffffff;
882 if (!ustatus && display) {
883 NV_INFO(dev, "PGRAPH_TRAP_M2MF - no ustatus?\n");
884 }
885 if (ustatus & 0x00000001) {
886 nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_NOTIFY");
887 ustatus &= ~0x00000001;
888 }
889 if (ustatus & 0x00000002) {
890 nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_IN");
891 ustatus &= ~0x00000002;
892 }
893 if (ustatus & 0x00000004) {
894 nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_OUT");
895 ustatus &= ~0x00000004;
896 }
897 NV_INFO (dev, "PGRAPH_TRAP_M2MF - %08x %08x %08x %08x\n",
898 nv_rd32(dev, 0x406804),
899 nv_rd32(dev, 0x406808),
900 nv_rd32(dev, 0x40680c),
901 nv_rd32(dev, 0x406810));
902 if (ustatus && display)
903 NV_INFO(dev, "PGRAPH_TRAP_M2MF - Unhandled ustatus 0x%08x\n", ustatus);
904 /* No sane way found yet -- just reset the bugger. */
905 nv_wr32(dev, 0x400040, 2);
906 nv_wr32(dev, 0x400040, 0);
907 nv_wr32(dev, 0x406800, 0xc0000000);
908 nv_wr32(dev, 0x400108, 0x002);
909 status &= ~0x002;
910 }
911
912 /* VFETCH: Fetches data from vertex buffers. */
913 if (status & 0x004) {
914 ustatus = nv_rd32(dev, 0x400c04) & 0x7fffffff;
915 if (!ustatus && display) {
916 NV_INFO(dev, "PGRAPH_TRAP_VFETCH - no ustatus?\n");
917 }
918 if (ustatus & 0x00000001) {
919 nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_VFETCH_FAULT");
920 NV_INFO (dev, "PGRAPH_TRAP_VFETCH_FAULT - %08x %08x %08x %08x\n",
921 nv_rd32(dev, 0x400c00),
922 nv_rd32(dev, 0x400c08),
923 nv_rd32(dev, 0x400c0c),
924 nv_rd32(dev, 0x400c10));
925 ustatus &= ~0x00000001;
926 }
927 if (ustatus && display)
928 NV_INFO(dev, "PGRAPH_TRAP_VFETCH - Unhandled ustatus 0x%08x\n", ustatus);
929 nv_wr32(dev, 0x400c04, 0xc0000000);
930 nv_wr32(dev, 0x400108, 0x004);
931 status &= ~0x004;
932 }
933
934 /* STRMOUT: DirectX streamout / OpenGL transform feedback. */
935 if (status & 0x008) {
936 ustatus = nv_rd32(dev, 0x401800) & 0x7fffffff;
937 if (!ustatus && display) {
938 NV_INFO(dev, "PGRAPH_TRAP_STRMOUT - no ustatus?\n");
939 }
940 if (ustatus & 0x00000001) {
941 nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_STRMOUT_FAULT");
942 NV_INFO (dev, "PGRAPH_TRAP_STRMOUT_FAULT - %08x %08x %08x %08x\n",
943 nv_rd32(dev, 0x401804),
944 nv_rd32(dev, 0x401808),
945 nv_rd32(dev, 0x40180c),
946 nv_rd32(dev, 0x401810));
947 ustatus &= ~0x00000001;
948 }
949 if (ustatus && display)
950 NV_INFO(dev, "PGRAPH_TRAP_STRMOUT - Unhandled ustatus 0x%08x\n", ustatus);
951 /* No sane way found yet -- just reset the bugger. */
952 nv_wr32(dev, 0x400040, 0x80);
953 nv_wr32(dev, 0x400040, 0);
954 nv_wr32(dev, 0x401800, 0xc0000000);
955 nv_wr32(dev, 0x400108, 0x008);
956 status &= ~0x008;
957 }
958
959 /* CCACHE: Handles code and c[] caches and fills them. */
960 if (status & 0x010) {
961 ustatus = nv_rd32(dev, 0x405018) & 0x7fffffff;
962 if (!ustatus && display) {
963 NV_INFO(dev, "PGRAPH_TRAP_CCACHE - no ustatus?\n");
964 }
965 if (ustatus & 0x00000001) {
966 nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_CCACHE_FAULT");
967 NV_INFO (dev, "PGRAPH_TRAP_CCACHE_FAULT - %08x %08x %08x %08x %08x %08x %08x\n",
968 nv_rd32(dev, 0x405800),
969 nv_rd32(dev, 0x405804),
970 nv_rd32(dev, 0x405808),
971 nv_rd32(dev, 0x40580c),
972 nv_rd32(dev, 0x405810),
973 nv_rd32(dev, 0x405814),
974 nv_rd32(dev, 0x40581c));
975 ustatus &= ~0x00000001;
976 }
977 if (ustatus && display)
978 NV_INFO(dev, "PGRAPH_TRAP_CCACHE - Unhandled ustatus 0x%08x\n", ustatus);
979 nv_wr32(dev, 0x405018, 0xc0000000);
980 nv_wr32(dev, 0x400108, 0x010);
981 status &= ~0x010;
982 }
983
984 /* Unknown, not seen yet... 0x402000 is the only trap status reg
985 * remaining, so try to handle it anyway. Perhaps related to that
986 * unknown DMA slot on tesla? */
987 if (status & 0x20) {
988 nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_UNKC04");
989 ustatus = nv_rd32(dev, 0x402000) & 0x7fffffff;
990 if (display)
991 NV_INFO(dev, "PGRAPH_TRAP_UNKC04 - Unhandled ustatus 0x%08x\n", ustatus);
992 nv_wr32(dev, 0x402000, 0xc0000000);
993 /* no status modifiction on purpose */
994 }
995
996 /* TEXTURE: CUDA texturing units */
997 if (status & 0x040) {
998 nv50_pgraph_tp_trap (dev, 6, 0x408900, 0x408600, display,
999 "PGRAPH_TRAP_TEXTURE");
1000 nv_wr32(dev, 0x400108, 0x040);
1001 status &= ~0x040;
1002 }
1003
1004 /* MP: CUDA execution engines. */
1005 if (status & 0x080) {
1006 nv50_pgraph_tp_trap (dev, 7, 0x408314, 0x40831c, display,
1007 "PGRAPH_TRAP_MP");
1008 nv_wr32(dev, 0x400108, 0x080);
1009 status &= ~0x080;
1010 }
1011
1012 /* TPDMA: Handles TP-initiated uncached memory accesses:
1013 * l[], g[], stack, 2d surfaces, render targets. */
1014 if (status & 0x100) {
1015 nv50_pgraph_tp_trap (dev, 8, 0x408e08, 0x408708, display,
1016 "PGRAPH_TRAP_TPDMA");
1017 nv_wr32(dev, 0x400108, 0x100);
1018 status &= ~0x100;
1019 }
1020
1021 if (status) {
1022 if (display)
1023 NV_INFO(dev, "PGRAPH_TRAP - Unknown trap 0x%08x\n",
1024 status);
1025 nv_wr32(dev, 0x400108, status);
1026 }
1027}
1028
1029/* There must be a *lot* of these. Will take some time to gather them up. */
1030static struct nouveau_enum_names nv50_data_error_names[] =
1031{
1032 { 4, "INVALID_VALUE" },
1033 { 5, "INVALID_ENUM" },
1034 { 8, "INVALID_OBJECT" },
1035 { 0xc, "INVALID_BITFIELD" },
1036 { 0x28, "MP_NO_REG_SPACE" },
1037 { 0x2b, "MP_BLOCK_SIZE_MISMATCH" },
1038};
1039
1040static void
581nv50_pgraph_irq_handler(struct drm_device *dev) 1041nv50_pgraph_irq_handler(struct drm_device *dev)
582{ 1042{
1043 struct nouveau_pgraph_trap trap;
1044 int unhandled = 0;
583 uint32_t status; 1045 uint32_t status;
584 1046
585 while ((status = nv_rd32(dev, NV03_PGRAPH_INTR))) { 1047 while ((status = nv_rd32(dev, NV03_PGRAPH_INTR))) {
586 uint32_t nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE); 1048 /* NOTIFY: You've set a NOTIFY an a command and it's done. */
587
588 if (status & 0x00000001) { 1049 if (status & 0x00000001) {
589 nouveau_pgraph_intr_notify(dev, nsource); 1050 nouveau_graph_trap_info(dev, &trap);
1051 if (nouveau_ratelimit())
1052 nouveau_graph_dump_trap_info(dev,
1053 "PGRAPH_NOTIFY", &trap);
590 status &= ~0x00000001; 1054 status &= ~0x00000001;
591 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000001); 1055 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000001);
592 } 1056 }
593 1057
594 if (status & 0x00000010) { 1058 /* COMPUTE_QUERY: Purpose and exact cause unknown, happens
595 nouveau_pgraph_intr_error(dev, nsource | 1059 * when you write 0x200 to 0x50c0 method 0x31c. */
596 NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD); 1060 if (status & 0x00000002) {
1061 nouveau_graph_trap_info(dev, &trap);
1062 if (nouveau_ratelimit())
1063 nouveau_graph_dump_trap_info(dev,
1064 "PGRAPH_COMPUTE_QUERY", &trap);
1065 status &= ~0x00000002;
1066 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000002);
1067 }
597 1068
1069 /* Unknown, never seen: 0x4 */
1070
1071 /* ILLEGAL_MTHD: You used a wrong method for this class. */
1072 if (status & 0x00000010) {
1073 nouveau_graph_trap_info(dev, &trap);
1074 if (nouveau_pgraph_intr_swmthd(dev, &trap))
1075 unhandled = 1;
1076 if (unhandled && nouveau_ratelimit())
1077 nouveau_graph_dump_trap_info(dev,
1078 "PGRAPH_ILLEGAL_MTHD", &trap);
598 status &= ~0x00000010; 1079 status &= ~0x00000010;
599 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000010); 1080 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000010);
600 } 1081 }
601 1082
1083 /* ILLEGAL_CLASS: You used a wrong class. */
1084 if (status & 0x00000020) {
1085 nouveau_graph_trap_info(dev, &trap);
1086 if (nouveau_ratelimit())
1087 nouveau_graph_dump_trap_info(dev,
1088 "PGRAPH_ILLEGAL_CLASS", &trap);
1089 status &= ~0x00000020;
1090 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000020);
1091 }
1092
1093 /* DOUBLE_NOTIFY: You tried to set a NOTIFY on another NOTIFY. */
1094 if (status & 0x00000040) {
1095 nouveau_graph_trap_info(dev, &trap);
1096 if (nouveau_ratelimit())
1097 nouveau_graph_dump_trap_info(dev,
1098 "PGRAPH_DOUBLE_NOTIFY", &trap);
1099 status &= ~0x00000040;
1100 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000040);
1101 }
1102
1103 /* CONTEXT_SWITCH: PGRAPH needs us to load a new context */
602 if (status & 0x00001000) { 1104 if (status & 0x00001000) {
603 nv_wr32(dev, 0x400500, 0x00000000); 1105 nv_wr32(dev, 0x400500, 0x00000000);
604 nv_wr32(dev, NV03_PGRAPH_INTR, 1106 nv_wr32(dev, NV03_PGRAPH_INTR,
@@ -613,49 +1115,59 @@ nv50_pgraph_irq_handler(struct drm_device *dev)
613 status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; 1115 status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
614 } 1116 }
615 1117
616 if (status & 0x00100000) { 1118 /* BUFFER_NOTIFY: Your m2mf transfer finished */
617 nouveau_pgraph_intr_error(dev, nsource | 1119 if (status & 0x00010000) {
618 NV03_PGRAPH_NSOURCE_DATA_ERROR); 1120 nouveau_graph_trap_info(dev, &trap);
1121 if (nouveau_ratelimit())
1122 nouveau_graph_dump_trap_info(dev,
1123 "PGRAPH_BUFFER_NOTIFY", &trap);
1124 status &= ~0x00010000;
1125 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00010000);
1126 }
619 1127
1128 /* DATA_ERROR: Invalid value for this method, or invalid
1129 * state in current PGRAPH context for this operation */
1130 if (status & 0x00100000) {
1131 nouveau_graph_trap_info(dev, &trap);
1132 if (nouveau_ratelimit()) {
1133 nouveau_graph_dump_trap_info(dev,
1134 "PGRAPH_DATA_ERROR", &trap);
1135 NV_INFO (dev, "PGRAPH_DATA_ERROR - ");
1136 nouveau_print_enum_names(nv_rd32(dev, 0x400110),
1137 nv50_data_error_names);
1138 printk("\n");
1139 }
620 status &= ~0x00100000; 1140 status &= ~0x00100000;
621 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00100000); 1141 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00100000);
622 } 1142 }
623 1143
1144 /* TRAP: Something bad happened in the middle of command
1145 * execution. Has a billion types, subtypes, and even
1146 * subsubtypes. */
624 if (status & 0x00200000) { 1147 if (status & 0x00200000) {
625 int r; 1148 nv50_pgraph_trap_handler(dev);
626
627 nouveau_pgraph_intr_error(dev, nsource |
628 NV03_PGRAPH_NSOURCE_PROTECTION_ERROR);
629
630 NV_ERROR(dev, "magic set 1:\n");
631 for (r = 0x408900; r <= 0x408910; r += 4)
632 NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r,
633 nv_rd32(dev, r));
634 nv_wr32(dev, 0x408900,
635 nv_rd32(dev, 0x408904) | 0xc0000000);
636 for (r = 0x408e08; r <= 0x408e24; r += 4)
637 NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r,
638 nv_rd32(dev, r));
639 nv_wr32(dev, 0x408e08,
640 nv_rd32(dev, 0x408e08) | 0xc0000000);
641
642 NV_ERROR(dev, "magic set 2:\n");
643 for (r = 0x409900; r <= 0x409910; r += 4)
644 NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r,
645 nv_rd32(dev, r));
646 nv_wr32(dev, 0x409900,
647 nv_rd32(dev, 0x409904) | 0xc0000000);
648 for (r = 0x409e08; r <= 0x409e24; r += 4)
649 NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r,
650 nv_rd32(dev, r));
651 nv_wr32(dev, 0x409e08,
652 nv_rd32(dev, 0x409e08) | 0xc0000000);
653
654 status &= ~0x00200000; 1149 status &= ~0x00200000;
655 nv_wr32(dev, NV03_PGRAPH_NSOURCE, nsource);
656 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00200000); 1150 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00200000);
657 } 1151 }
658 1152
1153 /* Unknown, never seen: 0x00400000 */
1154
1155 /* SINGLE_STEP: Happens on every method if you turned on
1156 * single stepping in 40008c */
1157 if (status & 0x01000000) {
1158 nouveau_graph_trap_info(dev, &trap);
1159 if (nouveau_ratelimit())
1160 nouveau_graph_dump_trap_info(dev,
1161 "PGRAPH_SINGLE_STEP", &trap);
1162 status &= ~0x01000000;
1163 nv_wr32(dev, NV03_PGRAPH_INTR, 0x01000000);
1164 }
1165
1166 /* 0x02000000 happens when you pause a ctxprog...
1167 * but the only way this can happen that I know is by
1168 * poking the relevant MMIO register, and we don't
1169 * do that. */
1170
659 if (status) { 1171 if (status) {
660 NV_INFO(dev, "Unhandled PGRAPH_INTR - 0x%08x\n", 1172 NV_INFO(dev, "Unhandled PGRAPH_INTR - 0x%08x\n",
661 status); 1173 status);
@@ -672,7 +1184,8 @@ nv50_pgraph_irq_handler(struct drm_device *dev)
672 } 1184 }
673 1185
674 nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING); 1186 nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING);
675 nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31)); 1187 if (nv_rd32(dev, 0x400824) & (1 << 31))
1188 nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31));
676} 1189}
677 1190
678static void 1191static void
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index 516a8d36cb10..f4ea3e61c094 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -34,7 +34,6 @@
34#include "nouveau_drm.h" 34#include "nouveau_drm.h"
35#include "nv50_display.h" 35#include "nv50_display.h"
36 36
37static int nouveau_stub_init(struct drm_device *dev) { return 0; }
38static void nouveau_stub_takedown(struct drm_device *dev) {} 37static void nouveau_stub_takedown(struct drm_device *dev) {}
39 38
40static int nouveau_init_engine_ptrs(struct drm_device *dev) 39static int nouveau_init_engine_ptrs(struct drm_device *dev)
@@ -276,8 +275,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
276 engine->timer.init = nv04_timer_init; 275 engine->timer.init = nv04_timer_init;
277 engine->timer.read = nv04_timer_read; 276 engine->timer.read = nv04_timer_read;
278 engine->timer.takedown = nv04_timer_takedown; 277 engine->timer.takedown = nv04_timer_takedown;
279 engine->fb.init = nouveau_stub_init; 278 engine->fb.init = nv50_fb_init;
280 engine->fb.takedown = nouveau_stub_takedown; 279 engine->fb.takedown = nv50_fb_takedown;
281 engine->graph.grclass = nv50_graph_grclass; 280 engine->graph.grclass = nv50_graph_grclass;
282 engine->graph.init = nv50_graph_init; 281 engine->graph.init = nv50_graph_init;
283 engine->graph.takedown = nv50_graph_takedown; 282 engine->graph.takedown = nv50_graph_takedown;
diff --git a/drivers/gpu/drm/nouveau/nv50_fb.c b/drivers/gpu/drm/nouveau/nv50_fb.c
new file mode 100644
index 000000000000..a95e6941ba88
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv50_fb.c
@@ -0,0 +1,32 @@
1#include "drmP.h"
2#include "drm.h"
3#include "nouveau_drv.h"
4#include "nouveau_drm.h"
5
6int
7nv50_fb_init(struct drm_device *dev)
8{
9 /* This is needed to get meaningful information from 100c90
10 * on traps. No idea what these values mean exactly. */
11 struct drm_nouveau_private *dev_priv = dev->dev_private;
12
13 switch (dev_priv->chipset) {
14 case 0x50:
15 nv_wr32(dev, 0x100c90, 0x0707ff);
16 break;
17 case 0xa5:
18 case 0xa8:
19 nv_wr32(dev, 0x100c90, 0x0d0fff);
20 break;
21 default:
22 nv_wr32(dev, 0x100c90, 0x1d07ff);
23 break;
24 }
25
26 return 0;
27}
28
29void
30nv50_fb_takedown(struct drm_device *dev)
31{
32}
diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
index 08d87b749a52..c62b33a02f88 100644
--- a/drivers/gpu/drm/nouveau/nv50_graph.c
+++ b/drivers/gpu/drm/nouveau/nv50_graph.c
@@ -56,6 +56,10 @@ nv50_graph_init_intr(struct drm_device *dev)
56static void 56static void
57nv50_graph_init_regs__nv(struct drm_device *dev) 57nv50_graph_init_regs__nv(struct drm_device *dev)
58{ 58{
59 struct drm_nouveau_private *dev_priv = dev->dev_private;
60 uint32_t units = nv_rd32(dev, 0x1540);
61 int i;
62
59 NV_DEBUG(dev, "\n"); 63 NV_DEBUG(dev, "\n");
60 64
61 nv_wr32(dev, 0x400804, 0xc0000000); 65 nv_wr32(dev, 0x400804, 0xc0000000);
@@ -65,6 +69,20 @@ nv50_graph_init_regs__nv(struct drm_device *dev)
65 nv_wr32(dev, 0x405018, 0xc0000000); 69 nv_wr32(dev, 0x405018, 0xc0000000);
66 nv_wr32(dev, 0x402000, 0xc0000000); 70 nv_wr32(dev, 0x402000, 0xc0000000);
67 71
72 for (i = 0; i < 16; i++) {
73 if (units & 1 << i) {
74 if (dev_priv->chipset < 0xa0) {
75 nv_wr32(dev, 0x408900 + (i << 12), 0xc0000000);
76 nv_wr32(dev, 0x408e08 + (i << 12), 0xc0000000);
77 nv_wr32(dev, 0x408314 + (i << 12), 0xc0000000);
78 } else {
79 nv_wr32(dev, 0x408600 + (i << 11), 0xc0000000);
80 nv_wr32(dev, 0x408708 + (i << 11), 0xc0000000);
81 nv_wr32(dev, 0x40831c + (i << 11), 0xc0000000);
82 }
83 }
84 }
85
68 nv_wr32(dev, 0x400108, 0xffffffff); 86 nv_wr32(dev, 0x400108, 0xffffffff);
69 87
70 nv_wr32(dev, 0x400824, 0x00004000); 88 nv_wr32(dev, 0x400824, 0x00004000);
diff --git a/drivers/gpu/drm/nouveau/nv50_grctx.c b/drivers/gpu/drm/nouveau/nv50_grctx.c
index 9f909abfb5ab..546b31949a30 100644
--- a/drivers/gpu/drm/nouveau/nv50_grctx.c
+++ b/drivers/gpu/drm/nouveau/nv50_grctx.c
@@ -274,7 +274,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
274 int offset, base; 274 int offset, base;
275 uint32_t units = nv_rd32 (ctx->dev, 0x1540); 275 uint32_t units = nv_rd32 (ctx->dev, 0x1540);
276 276
277 /* 0800 */ 277 /* 0800: DISPATCH */
278 cp_ctx(ctx, 0x400808, 7); 278 cp_ctx(ctx, 0x400808, 7);
279 gr_def(ctx, 0x400814, 0x00000030); 279 gr_def(ctx, 0x400814, 0x00000030);
280 cp_ctx(ctx, 0x400834, 0x32); 280 cp_ctx(ctx, 0x400834, 0x32);
@@ -305,7 +305,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
305 gr_def(ctx, 0x400b20, 0x0001629d); 305 gr_def(ctx, 0x400b20, 0x0001629d);
306 } 306 }
307 307
308 /* 0C00 */ 308 /* 0C00: VFETCH */
309 cp_ctx(ctx, 0x400c08, 0x2); 309 cp_ctx(ctx, 0x400c08, 0x2);
310 gr_def(ctx, 0x400c08, 0x0000fe0c); 310 gr_def(ctx, 0x400c08, 0x0000fe0c);
311 311
@@ -331,7 +331,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
331 cp_ctx(ctx, 0x401540, 0x5); 331 cp_ctx(ctx, 0x401540, 0x5);
332 gr_def(ctx, 0x401550, 0x00001018); 332 gr_def(ctx, 0x401550, 0x00001018);
333 333
334 /* 1800 */ 334 /* 1800: STREAMOUT */
335 cp_ctx(ctx, 0x401814, 0x1); 335 cp_ctx(ctx, 0x401814, 0x1);
336 gr_def(ctx, 0x401814, 0x000000ff); 336 gr_def(ctx, 0x401814, 0x000000ff);
337 if (dev_priv->chipset == 0x50) { 337 if (dev_priv->chipset == 0x50) {
@@ -646,7 +646,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
646 if (dev_priv->chipset == 0x50) 646 if (dev_priv->chipset == 0x50)
647 cp_ctx(ctx, 0x4063e0, 0x1); 647 cp_ctx(ctx, 0x4063e0, 0x1);
648 648
649 /* 6800 */ 649 /* 6800: M2MF */
650 if (dev_priv->chipset < 0x90) { 650 if (dev_priv->chipset < 0x90) {
651 cp_ctx(ctx, 0x406814, 0x2b); 651 cp_ctx(ctx, 0x406814, 0x2b);
652 gr_def(ctx, 0x406818, 0x00000f80); 652 gr_def(ctx, 0x406818, 0x00000f80);