amdgpu_pci.c revision 1.8 1 /* $NetBSD: amdgpu_pci.c,v 1.8 2021/12/19 11:53:50 riastradh Exp $ */
2
3 /*-
4 * Copyright (c) 2018 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Taylor R. Campbell.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: amdgpu_pci.c,v 1.8 2021/12/19 11:53:50 riastradh Exp $");
34
35 #include <sys/types.h>
36 #include <sys/queue.h>
37 #include <sys/systm.h>
38 #include <sys/workqueue.h>
39
40 #include <amdgpu.h>
41 #include "amdgpu_drv.h"
42 #include "amdgpu_task.h"
43
44 struct drm_device;
45
46 SIMPLEQ_HEAD(amdgpu_task_head, amdgpu_task);
47
48 struct amdgpu_softc {
49 device_t sc_dev;
50 struct pci_attach_args sc_pa;
51 enum {
52 AMDGPU_TASK_ATTACH,
53 AMDGPU_TASK_WORKQUEUE,
54 } sc_task_state;
55 union {
56 struct workqueue *workqueue;
57 struct amdgpu_task_head attach;
58 } sc_task_u;
59 struct drm_device *sc_drm_dev;
60 struct pci_dev sc_pci_dev;
61 bool sc_pci_attached;
62 bool sc_dev_registered;
63 };
64
65 static bool amdgpu_pci_lookup(const struct pci_attach_args *,
66 unsigned long *);
67
68 static int amdgpu_match(device_t, cfdata_t, void *);
69 static void amdgpu_attach(device_t, device_t, void *);
70 static void amdgpu_attach_real(device_t);
71 static int amdgpu_detach(device_t, int);
72 static bool amdgpu_do_suspend(device_t, const pmf_qual_t *);
73 static bool amdgpu_do_resume(device_t, const pmf_qual_t *);
74
75 static void amdgpu_task_work(struct work *, void *);
76
77 CFATTACH_DECL_NEW(amdgpu, sizeof(struct amdgpu_softc),
78 amdgpu_match, amdgpu_attach, amdgpu_detach, NULL);
79
80 /* XXX Kludge to get these from amdgpu_drv.c. */
81 extern struct drm_driver *const amdgpu_drm_driver;
82 extern const struct pci_device_id *const amdgpu_device_ids;
83 extern const size_t amdgpu_n_device_ids;
84
85 static bool
86 amdgpu_pci_lookup(const struct pci_attach_args *pa, unsigned long *flags)
87 {
88 size_t i;
89
90 for (i = 0; i < amdgpu_n_device_ids; i++) {
91 if ((PCI_VENDOR(pa->pa_id) == amdgpu_device_ids[i].vendor) &&
92 (PCI_PRODUCT(pa->pa_id) == amdgpu_device_ids[i].device))
93 break;
94 }
95
96 /* Did we find it? */
97 if (i == amdgpu_n_device_ids)
98 return false;
99
100 if (flags)
101 *flags = amdgpu_device_ids[i].driver_data;
102 return true;
103 }
104
105 static int
106 amdgpu_match(device_t parent, cfdata_t match, void *aux)
107 {
108 extern int amdgpu_guarantee_initialized(void);
109 const struct pci_attach_args *const pa = aux;
110 int error;
111
112 error = amdgpu_guarantee_initialized();
113 if (error) {
114 aprint_error("amdgpu: failed to initialize: %d\n", error);
115 return 0;
116 }
117
118 if (!amdgpu_pci_lookup(pa, NULL))
119 return 0;
120
121 return 7; /* beat genfb_pci and radeon */
122 }
123
124 static void
125 amdgpu_attach(device_t parent, device_t self, void *aux)
126 {
127 struct amdgpu_softc *const sc = device_private(self);
128 const struct pci_attach_args *const pa = aux;
129
130 pci_aprint_devinfo(pa, NULL);
131
132 if (!pmf_device_register(self, &amdgpu_do_suspend, &amdgpu_do_resume))
133 aprint_error_dev(self, "unable to establish power handler\n");
134
135 /*
136 * Trivial initialization first; the rest will come after we
137 * have mounted the root file system and can load firmware
138 * images.
139 */
140 sc->sc_dev = NULL;
141 sc->sc_pa = *pa;
142
143 config_mountroot(self, &amdgpu_attach_real);
144 }
145
146 static void
147 amdgpu_attach_real(device_t self)
148 {
149 struct amdgpu_softc *const sc = device_private(self);
150 const struct pci_attach_args *const pa = &sc->sc_pa;
151 bool ok __diagused;
152 unsigned long flags = 0; /* XXXGCC */
153 int error;
154
155 ok = amdgpu_pci_lookup(pa, &flags);
156 KASSERT(ok);
157
158 sc->sc_task_state = AMDGPU_TASK_ATTACH;
159 SIMPLEQ_INIT(&sc->sc_task_u.attach);
160
161 /* Initialize the Linux PCI device descriptor. */
162 linux_pci_dev_init(&sc->sc_pci_dev, self, device_parent(self), pa, 0);
163
164 sc->sc_drm_dev = drm_dev_alloc(amdgpu_drm_driver, self);
165 if (IS_ERR(sc->sc_drm_dev)) {
166 aprint_error_dev(self, "unable to create drm device: %ld\n",
167 PTR_ERR(sc->sc_drm_dev));
168 sc->sc_drm_dev = NULL;
169 goto out;
170 }
171
172 /* XXX errno Linux->NetBSD */
173 error = -drm_pci_attach(sc->sc_drm_dev, &sc->sc_pci_dev);
174 if (error) {
175 aprint_error_dev(self, "unable to attach drm: %d\n", error);
176 goto out;
177 }
178 sc->sc_pci_attached = true;
179
180 /* XXX errno Linux->NetBSD */
181 error = -drm_dev_register(sc->sc_drm_dev, flags);
182 if (error) {
183 aprint_error_dev(self, "unable to register drm: %d\n", error);
184 return;
185 }
186 sc->sc_dev_registered = true;
187
188 while (!SIMPLEQ_EMPTY(&sc->sc_task_u.attach)) {
189 struct amdgpu_task *const task =
190 SIMPLEQ_FIRST(&sc->sc_task_u.attach);
191
192 SIMPLEQ_REMOVE_HEAD(&sc->sc_task_u.attach, rt_u.queue);
193 (*task->rt_fn)(task);
194 }
195
196 sc->sc_task_state = AMDGPU_TASK_WORKQUEUE;
197 error = workqueue_create(&sc->sc_task_u.workqueue, "amdgpufb",
198 &amdgpu_task_work, NULL, PRI_NONE, IPL_NONE, WQ_MPSAFE);
199 if (error) {
200 aprint_error_dev(self, "unable to create workqueue: %d\n",
201 error);
202 sc->sc_task_u.workqueue = NULL;
203 goto out;
204 }
205
206 out: sc->sc_dev = self;
207 }
208
209 static int
210 amdgpu_detach(device_t self, int flags)
211 {
212 struct amdgpu_softc *const sc = device_private(self);
213 int error;
214
215 if (sc->sc_dev == NULL)
216 /* Not done attaching. */
217 return EBUSY;
218
219 /* XXX Check for in-use before tearing it all down... */
220 error = config_detach_children(self, flags);
221 if (error)
222 return error;
223
224 if (sc->sc_task_state == AMDGPU_TASK_ATTACH)
225 goto out;
226 if (sc->sc_task_u.workqueue != NULL) {
227 workqueue_destroy(sc->sc_task_u.workqueue);
228 sc->sc_task_u.workqueue = NULL;
229 }
230
231 if (sc->sc_drm_dev == NULL)
232 goto out0;
233 if (!sc->sc_pci_attached)
234 goto out1;
235 if (!sc->sc_dev_registered)
236 goto out2;
237
238 drm_dev_unregister(sc->sc_drm_dev);
239 out2: drm_pci_detach(sc->sc_drm_dev);
240 out1: drm_dev_put(sc->sc_drm_dev);
241 sc->sc_drm_dev = NULL;
242 out0: linux_pci_dev_destroy(&sc->sc_pci_dev);
243 pmf_device_deregister(self);
244 return 0;
245 }
246
247 static bool
248 amdgpu_do_suspend(device_t self, const pmf_qual_t *qual)
249 {
250 struct amdgpu_softc *const sc = device_private(self);
251 struct drm_device *const dev = sc->sc_drm_dev;
252 int ret;
253 bool is_console = true; /* XXX */
254
255 if (dev == NULL)
256 return true;
257
258 ret = amdgpu_suspend_kms(dev, true, is_console);
259 if (ret)
260 return false;
261
262 return true;
263 }
264
265 static bool
266 amdgpu_do_resume(device_t self, const pmf_qual_t *qual)
267 {
268 struct amdgpu_softc *const sc = device_private(self);
269 struct drm_device *const dev = sc->sc_drm_dev;
270 int ret;
271 bool is_console = true; /* XXX */
272
273 if (dev == NULL)
274 return true;
275
276 ret = amdgpu_resume_kms(dev, true, is_console);
277 if (ret)
278 return false;
279
280 return true;
281 }
282
283 static void
284 amdgpu_task_work(struct work *work, void *cookie __unused)
285 {
286 struct amdgpu_task *const task = container_of(work, struct amdgpu_task,
287 rt_u.work);
288
289 (*task->rt_fn)(task);
290 }
291
292 int
293 amdgpu_task_schedule(device_t self, struct amdgpu_task *task)
294 {
295 struct amdgpu_softc *const sc = device_private(self);
296
297 switch (sc->sc_task_state) {
298 case AMDGPU_TASK_ATTACH:
299 SIMPLEQ_INSERT_TAIL(&sc->sc_task_u.attach, task, rt_u.queue);
300 return 0;
301 case AMDGPU_TASK_WORKQUEUE:
302 if (sc->sc_task_u.workqueue == NULL) {
303 aprint_error_dev(self, "unable to schedule task\n");
304 return EIO;
305 }
306 workqueue_enqueue(sc->sc_task_u.workqueue, &task->rt_u.work,
307 NULL);
308 return 0;
309 default:
310 panic("amdgpu in invalid task state: %d\n",
311 (int)sc->sc_task_state);
312 }
313 }
314