amdgpu_probe.c revision 35d5b7c7
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		pAMDGPUEnt->fd_ref++;
256	}
257
258	xf86SetEntityInstanceForScreen(pScrn, pEnt->index,
259				       xf86GetNumEntityInstances(pEnt->
260								 index)
261				       - 1);
262	free(pEnt);
263
264	return TRUE;
265
266error_amdgpu:
267	amdgpu_kernel_close_fd(pAMDGPUEnt);
268error:
269	free(pEnt);
270	return FALSE;
271}
272
273static Bool
274amdgpu_pci_probe(DriverPtr pDriver,
275		 int entity_num, struct pci_device *device, intptr_t match_data)
276{
277	return amdgpu_get_scrninfo(entity_num, device);
278}
279
280static Bool AMDGPUDriverFunc(ScrnInfoPtr scrn, xorgDriverFuncOp op, void *data)
281{
282	xorgHWFlags *flag;
283
284	switch (op) {
285	case GET_REQUIRED_HW_INTERFACES:
286		flag = (CARD32 *) data;
287		(*flag) = 0;
288		return TRUE;
289#if XORG_VERSION_CURRENT > XORG_VERSION_NUMERIC(1,15,99,0,0)
290	case SUPPORTS_SERVER_FDS:
291		return TRUE;
292#endif
293       default:
294		return FALSE;
295	}
296}
297
298#ifdef XSERVER_PLATFORM_BUS
299static Bool
300amdgpu_platform_probe(DriverPtr pDriver,
301		      int entity_num, int flags,
302		      struct xf86_platform_device *dev, intptr_t match_data)
303{
304	ScrnInfoPtr pScrn;
305	int scr_flags = 0;
306	EntityInfoPtr pEnt = NULL;
307	DevUnion *pPriv;
308	AMDGPUEntPtr pAMDGPUEnt;
309
310	if (!dev->pdev)
311		return FALSE;
312
313	if (flags & PLATFORM_PROBE_GPU_SCREEN)
314		scr_flags = XF86_ALLOCATE_GPU_SCREEN;
315
316	pScrn = xf86AllocateScreen(pDriver, scr_flags);
317	if (xf86IsEntitySharable(entity_num))
318		xf86SetEntityShared(entity_num);
319	xf86AddEntityToScreen(pScrn, entity_num);
320
321	pScrn->driverVersion = AMDGPU_VERSION_CURRENT;
322	pScrn->driverName = AMDGPU_DRIVER_NAME;
323	pScrn->name = AMDGPU_NAME;
324	pScrn->Probe = NULL;
325	pScrn->PreInit = AMDGPUPreInit_KMS;
326	pScrn->ScreenInit = AMDGPUScreenInit_KMS;
327	pScrn->SwitchMode = AMDGPUSwitchMode_KMS;
328	pScrn->AdjustFrame = AMDGPUAdjustFrame_KMS;
329	pScrn->EnterVT = AMDGPUEnterVT_KMS;
330	pScrn->LeaveVT = AMDGPULeaveVT_KMS;
331	pScrn->FreeScreen = AMDGPUFreeScreen_KMS;
332	pScrn->ValidMode = AMDGPUValidMode;
333
334	pEnt = xf86GetEntityInfo(entity_num);
335
336	/* Create a AMDGPUEntity for all chips, even with old single head
337	 * Radeon, need to use pAMDGPUEnt for new monitor detection routines.
338	 */
339	xf86SetEntitySharable(entity_num);
340
341	if (gAMDGPUEntityIndex == -1)
342		gAMDGPUEntityIndex = xf86AllocateEntityPrivateIndex();
343
344	pPriv = xf86GetEntityPrivate(pEnt->index, gAMDGPUEntityIndex);
345
346	if (!pPriv->ptr) {
347		uint32_t major_version;
348		uint32_t minor_version;
349
350		pPriv->ptr = xnfcalloc(sizeof(AMDGPUEntRec), 1);
351		pAMDGPUEnt = pPriv->ptr;
352		pAMDGPUEnt->platform_dev = dev;
353		pAMDGPUEnt->fd = amdgpu_kernel_open_fd(pScrn, NULL, dev);
354		if (pAMDGPUEnt->fd < 0)
355			goto error;
356
357		pAMDGPUEnt->fd_ref = 1;
358
359		if (amdgpu_device_initialize(pAMDGPUEnt->fd,
360					     &major_version,
361					     &minor_version,
362					     &pAMDGPUEnt->pDev)) {
363			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
364				   "amdgpu_device_initialize failed\n");
365			goto error_amdgpu;
366		}
367	} else {
368		pAMDGPUEnt = pPriv->ptr;
369		pAMDGPUEnt->fd_ref++;
370	}
371
372	xf86SetEntityInstanceForScreen(pScrn, pEnt->index,
373				       xf86GetNumEntityInstances(pEnt->
374								 index)
375				       - 1);
376	free(pEnt);
377
378	return TRUE;
379
380error_amdgpu:
381	amdgpu_kernel_close_fd(pAMDGPUEnt);
382error:
383	free(pEnt);
384	return FALSE;
385}
386#endif
387
388static const struct pci_id_match amdgpu_device_match[] = {
389    {0x1002, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, 0},
390    {0, 0, 0},
391};
392
393DriverRec AMDGPU = {
394	AMDGPU_VERSION_CURRENT,
395	AMDGPU_DRIVER_NAME,
396	AMDGPUIdentify,
397	NULL,
398	AMDGPUAvailableOptions,
399	NULL,
400	0,
401	AMDGPUDriverFunc,
402	amdgpu_device_match,
403	amdgpu_pci_probe,
404#ifdef XSERVER_PLATFORM_BUS
405	amdgpu_platform_probe
406#endif
407};
408