amdgpu_probe.c revision 11bf0794
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; 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_fd; 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_fd: 259 free(pPriv->ptr); 260error: 261 free(busid); 262 return FALSE; 263} 264 265static Bool 266amdgpu_pci_probe(DriverPtr pDriver, 267 int entity_num, struct pci_device *device, intptr_t match_data) 268{ 269 return amdgpu_get_scrninfo(entity_num, device); 270} 271 272static Bool AMDGPUDriverFunc(ScrnInfoPtr scrn, xorgDriverFuncOp op, void *data) 273{ 274 xorgHWFlags *flag; 275 276 switch (op) { 277 case GET_REQUIRED_HW_INTERFACES: 278 flag = (CARD32 *) data; 279 (*flag) = 0; 280 return TRUE; 281#if XORG_VERSION_CURRENT > XORG_VERSION_NUMERIC(1,15,99,0,0) 282 case SUPPORTS_SERVER_FDS: 283 return TRUE; 284#endif 285 default: 286 return FALSE; 287 } 288} 289 290#ifdef XSERVER_PLATFORM_BUS 291static Bool 292amdgpu_platform_probe(DriverPtr pDriver, 293 int entity_num, int flags, 294 struct xf86_platform_device *dev, intptr_t match_data) 295{ 296 ScrnInfoPtr pScrn; 297 int scr_flags = 0; 298 char *busid; 299 EntityInfoPtr pEnt; 300 DevUnion *pPriv; 301 AMDGPUEntPtr pAMDGPUEnt; 302 303 if (!dev->pdev) 304 return FALSE; 305 306 if (flags & PLATFORM_PROBE_GPU_SCREEN) 307 scr_flags = XF86_ALLOCATE_GPU_SCREEN; 308 309 pScrn = xf86AllocateScreen(pDriver, scr_flags); 310 if (xf86IsEntitySharable(entity_num)) 311 xf86SetEntityShared(entity_num); 312 xf86AddEntityToScreen(pScrn, entity_num); 313 314 busid = amdgpu_bus_id(pScrn, dev->pdev); 315 if (!busid) 316 return FALSE; 317 318 if (!amdgpu_kernel_mode_enabled(pScrn, busid)) 319 goto error; 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, busid, dev); 354 if (pAMDGPUEnt->fd < 0) 355 goto error_fd; 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 free(busid); 378 379 return TRUE; 380 381error_amdgpu: 382 amdgpu_kernel_close_fd(pAMDGPUEnt); 383error_fd: 384 free(pPriv->ptr); 385error: 386 free(busid); 387 return FALSE; 388} 389#endif 390 391static const struct pci_id_match amdgpu_device_match[] = { 392 {0x1002, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, 0}, 393 {0, 0, 0}, 394}; 395 396_X_EXPORT DriverRec AMDGPU = { 397 AMDGPU_VERSION_CURRENT, 398 AMDGPU_DRIVER_NAME, 399 AMDGPUIdentify, 400 NULL, 401 AMDGPUAvailableOptions, 402 NULL, 403 0, 404 AMDGPUDriverFunc, 405 amdgpu_device_match, 406 amdgpu_pci_probe, 407#ifdef XSERVER_PLATFORM_BUS 408 amdgpu_platform_probe 409#endif 410}; 411