1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include "priv.h"
25
26static char *nvkm_pcie_speeds[] = {
27 "2.5GT/s",
28 "5.0GT/s",
29 "8.0GT/s",
30};
31
32static enum nvkm_pcie_speed
33nvkm_pcie_speed(enum pci_bus_speed speed)
34{
35 switch (speed) {
36 case PCIE_SPEED_2_5GT:
37 return NVKM_PCIE_SPEED_2_5;
38 case PCIE_SPEED_5_0GT:
39 return NVKM_PCIE_SPEED_5_0;
40 case PCIE_SPEED_8_0GT:
41 return NVKM_PCIE_SPEED_8_0;
42 default:
43
44 if (speed == 0x17)
45 return NVKM_PCIE_SPEED_8_0;
46 return -1;
47 }
48}
49
50static int
51nvkm_pcie_get_version(struct nvkm_pci *pci)
52{
53 if (!pci->func->pcie.version)
54 return -ENOSYS;
55
56 return pci->func->pcie.version(pci);
57}
58
59static int
60nvkm_pcie_get_max_version(struct nvkm_pci *pci)
61{
62 if (!pci->func->pcie.version_supported)
63 return -ENOSYS;
64
65 return pci->func->pcie.version_supported(pci);
66}
67
68static int
69nvkm_pcie_set_version(struct nvkm_pci *pci, int version)
70{
71 if (!pci->func->pcie.set_version)
72 return -ENOSYS;
73
74 nvkm_trace(&pci->subdev, "set to version %i\n", version);
75 pci->func->pcie.set_version(pci, version);
76 return nvkm_pcie_get_version(pci);
77}
78
79int
80nvkm_pcie_oneinit(struct nvkm_pci *pci)
81{
82 if (pci->func->pcie.max_speed)
83 nvkm_debug(&pci->subdev, "pcie max speed: %s\n",
84 nvkm_pcie_speeds[pci->func->pcie.max_speed(pci)]);
85 return 0;
86}
87
88int
89nvkm_pcie_init(struct nvkm_pci *pci)
90{
91 struct nvkm_subdev *subdev = &pci->subdev;
92 int ret;
93
94
95 ret = nvkm_pcie_get_version(pci);
96 if (ret > 0) {
97 int max_version = nvkm_pcie_get_max_version(pci);
98 if (max_version > 0 && max_version > ret)
99 ret = nvkm_pcie_set_version(pci, max_version);
100
101 if (ret < max_version)
102 nvkm_error(subdev, "couldn't raise version: %i\n", ret);
103 }
104
105 if (pci->func->pcie.init)
106 pci->func->pcie.init(pci);
107
108 if (pci->pcie.speed != -1)
109 nvkm_pcie_set_link(pci, pci->pcie.speed, pci->pcie.width);
110
111 return 0;
112}
113
114int
115nvkm_pcie_set_link(struct nvkm_pci *pci, enum nvkm_pcie_speed speed, u8 width)
116{
117 struct nvkm_subdev *subdev = &pci->subdev;
118 enum nvkm_pcie_speed cur_speed, max_speed;
119 struct pci_bus *pbus;
120 int ret;
121
122 if (!pci || !pci_is_pcie(pci->pdev))
123 return 0;
124 pbus = pci->pdev->bus;
125
126 if (!pci->func->pcie.set_link)
127 return -ENOSYS;
128
129 nvkm_trace(subdev, "requested %s\n", nvkm_pcie_speeds[speed]);
130
131 if (pci->func->pcie.version(pci) < 2) {
132 nvkm_error(subdev, "setting link failed due to low version\n");
133 return -ENODEV;
134 }
135
136 cur_speed = pci->func->pcie.cur_speed(pci);
137 max_speed = min(nvkm_pcie_speed(pbus->max_bus_speed),
138 pci->func->pcie.max_speed(pci));
139
140 nvkm_trace(subdev, "current speed: %s\n", nvkm_pcie_speeds[cur_speed]);
141
142 if (speed > max_speed) {
143 nvkm_debug(subdev, "%s not supported by bus or card, dropping"
144 "requested speed to %s", nvkm_pcie_speeds[speed],
145 nvkm_pcie_speeds[max_speed]);
146 speed = max_speed;
147 }
148
149 pci->pcie.speed = speed;
150 pci->pcie.width = width;
151
152 if (speed == cur_speed) {
153 nvkm_debug(subdev, "requested matches current speed\n");
154 return speed;
155 }
156
157 nvkm_debug(subdev, "set link to %s x%i\n",
158 nvkm_pcie_speeds[speed], width);
159
160 ret = pci->func->pcie.set_link(pci, speed, width);
161 if (ret < 0)
162 nvkm_error(subdev, "setting link failed: %i\n", ret);
163
164 return ret;
165}
166