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#include <sys/stat.h> 37#include <fcntl.h> 38 39/* 40 * Authors: 41 * Kevin E. Martin <martin@xfree86.org> 42 * Rickard E. Faith <faith@valinux.com> 43 * KMS support - Dave Airlie <airlied@redhat.com> 44 */ 45 46#include "amdgpu_probe.h" 47#include "amdgpu_version.h" 48#include "amdgpu_drv.h" 49 50#include "xf86.h" 51 52#include "xf86drmMode.h" 53 54#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 55#include <xf86_OSproc.h> 56#endif 57 58#include <xf86platformBus.h> 59 60_X_EXPORT int gAMDGPUEntityIndex = -1; 61 62/* Return the options for supported chipset 'n'; NULL otherwise */ 63static const OptionInfoRec *AMDGPUAvailableOptions(int chipid, int busid) 64{ 65 return AMDGPUOptionsWeak(); 66} 67 68static SymTabRec AMDGPUAny[] = { 69 { 0, "All GPUs supported by the amdgpu kernel driver" }, 70 { -1, NULL } 71}; 72 73/* Return the string name for supported chipset 'n'; NULL otherwise. */ 74static void AMDGPUIdentify(int flags) 75{ 76 xf86PrintChipsets(AMDGPU_NAME, "Driver for AMD Radeon", AMDGPUAny); 77} 78 79static Bool amdgpu_device_matches(const drmDevicePtr device, 80 const struct pci_device *dev) 81{ 82 return (device->bustype == DRM_BUS_PCI && 83 device->businfo.pci->domain == dev->domain && 84 device->businfo.pci->bus == dev->bus && 85 device->businfo.pci->dev == dev->dev && 86 device->businfo.pci->func == dev->func); 87} 88 89static Bool amdgpu_kernel_mode_enabled(ScrnInfoPtr pScrn) 90{ 91#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 92 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 93 const char *busIdString = pAMDGPUEnt->busid; 94 int ret = drmCheckModesettingSupported(busIdString); 95 96 if (ret) { 97 if (xf86LoadKernelModule("amdgpukms")) 98 ret = drmCheckModesettingSupported(busIdString); 99 } 100 if (ret) { 101 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0, 102 "[KMS] drm report modesetting isn't supported.\n"); 103 return FALSE; 104 } 105 106#endif 107 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0, 108 "[KMS] Kernel modesetting enabled.\n"); 109 return TRUE; 110} 111 112static int amdgpu_kernel_open_fd(ScrnInfoPtr pScrn, 113 struct pci_device *pci_dev, 114 struct xf86_platform_device *platform_dev, 115 AMDGPUEntPtr pAMDGPUEnt) 116{ 117#define MAX_DRM_DEVICES 64 118 drmDevicePtr devices[MAX_DRM_DEVICES]; 119 struct pci_device *dev; 120 const char *path; 121 int fd = -1, i, ret; 122 123 if (platform_dev) 124 dev = platform_dev->pdev; 125 else 126 dev = pci_dev; 127 128 XNFasprintf(&pAMDGPUEnt->busid, "pci:%04x:%02x:%02x.%u", 129 dev->domain, dev->bus, dev->dev, dev->func); 130 131 if (platform_dev) { 132#ifdef ODEV_ATTRIB_FD 133 fd = xf86_get_platform_device_int_attrib(platform_dev, 134 ODEV_ATTRIB_FD, -1); 135 if (fd != -1) 136 return fd; 137#endif 138 139#ifdef ODEV_ATTRIB_PATH 140 path = xf86_get_platform_device_attrib(platform_dev, 141 ODEV_ATTRIB_PATH); 142 143 fd = open(path, O_RDWR | O_CLOEXEC); 144 if (fd != -1) 145 return fd; 146#endif 147 } 148 149 if (!amdgpu_kernel_mode_enabled(pScrn)) 150 return -1; 151 152 ret = drmGetDevices2(0, devices, ARRAY_SIZE(devices)); 153 if (ret == -1) { 154 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 155 "[drm] Failed to retrieve DRM devices information.\n"); 156 return -1; 157 } 158 for (i = 0; i < ret; i++) { 159 if (amdgpu_device_matches(devices[i], dev) && 160 devices[i]->available_nodes & (1 << DRM_NODE_PRIMARY)) { 161 path = devices[i]->nodes[DRM_NODE_PRIMARY]; 162 fd = open(path, O_RDWR | O_CLOEXEC); 163 break; 164 } 165 } 166 drmFreeDevices(devices, ret); 167 168 if (fd == -1) 169 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 170 "[drm] Failed to open DRM device for %s: %s\n", 171 pAMDGPUEnt->busid, strerror(errno)); 172 return fd; 173#undef MAX_DRM_DEVICES 174} 175 176void amdgpu_kernel_close_fd(AMDGPUEntPtr pAMDGPUEnt) 177{ 178#if defined(XSERVER_PLATFORM_BUS) && defined(XF86_PDEV_SERVER_FD) 179 if (!(pAMDGPUEnt->platform_dev && 180 pAMDGPUEnt->platform_dev->flags & XF86_PDEV_SERVER_FD)) 181#endif 182 close(pAMDGPUEnt->fd); 183 pAMDGPUEnt->fd = -1; 184} 185 186/* Pull a local version of the helper. It's available since 2.4.98 yet 187 * it may be too new for some distributions. 188 */ 189static int local_drmIsMaster(int fd) 190{ 191 return drmAuthMagic(fd, 0) != -EACCES; 192} 193 194static Bool amdgpu_open_drm_master(ScrnInfoPtr pScrn, 195 struct pci_device *pci_dev, 196 struct xf86_platform_device *platform_dev, 197 AMDGPUEntPtr pAMDGPUEnt) 198{ 199 drmSetVersion sv; 200 int err; 201 202 pAMDGPUEnt->fd = amdgpu_kernel_open_fd(pScrn, pci_dev, platform_dev, pAMDGPUEnt); 203 if (pAMDGPUEnt->fd == -1) 204 return FALSE; 205 206 /* Check that what we opened was a master or a master-capable FD, 207 * by setting the version of the interface we'll use to talk to it. 208 * (see DRIOpenDRMMaster() in DRI1) 209 */ 210 sv.drm_di_major = 1; 211 sv.drm_di_minor = 1; 212 sv.drm_dd_major = -1; 213 sv.drm_dd_minor = -1; 214 err = drmSetInterfaceVersion(pAMDGPUEnt->fd, &sv); 215 if (err != 0) { 216 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 217 "[drm] failed to set drm interface version.\n"); 218 amdgpu_kernel_close_fd(pAMDGPUEnt); 219 return FALSE; 220 } 221 222 /* Check that what we opened is a master or a master-capable FD */ 223 if (!local_drmIsMaster(pAMDGPUEnt->fd)) { 224 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 225 "[drm] device is not DRM master.\n"); 226 amdgpu_kernel_close_fd(pAMDGPUEnt); 227 return FALSE; 228 } 229 230 return TRUE; 231} 232 233static Bool amdgpu_device_setup(ScrnInfoPtr pScrn, 234 struct pci_device *pci_dev, 235 struct xf86_platform_device *platform_dev, 236 AMDGPUEntPtr pAMDGPUEnt) 237{ 238 uint32_t major_version; 239 uint32_t minor_version; 240 241 pAMDGPUEnt->platform_dev = platform_dev; 242 if (!amdgpu_open_drm_master(pScrn, pci_dev, platform_dev, 243 pAMDGPUEnt)) 244 return FALSE; 245 246 if (amdgpu_device_initialize(pAMDGPUEnt->fd, 247 &major_version, 248 &minor_version, 249 &pAMDGPUEnt->pDev)) { 250 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 251 "amdgpu_device_initialize failed\n"); 252 goto error_amdgpu; 253 } 254 255 return TRUE; 256 257error_amdgpu: 258 amdgpu_kernel_close_fd(pAMDGPUEnt); 259 return FALSE; 260} 261 262static Bool 263amdgpu_probe(ScrnInfoPtr pScrn, int entity_num, 264 struct pci_device *pci_dev, struct xf86_platform_device *dev) 265{ 266 EntityInfoPtr pEnt = NULL; 267 DevUnion *pPriv; 268 AMDGPUEntPtr pAMDGPUEnt; 269 270 if (!pScrn) 271 return FALSE; 272 273 pScrn->driverVersion = AMDGPU_VERSION_CURRENT; 274 pScrn->driverName = AMDGPU_DRIVER_NAME; 275 pScrn->name = AMDGPU_NAME; 276 pScrn->Probe = NULL; 277 pScrn->PreInit = AMDGPUPreInit_KMS; 278 pScrn->ScreenInit = AMDGPUScreenInit_KMS; 279 pScrn->SwitchMode = AMDGPUSwitchMode_KMS; 280 pScrn->AdjustFrame = AMDGPUAdjustFrame_KMS; 281 pScrn->EnterVT = AMDGPUEnterVT_KMS; 282 pScrn->LeaveVT = AMDGPULeaveVT_KMS; 283 pScrn->FreeScreen = AMDGPUFreeScreen_KMS; 284 pScrn->ValidMode = AMDGPUValidMode; 285 286 pEnt = xf86GetEntityInfo(entity_num); 287 288 /* Create a AMDGPUEntity for all chips, even with old single head 289 * Radeon, need to use pAMDGPUEnt for new monitor detection routines. 290 */ 291 xf86SetEntitySharable(entity_num); 292 293 if (gAMDGPUEntityIndex == -1) 294 gAMDGPUEntityIndex = xf86AllocateEntityPrivateIndex(); 295 296 pPriv = xf86GetEntityPrivate(pEnt->index, gAMDGPUEntityIndex); 297 298 if (!pPriv->ptr) { 299 pPriv->ptr = xnfcalloc(sizeof(AMDGPUEntRec), 1); 300 if (!pPriv->ptr) 301 goto error; 302 303 pAMDGPUEnt = pPriv->ptr; 304 if (!amdgpu_device_setup(pScrn, pci_dev, dev, pAMDGPUEnt)) 305 goto error; 306 307 pAMDGPUEnt->fd_ref = 1; 308 309 } else { 310 pAMDGPUEnt = pPriv->ptr; 311 312 if (pAMDGPUEnt->fd_ref == ARRAY_SIZE(pAMDGPUEnt->scrn)) { 313 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 314 "Only up to %u Zaphod instances supported\n", 315 (unsigned)ARRAY_SIZE(pAMDGPUEnt->scrn)); 316 goto error; 317 } 318 319 pAMDGPUEnt->fd_ref++; 320 } 321 322 xf86SetEntityInstanceForScreen(pScrn, pEnt->index, 323 xf86GetNumEntityInstances(pEnt-> 324 index) 325 - 1); 326 free(pEnt); 327 328 return TRUE; 329 330error: 331 free(pEnt); 332 return FALSE; 333} 334 335static Bool 336amdgpu_pci_probe(DriverPtr pDriver, 337 int entity_num, struct pci_device *device, intptr_t match_data) 338{ 339 ScrnInfoPtr pScrn = xf86ConfigPciEntity(NULL, 0, entity_num, NULL, 340 NULL, NULL, NULL, NULL, NULL); 341 342 return amdgpu_probe(pScrn, entity_num, device, NULL); 343} 344 345static Bool AMDGPUDriverFunc(ScrnInfoPtr scrn, xorgDriverFuncOp op, void *data) 346{ 347 xorgHWFlags *flag; 348 349 switch (op) { 350 case GET_REQUIRED_HW_INTERFACES: 351 flag = (CARD32 *) data; 352 (*flag) = 0; 353 return TRUE; 354#if XORG_VERSION_CURRENT > XORG_VERSION_NUMERIC(1,15,99,0,0) 355 case SUPPORTS_SERVER_FDS: 356 return TRUE; 357#endif 358 default: 359 return FALSE; 360 } 361} 362 363#ifdef XSERVER_PLATFORM_BUS 364static Bool 365amdgpu_platform_probe(DriverPtr pDriver, 366 int entity_num, int flags, 367 struct xf86_platform_device *dev, intptr_t match_data) 368{ 369 ScrnInfoPtr pScrn; 370 int scr_flags = 0; 371 372 if (!dev->pdev) 373 return FALSE; 374 375 if (flags & PLATFORM_PROBE_GPU_SCREEN) 376 scr_flags = XF86_ALLOCATE_GPU_SCREEN; 377 378 pScrn = xf86AllocateScreen(pDriver, scr_flags); 379 if (xf86IsEntitySharable(entity_num)) 380 xf86SetEntityShared(entity_num); 381 xf86AddEntityToScreen(pScrn, entity_num); 382 383 return amdgpu_probe(pScrn, entity_num, NULL, dev); 384} 385#endif 386 387static const struct pci_id_match amdgpu_device_match[] = { 388 {0x1002, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, 0}, 389 {0, 0, 0}, 390}; 391 392DriverRec AMDGPU = { 393 AMDGPU_VERSION_CURRENT, 394 AMDGPU_DRIVER_NAME, 395 AMDGPUIdentify, 396 NULL, 397 AMDGPUAvailableOptions, 398 NULL, 399 0, 400 AMDGPUDriverFunc, 401 amdgpu_device_match, 402 amdgpu_pci_probe, 403#ifdef XSERVER_PLATFORM_BUS 404 amdgpu_platform_probe 405#endif 406}; 407