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