amdgpu_probe.c revision 90f2b693
1/*
2 * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
3 *                VA Linux Systems Inc., Fremont, California.
4 *
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation on the rights to use, copy, modify, merge,
11 * publish, distribute, sublicense, and/or sell copies of the Software,
12 * and to permit persons to whom the Software is furnished to do so,
13 * subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial
17 * portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
23 * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 */
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include <errno.h>
34#include <string.h>
35#include <stdlib.h>
36
37/*
38 * Authors:
39 *   Kevin E. Martin <martin@xfree86.org>
40 *   Rickard E. Faith <faith@valinux.com>
41 * KMS support - Dave Airlie <airlied@redhat.com>
42 */
43
44#include "amdgpu_probe.h"
45#include "amdgpu_version.h"
46#include "amdgpu_drv.h"
47
48#include "xf86.h"
49
50#include "xf86drmMode.h"
51#include "dri.h"
52
53#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
54#include <xf86_OSproc.h>
55#endif
56
57#include <xf86platformBus.h>
58
59_X_EXPORT int gAMDGPUEntityIndex = -1;
60
61/* Return the options for supported chipset 'n'; NULL otherwise */
62static const OptionInfoRec *AMDGPUAvailableOptions(int chipid, int busid)
63{
64	return AMDGPUOptionsWeak();
65}
66
67static SymTabRec AMDGPUAny[] = {
68	{ 0, "All GPUs supported by the amdgpu kernel driver" },
69	{ -1, NULL }
70};
71
72/* Return the string name for supported chipset 'n'; NULL otherwise. */
73static void AMDGPUIdentify(int flags)
74{
75	xf86PrintChipsets(AMDGPU_NAME, "Driver for AMD Radeon", AMDGPUAny);
76}
77
78static char *amdgpu_bus_id(ScrnInfoPtr pScrn, struct pci_device *dev)
79{
80	char *busid;
81
82	XNFasprintf(&busid, "pci:%04x:%02x:%02x.%d",
83		    dev->domain, dev->bus, dev->dev, dev->func);
84
85	if (!busid)
86		xf86DrvMsgVerb(pScrn->scrnIndex, X_ERROR, 0,
87			       "AMDGPU: Failed to generate bus ID string\n");
88
89	return busid;
90}
91
92static Bool amdgpu_kernel_mode_enabled(ScrnInfoPtr pScrn, char *busIdString)
93{
94	int ret = drmCheckModesettingSupported(busIdString);
95
96#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
97	if (ret) {
98		if (xf86LoadKernelModule("amdgpukms"))
99			ret = drmCheckModesettingSupported(busIdString);
100	}
101#endif
102	if (ret) {
103		xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0,
104			       "[KMS] drm report modesetting isn't supported.\n");
105		return FALSE;
106	}
107
108	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0,
109		       "[KMS] Kernel modesetting enabled.\n");
110	return TRUE;
111}
112
113static int amdgpu_kernel_open_fd(ScrnInfoPtr pScrn,
114				 struct pci_device *pci_dev,
115				 struct xf86_platform_device *platform_dev)
116{
117	struct pci_device *dev;
118	char *busid;
119	int fd;
120
121#ifdef ODEV_ATTRIB_FD
122	if (platform_dev) {
123		fd = xf86_get_platform_device_int_attrib(platform_dev,
124							 ODEV_ATTRIB_FD, -1);
125		if (fd != -1)
126			return fd;
127	}
128#endif
129
130	if (platform_dev)
131		dev = platform_dev->pdev;
132	else
133		dev = pci_dev;
134
135	busid = amdgpu_bus_id(pScrn, dev);
136	if (!busid)
137		return -1;
138
139	if (!amdgpu_kernel_mode_enabled(pScrn, busid)) {
140		free(busid);
141		return -1;
142	}
143
144	fd = drmOpen(NULL, busid);
145	if (fd == -1)
146		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
147			   "[drm] Failed to open DRM device for %s: %s\n",
148			   busid, strerror(errno));
149	free(busid);
150	return fd;
151}
152
153void amdgpu_kernel_close_fd(AMDGPUEntPtr pAMDGPUEnt)
154{
155#if defined(XSERVER_PLATFORM_BUS) && defined(XF86_PDEV_SERVER_FD)
156	if (!(pAMDGPUEnt->platform_dev &&
157	      pAMDGPUEnt->platform_dev->flags & XF86_PDEV_SERVER_FD))
158#endif
159		drmClose(pAMDGPUEnt->fd);
160	pAMDGPUEnt->fd = -1;
161}
162
163static Bool amdgpu_open_drm_master(ScrnInfoPtr pScrn, AMDGPUEntPtr pAMDGPUEnt,
164				   struct pci_device *pci_dev)
165{
166	drmSetVersion sv;
167	int err;
168
169	pAMDGPUEnt->fd = amdgpu_kernel_open_fd(pScrn, pci_dev, NULL);
170	if (pAMDGPUEnt->fd == -1)
171		return FALSE;
172
173	/* Check that what we opened was a master or a master-capable FD,
174	 * by setting the version of the interface we'll use to talk to it.
175	 * (see DRIOpenDRMMaster() in DRI1)
176	 */
177	sv.drm_di_major = 1;
178	sv.drm_di_minor = 1;
179	sv.drm_dd_major = -1;
180	sv.drm_dd_minor = -1;
181	err = drmSetInterfaceVersion(pAMDGPUEnt->fd, &sv);
182	if (err != 0) {
183		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
184			   "[drm] failed to set drm interface version.\n");
185		amdgpu_kernel_close_fd(pAMDGPUEnt);
186		return FALSE;
187	}
188
189	return TRUE;
190}
191
192static Bool amdgpu_get_scrninfo(int entity_num, struct pci_device *pci_dev)
193{
194	ScrnInfoPtr pScrn = NULL;
195	EntityInfoPtr pEnt = NULL;
196	DevUnion *pPriv;
197	AMDGPUEntPtr pAMDGPUEnt;
198
199	pScrn = xf86ConfigPciEntity(pScrn, 0, entity_num, NULL,
200				    NULL, NULL, NULL, NULL, NULL);
201
202	if (!pScrn)
203		return FALSE;
204
205	pScrn->driverVersion = AMDGPU_VERSION_CURRENT;
206	pScrn->driverName = AMDGPU_DRIVER_NAME;
207	pScrn->name = AMDGPU_NAME;
208	pScrn->Probe = NULL;
209
210	pScrn->PreInit = AMDGPUPreInit_KMS;
211	pScrn->ScreenInit = AMDGPUScreenInit_KMS;
212	pScrn->SwitchMode = AMDGPUSwitchMode_KMS;
213	pScrn->AdjustFrame = AMDGPUAdjustFrame_KMS;
214	pScrn->EnterVT = AMDGPUEnterVT_KMS;
215	pScrn->LeaveVT = AMDGPULeaveVT_KMS;
216	pScrn->FreeScreen = AMDGPUFreeScreen_KMS;
217	pScrn->ValidMode = AMDGPUValidMode;
218
219	pEnt = xf86GetEntityInfo(entity_num);
220
221	/* Create a AMDGPUEntity for all chips, even with old single head
222	 * Radeon, need to use pAMDGPUEnt for new monitor detection routines.
223	 */
224	xf86SetEntitySharable(entity_num);
225
226	if (gAMDGPUEntityIndex == -1)
227		gAMDGPUEntityIndex = xf86AllocateEntityPrivateIndex();
228
229	pPriv = xf86GetEntityPrivate(pEnt->index, gAMDGPUEntityIndex);
230
231	if (!pPriv->ptr) {
232		uint32_t major_version;
233		uint32_t minor_version;
234
235		pPriv->ptr = xnfcalloc(sizeof(AMDGPUEntRec), 1);
236		if (!pPriv->ptr)
237			goto error;
238
239		pAMDGPUEnt = pPriv->ptr;
240		if (!amdgpu_open_drm_master(pScrn, pAMDGPUEnt, pci_dev))
241			goto error;
242
243		pAMDGPUEnt->fd_ref = 1;
244
245		if (amdgpu_device_initialize(pAMDGPUEnt->fd,
246					     &major_version,
247					     &minor_version,
248					     &pAMDGPUEnt->pDev)) {
249			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
250				   "amdgpu_device_initialize failed\n");
251			goto error_amdgpu;
252		}
253	} else {
254		pAMDGPUEnt = pPriv->ptr;
255
256		if (pAMDGPUEnt->fd_ref == ARRAY_SIZE(pAMDGPUEnt->scrn)) {
257			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
258				   "Only up to %u Zaphod instances supported\n",
259				   (unsigned)ARRAY_SIZE(pAMDGPUEnt->scrn));
260			goto error;
261		}
262
263		pAMDGPUEnt->fd_ref++;
264	}
265
266	xf86SetEntityInstanceForScreen(pScrn, pEnt->index,
267				       xf86GetNumEntityInstances(pEnt->
268								 index)
269				       - 1);
270	free(pEnt);
271
272	return TRUE;
273
274error_amdgpu:
275	amdgpu_kernel_close_fd(pAMDGPUEnt);
276error:
277	free(pEnt);
278	return FALSE;
279}
280
281static Bool
282amdgpu_pci_probe(DriverPtr pDriver,
283		 int entity_num, struct pci_device *device, intptr_t match_data)
284{
285	return amdgpu_get_scrninfo(entity_num, device);
286}
287
288static Bool AMDGPUDriverFunc(ScrnInfoPtr scrn, xorgDriverFuncOp op, void *data)
289{
290	xorgHWFlags *flag;
291
292	switch (op) {
293	case GET_REQUIRED_HW_INTERFACES:
294		flag = (CARD32 *) data;
295		(*flag) = 0;
296		return TRUE;
297#if XORG_VERSION_CURRENT > XORG_VERSION_NUMERIC(1,15,99,0,0)
298	case SUPPORTS_SERVER_FDS:
299		return TRUE;
300#endif
301       default:
302		return FALSE;
303	}
304}
305
306#ifdef XSERVER_PLATFORM_BUS
307static Bool
308amdgpu_platform_probe(DriverPtr pDriver,
309		      int entity_num, int flags,
310		      struct xf86_platform_device *dev, intptr_t match_data)
311{
312	ScrnInfoPtr pScrn;
313	int scr_flags = 0;
314	EntityInfoPtr pEnt = NULL;
315	DevUnion *pPriv;
316	AMDGPUEntPtr pAMDGPUEnt;
317
318	if (!dev->pdev)
319		return FALSE;
320
321	if (flags & PLATFORM_PROBE_GPU_SCREEN)
322		scr_flags = XF86_ALLOCATE_GPU_SCREEN;
323
324	pScrn = xf86AllocateScreen(pDriver, scr_flags);
325	if (xf86IsEntitySharable(entity_num))
326		xf86SetEntityShared(entity_num);
327	xf86AddEntityToScreen(pScrn, entity_num);
328
329	pScrn->driverVersion = AMDGPU_VERSION_CURRENT;
330	pScrn->driverName = AMDGPU_DRIVER_NAME;
331	pScrn->name = AMDGPU_NAME;
332	pScrn->Probe = NULL;
333	pScrn->PreInit = AMDGPUPreInit_KMS;
334	pScrn->ScreenInit = AMDGPUScreenInit_KMS;
335	pScrn->SwitchMode = AMDGPUSwitchMode_KMS;
336	pScrn->AdjustFrame = AMDGPUAdjustFrame_KMS;
337	pScrn->EnterVT = AMDGPUEnterVT_KMS;
338	pScrn->LeaveVT = AMDGPULeaveVT_KMS;
339	pScrn->FreeScreen = AMDGPUFreeScreen_KMS;
340	pScrn->ValidMode = AMDGPUValidMode;
341
342	pEnt = xf86GetEntityInfo(entity_num);
343
344	/* Create a AMDGPUEntity for all chips, even with old single head
345	 * Radeon, need to use pAMDGPUEnt for new monitor detection routines.
346	 */
347	xf86SetEntitySharable(entity_num);
348
349	if (gAMDGPUEntityIndex == -1)
350		gAMDGPUEntityIndex = xf86AllocateEntityPrivateIndex();
351
352	pPriv = xf86GetEntityPrivate(pEnt->index, gAMDGPUEntityIndex);
353
354	if (!pPriv->ptr) {
355		uint32_t major_version;
356		uint32_t minor_version;
357
358		pPriv->ptr = xnfcalloc(sizeof(AMDGPUEntRec), 1);
359		pAMDGPUEnt = pPriv->ptr;
360		pAMDGPUEnt->platform_dev = dev;
361		pAMDGPUEnt->fd = amdgpu_kernel_open_fd(pScrn, NULL, dev);
362		if (pAMDGPUEnt->fd < 0)
363			goto error;
364
365		pAMDGPUEnt->fd_ref = 1;
366
367		if (amdgpu_device_initialize(pAMDGPUEnt->fd,
368					     &major_version,
369					     &minor_version,
370					     &pAMDGPUEnt->pDev)) {
371			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
372				   "amdgpu_device_initialize failed\n");
373			goto error_amdgpu;
374		}
375	} else {
376		pAMDGPUEnt = pPriv->ptr;
377
378		if (pAMDGPUEnt->fd_ref == ARRAY_SIZE(pAMDGPUEnt->scrn)) {
379			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
380				   "Only up to %u Zaphod instances supported\n",
381				   (unsigned)ARRAY_SIZE(pAMDGPUEnt->scrn));
382			goto error;
383		}
384
385		pAMDGPUEnt->fd_ref++;
386	}
387
388	xf86SetEntityInstanceForScreen(pScrn, pEnt->index,
389				       xf86GetNumEntityInstances(pEnt->
390								 index)
391				       - 1);
392	free(pEnt);
393
394	return TRUE;
395
396error_amdgpu:
397	amdgpu_kernel_close_fd(pAMDGPUEnt);
398error:
399	free(pEnt);
400	return FALSE;
401}
402#endif
403
404static const struct pci_id_match amdgpu_device_match[] = {
405    {0x1002, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, 0},
406    {0, 0, 0},
407};
408
409DriverRec AMDGPU = {
410	AMDGPU_VERSION_CURRENT,
411	AMDGPU_DRIVER_NAME,
412	AMDGPUIdentify,
413	NULL,
414	AMDGPUAvailableOptions,
415	NULL,
416	0,
417	AMDGPUDriverFunc,
418	amdgpu_device_match,
419	amdgpu_pci_probe,
420#ifdef XSERVER_PLATFORM_BUS
421	amdgpu_platform_probe
422#endif
423};
424