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