amdgpu_probe.c revision 24b90cf4
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#ifdef XSERVER_PLATFORM_BUS
58#include <xf86platformBus.h>
59#endif
60
61_X_EXPORT int gAMDGPUEntityIndex = -1;
62
63/* Return the options for supported chipset 'n'; NULL otherwise */
64static const OptionInfoRec *AMDGPUAvailableOptions(int chipid, int busid)
65{
66	return AMDGPUOptionsWeak();
67}
68
69static SymTabRec AMDGPUAny[] = {
70	{ 0, "All GPUs supported by the amdgpu kernel driver" },
71	{ -1, NULL }
72};
73
74/* Return the string name for supported chipset 'n'; NULL otherwise. */
75static void AMDGPUIdentify(int flags)
76{
77	xf86PrintChipsets(AMDGPU_NAME, "Driver for AMD Radeon", AMDGPUAny);
78}
79
80static char *amdgpu_bus_id(ScrnInfoPtr pScrn, struct pci_device *dev)
81{
82	char *busid;
83
84	XNFasprintf(&busid, "pci:%04x:%02x:%02x.%d",
85		    dev->domain, dev->bus, dev->dev, dev->func);
86
87	if (!busid)
88		xf86DrvMsgVerb(pScrn->scrnIndex, X_ERROR, 0,
89			       "AMDGPU: Failed to generate bus ID string\n");
90
91	return busid;
92}
93
94static Bool amdgpu_kernel_mode_enabled(ScrnInfoPtr pScrn, char *busIdString)
95{
96	int ret = drmCheckModesettingSupported(busIdString);
97
98#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
99	if (ret) {
100		if (xf86LoadKernelModule("amdgpukms"))
101			ret = drmCheckModesettingSupported(busIdString);
102	}
103#endif
104	if (ret) {
105		xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0,
106			       "[KMS] drm report modesetting isn't supported.\n");
107		return FALSE;
108	}
109
110	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0,
111		       "[KMS] Kernel modesetting enabled.\n");
112	return TRUE;
113}
114
115static int amdgpu_kernel_open_fd(ScrnInfoPtr pScrn, char *busid,
116				 struct xf86_platform_device *platform_dev)
117{
118	int fd;
119
120#ifdef XF86_PDEV_SERVER_FD
121	if (platform_dev) {
122		fd = xf86_get_platform_device_int_attrib(platform_dev,
123							 ODEV_ATTRIB_FD, -1);
124		if (fd != -1)
125			return fd;
126	}
127#endif
128
129	fd = drmOpen(NULL, busid);
130	if (fd == -1)
131		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
132			   "[drm] Failed to open DRM device for %s: %s\n",
133			   busid, strerror(errno));
134	return fd;
135}
136
137void amdgpu_kernel_close_fd(AMDGPUEntPtr pAMDGPUEnt)
138{
139#ifdef XF86_PDEV_SERVER_FD
140	if (!(pAMDGPUEnt->platform_dev &&
141	      pAMDGPUEnt->platform_dev->flags & XF86_PDEV_SERVER_FD))
142#endif
143		drmClose(pAMDGPUEnt->fd);
144	pAMDGPUEnt->fd = -1;
145}
146
147static Bool amdgpu_open_drm_master(ScrnInfoPtr pScrn, AMDGPUEntPtr pAMDGPUEnt,
148				   char *busid)
149{
150	drmSetVersion sv;
151	int err;
152
153	pAMDGPUEnt->fd = amdgpu_kernel_open_fd(pScrn, busid, NULL);
154	if (pAMDGPUEnt->fd == -1)
155		return FALSE;
156
157	/* Check that what we opened was a master or a master-capable FD,
158	 * by setting the version of the interface we'll use to talk to it.
159	 * (see DRIOpenDRMMaster() in DRI1)
160	 */
161	sv.drm_di_major = 1;
162	sv.drm_di_minor = 1;
163	sv.drm_dd_major = -1;
164	sv.drm_dd_minor = -1;
165	err = drmSetInterfaceVersion(pAMDGPUEnt->fd, &sv);
166	if (err != 0) {
167		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
168			   "[drm] failed to set drm interface version.\n");
169		amdgpu_kernel_close_fd(pAMDGPUEnt);
170		return FALSE;
171	}
172
173	return TRUE;
174}
175
176static Bool amdgpu_get_scrninfo(int entity_num, struct pci_device *pci_dev)
177{
178	ScrnInfoPtr pScrn = NULL;
179	char *busid;
180	EntityInfoPtr pEnt = NULL;
181	DevUnion *pPriv;
182	AMDGPUEntPtr pAMDGPUEnt;
183
184	pScrn = xf86ConfigPciEntity(pScrn, 0, entity_num, NULL,
185				    NULL, NULL, NULL, NULL, NULL);
186
187	if (!pScrn)
188		return FALSE;
189
190	busid = amdgpu_bus_id(pScrn, pci_dev);
191	if (!amdgpu_kernel_mode_enabled(pScrn, busid))
192		goto error;
193
194	pScrn->driverVersion = AMDGPU_VERSION_CURRENT;
195	pScrn->driverName = AMDGPU_DRIVER_NAME;
196	pScrn->name = AMDGPU_NAME;
197	pScrn->Probe = NULL;
198
199	pScrn->PreInit = AMDGPUPreInit_KMS;
200	pScrn->ScreenInit = AMDGPUScreenInit_KMS;
201	pScrn->SwitchMode = AMDGPUSwitchMode_KMS;
202	pScrn->AdjustFrame = AMDGPUAdjustFrame_KMS;
203	pScrn->EnterVT = AMDGPUEnterVT_KMS;
204	pScrn->LeaveVT = AMDGPULeaveVT_KMS;
205	pScrn->FreeScreen = AMDGPUFreeScreen_KMS;
206	pScrn->ValidMode = AMDGPUValidMode;
207
208	pEnt = xf86GetEntityInfo(entity_num);
209
210	/* Create a AMDGPUEntity for all chips, even with old single head
211	 * Radeon, need to use pAMDGPUEnt for new monitor detection routines.
212	 */
213	xf86SetEntitySharable(entity_num);
214
215	if (gAMDGPUEntityIndex == -1)
216		gAMDGPUEntityIndex = xf86AllocateEntityPrivateIndex();
217
218	pPriv = xf86GetEntityPrivate(pEnt->index, gAMDGPUEntityIndex);
219
220	if (!pPriv->ptr) {
221		uint32_t major_version;
222		uint32_t minor_version;
223
224		pPriv->ptr = xnfcalloc(sizeof(AMDGPUEntRec), 1);
225		if (!pPriv->ptr)
226			goto error;
227
228		pAMDGPUEnt = pPriv->ptr;
229		if (!amdgpu_open_drm_master(pScrn, pAMDGPUEnt, busid))
230			goto error;
231
232		pAMDGPUEnt->fd_ref = 1;
233
234		if (amdgpu_device_initialize(pAMDGPUEnt->fd,
235					     &major_version,
236					     &minor_version,
237					     &pAMDGPUEnt->pDev)) {
238			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
239				   "amdgpu_device_initialize failed\n");
240			goto error_amdgpu;
241		}
242	} else {
243		pAMDGPUEnt = pPriv->ptr;
244		pAMDGPUEnt->fd_ref++;
245	}
246
247	xf86SetEntityInstanceForScreen(pScrn, pEnt->index,
248				       xf86GetNumEntityInstances(pEnt->
249								 index)
250				       - 1);
251	free(pEnt);
252	free(busid);
253
254	return TRUE;
255
256error_amdgpu:
257	amdgpu_kernel_close_fd(pAMDGPUEnt);
258error:
259	free(pEnt);
260	free(busid);
261	return FALSE;
262}
263
264static Bool
265amdgpu_pci_probe(DriverPtr pDriver,
266		 int entity_num, struct pci_device *device, intptr_t match_data)
267{
268	return amdgpu_get_scrninfo(entity_num, device);
269}
270
271static Bool AMDGPUDriverFunc(ScrnInfoPtr scrn, xorgDriverFuncOp op, void *data)
272{
273	xorgHWFlags *flag;
274
275	switch (op) {
276	case GET_REQUIRED_HW_INTERFACES:
277		flag = (CARD32 *) data;
278		(*flag) = 0;
279		return TRUE;
280#if XORG_VERSION_CURRENT > XORG_VERSION_NUMERIC(1,15,99,0,0)
281	case SUPPORTS_SERVER_FDS:
282		return TRUE;
283#endif
284       default:
285		return FALSE;
286	}
287}
288
289#ifdef XSERVER_PLATFORM_BUS
290static Bool
291amdgpu_platform_probe(DriverPtr pDriver,
292		      int entity_num, int flags,
293		      struct xf86_platform_device *dev, intptr_t match_data)
294{
295	ScrnInfoPtr pScrn;
296	int scr_flags = 0;
297	char *busid;
298	EntityInfoPtr pEnt = NULL;
299	DevUnion *pPriv;
300	AMDGPUEntPtr pAMDGPUEnt;
301
302	if (!dev->pdev)
303		return FALSE;
304
305	if (flags & PLATFORM_PROBE_GPU_SCREEN)
306		scr_flags = XF86_ALLOCATE_GPU_SCREEN;
307
308	pScrn = xf86AllocateScreen(pDriver, scr_flags);
309	if (xf86IsEntitySharable(entity_num))
310		xf86SetEntityShared(entity_num);
311	xf86AddEntityToScreen(pScrn, entity_num);
312
313	busid = amdgpu_bus_id(pScrn, dev->pdev);
314	if (!busid)
315		return FALSE;
316
317	if (!amdgpu_kernel_mode_enabled(pScrn, busid))
318		goto error;
319
320	pScrn->driverVersion = AMDGPU_VERSION_CURRENT;
321	pScrn->driverName = AMDGPU_DRIVER_NAME;
322	pScrn->name = AMDGPU_NAME;
323	pScrn->Probe = NULL;
324	pScrn->PreInit = AMDGPUPreInit_KMS;
325	pScrn->ScreenInit = AMDGPUScreenInit_KMS;
326	pScrn->SwitchMode = AMDGPUSwitchMode_KMS;
327	pScrn->AdjustFrame = AMDGPUAdjustFrame_KMS;
328	pScrn->EnterVT = AMDGPUEnterVT_KMS;
329	pScrn->LeaveVT = AMDGPULeaveVT_KMS;
330	pScrn->FreeScreen = AMDGPUFreeScreen_KMS;
331	pScrn->ValidMode = AMDGPUValidMode;
332
333	pEnt = xf86GetEntityInfo(entity_num);
334
335	/* Create a AMDGPUEntity for all chips, even with old single head
336	 * Radeon, need to use pAMDGPUEnt for new monitor detection routines.
337	 */
338	xf86SetEntitySharable(entity_num);
339
340	if (gAMDGPUEntityIndex == -1)
341		gAMDGPUEntityIndex = xf86AllocateEntityPrivateIndex();
342
343	pPriv = xf86GetEntityPrivate(pEnt->index, gAMDGPUEntityIndex);
344
345	if (!pPriv->ptr) {
346		uint32_t major_version;
347		uint32_t minor_version;
348
349		pPriv->ptr = xnfcalloc(sizeof(AMDGPUEntRec), 1);
350		pAMDGPUEnt = pPriv->ptr;
351		pAMDGPUEnt->platform_dev = dev;
352		pAMDGPUEnt->fd = amdgpu_kernel_open_fd(pScrn, busid, dev);
353		if (pAMDGPUEnt->fd < 0)
354			goto error;
355
356		pAMDGPUEnt->fd_ref = 1;
357
358		if (amdgpu_device_initialize(pAMDGPUEnt->fd,
359					     &major_version,
360					     &minor_version,
361					     &pAMDGPUEnt->pDev)) {
362			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
363				   "amdgpu_device_initialize failed\n");
364			goto error_amdgpu;
365		}
366	} else {
367		pAMDGPUEnt = pPriv->ptr;
368		pAMDGPUEnt->fd_ref++;
369	}
370
371	xf86SetEntityInstanceForScreen(pScrn, pEnt->index,
372				       xf86GetNumEntityInstances(pEnt->
373								 index)
374				       - 1);
375	free(pEnt);
376	free(busid);
377
378	return TRUE;
379
380error_amdgpu:
381	amdgpu_kernel_close_fd(pAMDGPUEnt);
382error:
383	free(pEnt);
384	free(busid);
385	return FALSE;
386}
387#endif
388
389static const struct pci_id_match amdgpu_device_match[] = {
390    {0x1002, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, 0},
391    {0, 0, 0},
392};
393
394_X_EXPORT DriverRec AMDGPU = {
395	AMDGPU_VERSION_CURRENT,
396	AMDGPU_DRIVER_NAME,
397	AMDGPUIdentify,
398	NULL,
399	AMDGPUAvailableOptions,
400	NULL,
401	0,
402	AMDGPUDriverFunc,
403	amdgpu_device_match,
404	amdgpu_pci_probe,
405#ifdef XSERVER_PLATFORM_BUS
406	amdgpu_platform_probe
407#endif
408};
409