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