xref: /netbsd-src/sys/external/bsd/drm2/amdgpu/amdgpu_pci.c (revision daf16ae8b45b866c656f64255c7e1a59c2d98255)
1 /*	$NetBSD: amdgpu_pci.c,v 1.7 2021/12/19 11:05:12 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.7 2021/12/19 11:05:12 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, pa, &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