1bcc19d9bSKarol Herbst /*
2bcc19d9bSKarol Herbst * Copyright 2015 Karol Herbst <nouveau@karolherbst.de>
3bcc19d9bSKarol Herbst *
4bcc19d9bSKarol Herbst * Permission is hereby granted, free of charge, to any person obtaining a
5bcc19d9bSKarol Herbst * copy of this software and associated documentation files (the "Software"),
6bcc19d9bSKarol Herbst * to deal in the Software without restriction, including without limitation
7bcc19d9bSKarol Herbst * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bcc19d9bSKarol Herbst * and/or sell copies of the Software, and to permit persons to whom the
9bcc19d9bSKarol Herbst * Software is furnished to do so, subject to the following conditions:
10bcc19d9bSKarol Herbst *
11bcc19d9bSKarol Herbst * The above copyright notice and this permission notice shall be included in
12bcc19d9bSKarol Herbst * all copies or substantial portions of the Software.
13bcc19d9bSKarol Herbst *
14bcc19d9bSKarol Herbst * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15bcc19d9bSKarol Herbst * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16bcc19d9bSKarol Herbst * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17bcc19d9bSKarol Herbst * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18bcc19d9bSKarol Herbst * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19bcc19d9bSKarol Herbst * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20bcc19d9bSKarol Herbst * OTHER DEALINGS IN THE SOFTWARE.
21bcc19d9bSKarol Herbst *
22bcc19d9bSKarol Herbst * Authors: Karol Herbst <git@karolherbst.de>
23bcc19d9bSKarol Herbst */
24bcc19d9bSKarol Herbst #include "priv.h"
25bcc19d9bSKarol Herbst
26bcc19d9bSKarol Herbst static char *nvkm_pcie_speeds[] = {
27bcc19d9bSKarol Herbst "2.5GT/s",
28bcc19d9bSKarol Herbst "5.0GT/s",
29bcc19d9bSKarol Herbst "8.0GT/s",
30bcc19d9bSKarol Herbst };
31bcc19d9bSKarol Herbst
32bcc19d9bSKarol Herbst static enum nvkm_pcie_speed
nvkm_pcie_speed(enum pci_bus_speed speed)33bcc19d9bSKarol Herbst nvkm_pcie_speed(enum pci_bus_speed speed)
34bcc19d9bSKarol Herbst {
35bcc19d9bSKarol Herbst switch (speed) {
36bcc19d9bSKarol Herbst case PCIE_SPEED_2_5GT:
37bcc19d9bSKarol Herbst return NVKM_PCIE_SPEED_2_5;
38bcc19d9bSKarol Herbst case PCIE_SPEED_5_0GT:
39bcc19d9bSKarol Herbst return NVKM_PCIE_SPEED_5_0;
40bcc19d9bSKarol Herbst case PCIE_SPEED_8_0GT:
41bcc19d9bSKarol Herbst return NVKM_PCIE_SPEED_8_0;
42bcc19d9bSKarol Herbst default:
43bcc19d9bSKarol Herbst /* XXX 0x16 is 8_0, assume 0x17 will be 16_0 for now */
44bcc19d9bSKarol Herbst if (speed == 0x17)
45bcc19d9bSKarol Herbst return NVKM_PCIE_SPEED_8_0;
46bcc19d9bSKarol Herbst return -1;
47bcc19d9bSKarol Herbst }
48bcc19d9bSKarol Herbst }
49bcc19d9bSKarol Herbst
50bcc19d9bSKarol Herbst static int
nvkm_pcie_get_version(struct nvkm_pci * pci)51bcc19d9bSKarol Herbst nvkm_pcie_get_version(struct nvkm_pci *pci)
52bcc19d9bSKarol Herbst {
53bcc19d9bSKarol Herbst if (!pci->func->pcie.version)
54bcc19d9bSKarol Herbst return -ENOSYS;
55bcc19d9bSKarol Herbst
56bcc19d9bSKarol Herbst return pci->func->pcie.version(pci);
57bcc19d9bSKarol Herbst }
58bcc19d9bSKarol Herbst
59bcc19d9bSKarol Herbst static int
nvkm_pcie_get_max_version(struct nvkm_pci * pci)60bcc19d9bSKarol Herbst nvkm_pcie_get_max_version(struct nvkm_pci *pci)
61bcc19d9bSKarol Herbst {
62bcc19d9bSKarol Herbst if (!pci->func->pcie.version_supported)
63bcc19d9bSKarol Herbst return -ENOSYS;
64bcc19d9bSKarol Herbst
65bcc19d9bSKarol Herbst return pci->func->pcie.version_supported(pci);
66bcc19d9bSKarol Herbst }
67bcc19d9bSKarol Herbst
68bcc19d9bSKarol Herbst static int
nvkm_pcie_set_version(struct nvkm_pci * pci,int version)69bcc19d9bSKarol Herbst nvkm_pcie_set_version(struct nvkm_pci *pci, int version)
70bcc19d9bSKarol Herbst {
71bcc19d9bSKarol Herbst if (!pci->func->pcie.set_version)
72bcc19d9bSKarol Herbst return -ENOSYS;
73bcc19d9bSKarol Herbst
74bcc19d9bSKarol Herbst nvkm_trace(&pci->subdev, "set to version %i\n", version);
75bcc19d9bSKarol Herbst pci->func->pcie.set_version(pci, version);
76bcc19d9bSKarol Herbst return nvkm_pcie_get_version(pci);
77bcc19d9bSKarol Herbst }
78bcc19d9bSKarol Herbst
79bcc19d9bSKarol Herbst int
nvkm_pcie_oneinit(struct nvkm_pci * pci)80bcc19d9bSKarol Herbst nvkm_pcie_oneinit(struct nvkm_pci *pci)
81bcc19d9bSKarol Herbst {
82bcc19d9bSKarol Herbst if (pci->func->pcie.max_speed)
83bcc19d9bSKarol Herbst nvkm_debug(&pci->subdev, "pcie max speed: %s\n",
84bcc19d9bSKarol Herbst nvkm_pcie_speeds[pci->func->pcie.max_speed(pci)]);
85bcc19d9bSKarol Herbst return 0;
86bcc19d9bSKarol Herbst }
87bcc19d9bSKarol Herbst
88bcc19d9bSKarol Herbst int
nvkm_pcie_init(struct nvkm_pci * pci)89bcc19d9bSKarol Herbst nvkm_pcie_init(struct nvkm_pci *pci)
90bcc19d9bSKarol Herbst {
91bcc19d9bSKarol Herbst struct nvkm_subdev *subdev = &pci->subdev;
92bcc19d9bSKarol Herbst int ret;
93bcc19d9bSKarol Herbst
94bcc19d9bSKarol Herbst /* raise pcie version first */
95bcc19d9bSKarol Herbst ret = nvkm_pcie_get_version(pci);
96bcc19d9bSKarol Herbst if (ret > 0) {
97bcc19d9bSKarol Herbst int max_version = nvkm_pcie_get_max_version(pci);
98bcc19d9bSKarol Herbst if (max_version > 0 && max_version > ret)
99bcc19d9bSKarol Herbst ret = nvkm_pcie_set_version(pci, max_version);
100bcc19d9bSKarol Herbst
101bcc19d9bSKarol Herbst if (ret < max_version)
102bcc19d9bSKarol Herbst nvkm_error(subdev, "couldn't raise version: %i\n", ret);
103bcc19d9bSKarol Herbst }
104bcc19d9bSKarol Herbst
105bcc19d9bSKarol Herbst if (pci->func->pcie.init)
106bcc19d9bSKarol Herbst pci->func->pcie.init(pci);
107bcc19d9bSKarol Herbst
108bcc19d9bSKarol Herbst if (pci->pcie.speed != -1)
109bcc19d9bSKarol Herbst nvkm_pcie_set_link(pci, pci->pcie.speed, pci->pcie.width);
110bcc19d9bSKarol Herbst
111bcc19d9bSKarol Herbst return 0;
112bcc19d9bSKarol Herbst }
113bcc19d9bSKarol Herbst
114bcc19d9bSKarol Herbst int
nvkm_pcie_set_link(struct nvkm_pci * pci,enum nvkm_pcie_speed speed,u8 width)115bcc19d9bSKarol Herbst nvkm_pcie_set_link(struct nvkm_pci *pci, enum nvkm_pcie_speed speed, u8 width)
116bcc19d9bSKarol Herbst {
117488c1ce6SMarkus Elfring struct nvkm_subdev *subdev;
118bcc19d9bSKarol Herbst enum nvkm_pcie_speed cur_speed, max_speed;
119bcc19d9bSKarol Herbst int ret;
120bcc19d9bSKarol Herbst
12125c80507SKarol Herbst if (!pci || !pci_is_pcie(pci->pdev))
122bcc19d9bSKarol Herbst return 0;
123bcc19d9bSKarol Herbst
124bcc19d9bSKarol Herbst if (!pci->func->pcie.set_link)
125bcc19d9bSKarol Herbst return -ENOSYS;
126bcc19d9bSKarol Herbst
127488c1ce6SMarkus Elfring subdev = &pci->subdev;
128bcc19d9bSKarol Herbst nvkm_trace(subdev, "requested %s\n", nvkm_pcie_speeds[speed]);
129bcc19d9bSKarol Herbst
130bcc19d9bSKarol Herbst if (pci->func->pcie.version(pci) < 2) {
131bcc19d9bSKarol Herbst nvkm_error(subdev, "setting link failed due to low version\n");
132bcc19d9bSKarol Herbst return -ENODEV;
133bcc19d9bSKarol Herbst }
134bcc19d9bSKarol Herbst
135bcc19d9bSKarol Herbst cur_speed = pci->func->pcie.cur_speed(pci);
136*8a89e132SMarkus Elfring max_speed = min(nvkm_pcie_speed(pci->pdev->bus->max_bus_speed),
137bcc19d9bSKarol Herbst pci->func->pcie.max_speed(pci));
138bcc19d9bSKarol Herbst
139bcc19d9bSKarol Herbst nvkm_trace(subdev, "current speed: %s\n", nvkm_pcie_speeds[cur_speed]);
140bcc19d9bSKarol Herbst
141bcc19d9bSKarol Herbst if (speed > max_speed) {
142bcc19d9bSKarol Herbst nvkm_debug(subdev, "%s not supported by bus or card, dropping"
143bcc19d9bSKarol Herbst "requested speed to %s", nvkm_pcie_speeds[speed],
144bcc19d9bSKarol Herbst nvkm_pcie_speeds[max_speed]);
145bcc19d9bSKarol Herbst speed = max_speed;
146bcc19d9bSKarol Herbst }
147bcc19d9bSKarol Herbst
148bcc19d9bSKarol Herbst pci->pcie.speed = speed;
149bcc19d9bSKarol Herbst pci->pcie.width = width;
150bcc19d9bSKarol Herbst
151bcc19d9bSKarol Herbst if (speed == cur_speed) {
152bcc19d9bSKarol Herbst nvkm_debug(subdev, "requested matches current speed\n");
153bcc19d9bSKarol Herbst return speed;
154bcc19d9bSKarol Herbst }
155bcc19d9bSKarol Herbst
156bcc19d9bSKarol Herbst nvkm_debug(subdev, "set link to %s x%i\n",
157bcc19d9bSKarol Herbst nvkm_pcie_speeds[speed], width);
158bcc19d9bSKarol Herbst
159bcc19d9bSKarol Herbst ret = pci->func->pcie.set_link(pci, speed, width);
160bcc19d9bSKarol Herbst if (ret < 0)
161bcc19d9bSKarol Herbst nvkm_error(subdev, "setting link failed: %i\n", ret);
162bcc19d9bSKarol Herbst
163bcc19d9bSKarol Herbst return ret;
164bcc19d9bSKarol Herbst }
165