1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 44c4ae1abd00..d94ddb1c6832 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3825,6 +3825,97 @@ static int delay_250ms_after_flr(struct pci_dev *dev, int probe)
return 0;
}
+/*
+ * AMD Navi 10 series GPUs require a vendor specific reset procedure.
+ * According to AMD a PSP mode 2 reset should be enough however at this
+ * time the details of how to perform this are not available to us.
+ * Instead we can signal the SMU to enter and exit BACO which has the same
+ * desired effect.
+ */
+static int reset_amd_navi10(struct pci_dev *dev, int probe)
+{
+ const int mmMP0_SMN_C2PMSG_81 = 0x16091;
+ const int mmMP1_SMN_C2PMSG_66 = 0x16282;
+ const int mmMP1_SMN_C2PMSG_82 = 0x16292;
+ const int mmMP1_SMN_C2PMSG_90 = 0x1629a;
+
+ u16 cfg;
+ resource_size_t mmio_base, mmio_size;
+ uint32_t __iomem * mmio;
+ unsigned int sol;
+ unsigned int timeout;
+
+ /* bus resets still cause navi to flake out */
+ dev->dev_flags |= PCI_DEV_FLAGS_NO_BUS_RESET;
+
+ if (probe)
+ return 0;
+
+ /* save the PCI state and enable memory access */
+ pci_save_state(dev);
+ pci_read_config_word(dev, PCI_COMMAND, &cfg);
+ pci_write_config_word(dev, PCI_COMMAND, cfg | PCI_COMMAND_MEMORY);
+
+ /* map BAR5 */
+ mmio_base = pci_resource_start(dev, 5);
+ mmio_size = pci_resource_len(dev, 5);
+ mmio = ioremap(mmio_base, mmio_size);
+ if (mmio == NULL) {
+ pci_disable_device(dev);
+ pci_err(dev, "Navi10: cannot iomap device\n");
+ return 0;
+ }
+
+ /* check the sign of life indicator */
+ sol = readl(mmio + mmMP0_SMN_C2PMSG_81);
+ pci_info(dev, "Navi10: SOL 0x%x\n", sol);
+ if (sol == 0 || sol == 0xffffffff) {
+ pci_info(dev, "Navi10: device doesn't need to be reset\n");
+ goto out;
+ }
+
+ pci_info(dev, "Navi10: performing BACO reset\n");
+
+ /* the SMU might be busy already, wait for it */
+ for(timeout = 200; timeout && readl(mmio + mmMP1_SMN_C2PMSG_90) != 0; --timeout)
+ msleep(1);
+ readl(mmio + mmMP1_SMN_C2PMSG_90);
+
+ /* send PPSMC_MSG_ArmD3 */
+ writel(0x00, mmio + mmMP1_SMN_C2PMSG_90);
+ writel(0x46, mmio + mmMP1_SMN_C2PMSG_66);
+ for(timeout = 200; timeout && readl(mmio + mmMP1_SMN_C2PMSG_90) != 0; --timeout)
+ msleep(1);
+
+ /* send PPSMC_MSG_EnterBaco with param */
+ writel(0x00, mmio + mmMP1_SMN_C2PMSG_90);
+ writel(0x00, mmio + mmMP1_SMN_C2PMSG_82);
+ writel(0x18, mmio + mmMP1_SMN_C2PMSG_66);
+ for(timeout = 200; timeout && readl(mmio + mmMP1_SMN_C2PMSG_90) != 0; --timeout)
+ msleep(1);
+
+ /* wait for the regulators to shutdown */
+ msleep(400);
+
+ /* send PPSMC_MSG_ExitBaco */
+ writel(0x00, mmio + mmMP1_SMN_C2PMSG_90);
+ writel(0x19, mmio + mmMP1_SMN_C2PMSG_66);
+ for(timeout = 200; timeout && readl(mmio + mmMP1_SMN_C2PMSG_90) != 0; --timeout)
+ msleep(1);
+
+ /* wait for regulators to startup again */
+ msleep(400);
+
+out:
+ /* unmap BAR5 */
+ iounmap(mmio);
+
+ /* restore the PCI state and command register */
+ pci_restore_state(dev);
+ pci_write_config_word(dev, PCI_COMMAND, cfg);
+ return 0;
+}
+
static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82599_SFP_VF,
reset_intel_82599_sfp_virtfn },
@@ -3836,6 +3927,13 @@ static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
{ PCI_VENDOR_ID_INTEL, 0x0953, delay_250ms_after_flr },
{ PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID,
reset_chelsio_generic_dev },
+ { PCI_VENDOR_ID_ATI, 0x7310, reset_amd_navi10 },
+ { PCI_VENDOR_ID_ATI, 0x7312, reset_amd_navi10 },
+ { PCI_VENDOR_ID_ATI, 0x7318, reset_amd_navi10 },
+ { PCI_VENDOR_ID_ATI, 0x7319, reset_amd_navi10 },
+ { PCI_VENDOR_ID_ATI, 0x731a, reset_amd_navi10 },
+ { PCI_VENDOR_ID_ATI, 0x731b, reset_amd_navi10 },
+ { PCI_VENDOR_ID_ATI, 0x731f, reset_amd_navi10 },
{ 0 }
};
|