1/* 2 * Copyright © 2020 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24#include <stdio.h> 25#include <stdlib.h> 26#include <unistd.h> 27#include <sys/ioctl.h> 28#include <sys/mman.h> 29#include <sys/types.h> 30#include <sys/socket.h> 31#include <sys/time.h> 32#include <sys/resource.h> 33#include <sys/un.h> 34 35#include "common/intel_gem.h" 36#include "dev/intel_device_info.h" 37#include "drm-uapi/i915_drm.h" 38#include "drm-shim/drm_shim.h" 39#include "util/macros.h" 40#include "util/vma.h" 41 42struct i915_device { 43 struct intel_device_info devinfo; 44 uint32_t device_id; 45}; 46 47struct i915_bo { 48 struct shim_bo base; 49 uint32_t tiling_mode; 50 uint32_t stride; 51}; 52 53static struct i915_device i915 = {}; 54 55bool drm_shim_driver_prefers_first_render_node = true; 56 57static int 58i915_ioctl_noop(int fd, unsigned long request, void *arg) 59{ 60 return 0; 61} 62 63static int 64i915_ioctl_gem_set_tiling(int fd, unsigned long request, void *arg) 65{ 66 struct shim_fd *shim_fd = drm_shim_fd_lookup(fd); 67 struct drm_i915_gem_set_tiling *tiling_arg = arg; 68 struct i915_bo *bo = (struct i915_bo *) drm_shim_bo_lookup(shim_fd, tiling_arg->handle); 69 70 if (!bo) 71 return -1; 72 73 bo->tiling_mode = tiling_arg->tiling_mode; 74 bo->stride = tiling_arg->stride; 75 76 return 0; 77} 78 79static int 80i915_ioctl_gem_get_tiling(int fd, unsigned long request, void *arg) 81{ 82 struct shim_fd *shim_fd = drm_shim_fd_lookup(fd); 83 struct drm_i915_gem_get_tiling *tiling_arg = arg; 84 struct i915_bo *bo = (struct i915_bo *) drm_shim_bo_lookup(shim_fd, tiling_arg->handle); 85 86 if (!bo) 87 return -1; 88 89 tiling_arg->tiling_mode = bo->tiling_mode; 90 tiling_arg->swizzle_mode = I915_BIT_6_SWIZZLE_NONE; 91 tiling_arg->phys_swizzle_mode = I915_BIT_6_SWIZZLE_NONE; 92 93 return 0; 94} 95 96static int 97i915_ioctl_gem_create(int fd, unsigned long request, void *arg) 98{ 99 struct shim_fd *shim_fd = drm_shim_fd_lookup(fd); 100 struct drm_i915_gem_create *create = arg; 101 struct i915_bo *bo = calloc(1, sizeof(*bo)); 102 103 drm_shim_bo_init(&bo->base, create->size); 104 105 create->handle = drm_shim_bo_get_handle(shim_fd, &bo->base); 106 107 drm_shim_bo_put(&bo->base); 108 109 return 0; 110} 111 112static int 113i915_ioctl_gem_mmap(int fd, unsigned long request, void *arg) 114{ 115 struct shim_fd *shim_fd = drm_shim_fd_lookup(fd); 116 struct drm_i915_gem_mmap *mmap_arg = arg; 117 struct shim_bo *bo = drm_shim_bo_lookup(shim_fd, mmap_arg->handle); 118 119 if (!bo) 120 return -1; 121 122 if (!bo->map) 123 bo->map = drm_shim_mmap(shim_fd, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, -1, 124 drm_shim_bo_get_mmap_offset(shim_fd, bo)); 125 126 mmap_arg->addr_ptr = (uint64_t) (bo->map + mmap_arg->offset); 127 128 return 0; 129} 130 131static int 132i915_ioctl_gem_userptr(int fd, unsigned long request, void *arg) 133{ 134 struct shim_fd *shim_fd = drm_shim_fd_lookup(fd); 135 struct drm_i915_gem_userptr *userptr = arg; 136 struct i915_bo *bo = calloc(1, sizeof(*bo)); 137 138 drm_shim_bo_init(&bo->base, userptr->user_size); 139 140 userptr->handle = drm_shim_bo_get_handle(shim_fd, &bo->base); 141 142 drm_shim_bo_put(&bo->base); 143 144 return 0; 145} 146 147static int 148i915_ioctl_gem_context_create(int fd, unsigned long request, void *arg) 149{ 150 struct drm_i915_gem_context_create *create = arg; 151 152 create->ctx_id = 1; /* Just return a fake non zero ID. */ 153 154 return 0; 155} 156 157static int 158i915_ioctl_gem_context_getparam(int fd, unsigned long request, void *arg) 159{ 160 struct drm_i915_gem_context_param *param = arg; 161 162 if (param->param == I915_CONTEXT_PARAM_GTT_SIZE) { 163 if (i915.devinfo.ver >= 8 && i915.devinfo.platform != INTEL_PLATFORM_CHV) 164 param->value = 1ull << 48; 165 else 166 param->value = 1ull << 31; 167 } else { 168 param->value = 0; 169 } 170 171 return 0; 172} 173 174static int 175i915_ioctl_get_param(int fd, unsigned long request, void *arg) 176{ 177 drm_i915_getparam_t *gp = arg; 178 179 switch (gp->param) { 180 case I915_PARAM_CHIPSET_ID: 181 *gp->value = i915.device_id; 182 return 0; 183 case I915_PARAM_REVISION: 184 *gp->value = 0; 185 return 0; 186 case I915_PARAM_CS_TIMESTAMP_FREQUENCY: 187 *gp->value = i915.devinfo.timestamp_frequency; 188 return 0; 189 case I915_PARAM_HAS_ALIASING_PPGTT: 190 if (i915.devinfo.ver < 6) 191 *gp->value = I915_GEM_PPGTT_NONE; 192 else if (i915.devinfo.ver <= 7) 193 *gp->value = I915_GEM_PPGTT_ALIASING; 194 else 195 *gp->value = I915_GEM_PPGTT_FULL; 196 return 0; 197 198 case I915_PARAM_NUM_FENCES_AVAIL: 199 *gp->value = 8; /* gfx2/3 value, unused in brw/iris */ 200 return 0; 201 202 case I915_PARAM_HAS_BLT: 203 *gp->value = 1; /* gfx2/3 value, unused in brw/iris */ 204 return 0; 205 206 case I915_PARAM_HAS_BSD: 207 case I915_PARAM_HAS_LLC: 208 case I915_PARAM_HAS_VEBOX: 209 *gp->value = 0; /* gfx2/3 value, unused in brw/iris */ 210 return 0; 211 212 case I915_PARAM_HAS_GEM: 213 case I915_PARAM_HAS_RELAXED_DELTA: 214 case I915_PARAM_HAS_RELAXED_FENCING: 215 case I915_PARAM_HAS_WAIT_TIMEOUT: 216 case I915_PARAM_HAS_EXECBUF2: 217 case I915_PARAM_HAS_EXEC_SOFTPIN: 218 case I915_PARAM_HAS_EXEC_CAPTURE: 219 case I915_PARAM_HAS_EXEC_FENCE: 220 case I915_PARAM_HAS_EXEC_FENCE_ARRAY: 221 case I915_PARAM_HAS_CONTEXT_ISOLATION: 222 case I915_PARAM_HAS_EXEC_ASYNC: 223 case I915_PARAM_HAS_EXEC_NO_RELOC: 224 case I915_PARAM_HAS_EXEC_BATCH_FIRST: 225 *gp->value = true; 226 return 0; 227 case I915_PARAM_HAS_EXEC_TIMELINE_FENCES: 228 *gp->value = false; 229 return 0; 230 case I915_PARAM_CMD_PARSER_VERSION: 231 /* Most recent version in drivers/gpu/drm/i915/i915_cmd_parser.c */ 232 *gp->value = 10; 233 return 0; 234 case I915_PARAM_MMAP_VERSION: 235 case I915_PARAM_MMAP_GTT_VERSION: 236 *gp->value = 1; 237 return 0; 238 case I915_PARAM_SUBSLICE_TOTAL: 239 *gp->value = 0; 240 for (uint32_t s = 0; s < i915.devinfo.num_slices; s++) 241 *gp->value += i915.devinfo.num_subslices[s]; 242 return 0; 243 case I915_PARAM_EU_TOTAL: 244 *gp->value = 0; 245 for (uint32_t s = 0; s < i915.devinfo.num_slices; s++) 246 *gp->value += i915.devinfo.num_subslices[s] * i915.devinfo.max_eus_per_subslice; 247 return 0; 248 case I915_PARAM_PERF_REVISION: 249 *gp->value = 3; 250 return 0; 251 case I915_PARAM_HAS_USERPTR_PROBE: 252 *gp->value = 0; 253 return 0; 254 default: 255 break; 256 } 257 258 fprintf(stderr, "Unknown DRM_IOCTL_I915_GET_PARAM %d\n", gp->param); 259 return -1; 260} 261 262static int 263query_write_topology(struct drm_i915_query_item *item) 264{ 265 struct drm_i915_query_topology_info *info = 266 (void *) (uintptr_t) item->data_ptr; 267 int32_t length = 268 sizeof(*info) + 269 DIV_ROUND_UP(i915.devinfo.num_slices, 8) + 270 i915.devinfo.num_slices * DIV_ROUND_UP(i915.devinfo.num_subslices[0], 8) + 271 i915.devinfo.num_slices * i915.devinfo.num_subslices[0] * 272 DIV_ROUND_UP(i915.devinfo.max_eus_per_subslice, 8); 273 274 if (item->length == 0) { 275 item->length = length; 276 return 0; 277 } 278 279 if (item->length < length) { 280 fprintf(stderr, "size too small\n"); 281 return -EINVAL; 282 } 283 284 if (info->flags) { 285 fprintf(stderr, "invalid topology flags\n"); 286 return -EINVAL; 287 } 288 289 info->max_slices = i915.devinfo.num_slices; 290 info->max_subslices = i915.devinfo.num_subslices[0]; 291 info->max_eus_per_subslice = i915.devinfo.max_eus_per_subslice; 292 293 info->subslice_offset = DIV_ROUND_UP(i915.devinfo.num_slices, 8); 294 info->subslice_stride = DIV_ROUND_UP(i915.devinfo.num_subslices[0], 8); 295 info->eu_offset = info->subslice_offset + info->max_slices * info->subslice_stride; 296 info->eu_stride = DIV_ROUND_UP(info->max_eus_per_subslice, 8); 297 298 uint32_t slice_mask = (1u << i915.devinfo.num_slices) - 1; 299 for (uint32_t i = 0; i < info->subslice_offset; i++) 300 info->data[i] = (slice_mask >> (8 * i)) & 0xff; 301 302 for (uint32_t s = 0; s < i915.devinfo.num_slices; s++) { 303 uint32_t subslice_mask = (1u << i915.devinfo.num_subslices[s]) - 1; 304 for (uint32_t i = 0; i < info->subslice_stride; i++) { 305 info->data[info->subslice_offset + s * info->subslice_stride + i] = 306 (subslice_mask >> (8 * i)) & 0xff; 307 } 308 } 309 310 for (uint32_t s = 0; s < i915.devinfo.num_slices; s++) { 311 for (uint32_t ss = 0; ss < i915.devinfo.num_subslices[s]; ss++) { 312 uint32_t eu_mask = (1u << info->max_eus_per_subslice) - 1; 313 for (uint32_t i = 0; i < DIV_ROUND_UP(info->max_eus_per_subslice, 8); i++) { 314 info->data[info->eu_offset + 315 (s * info->max_subslices + ss) * DIV_ROUND_UP(info->max_eus_per_subslice, 8) + i] = 316 (eu_mask >> (8 * i)) & 0xff; 317 } 318 } 319 } 320 321 return 0; 322} 323 324static int 325i915_ioctl_query(int fd, unsigned long request, void *arg) 326{ 327 struct drm_i915_query *query = arg; 328 struct drm_i915_query_item *items = (void *) (uintptr_t) query->items_ptr; 329 330 if (query->flags) { 331 fprintf(stderr, "invalid query flags\n"); 332 return -EINVAL; 333 } 334 335 for (uint32_t i = 0; i < query->num_items; i++) { 336 struct drm_i915_query_item *item = &items[i]; 337 338 switch (item->query_id) { 339 case DRM_I915_QUERY_TOPOLOGY_INFO: { 340 int ret = query_write_topology(item); 341 if (ret) 342 item->length = ret; 343 break; 344 } 345 346 case DRM_I915_QUERY_ENGINE_INFO: { 347 uint32_t num_copy = 1; 348 uint32_t num_render = 1; 349 uint32_t num_engines = num_copy + num_render; 350 351 struct drm_i915_query_engine_info *info = 352 (struct drm_i915_query_engine_info*)(uintptr_t)item->data_ptr; 353 354 int32_t data_length = 355 sizeof(*info) + 356 num_engines * sizeof(info->engines[0]); 357 358 if (item->length == 0) { 359 item->length = data_length; 360 return 0; 361 } else if (item->length < data_length) { 362 item->length = -EINVAL; 363 return -1; 364 } else { 365 memset(info, 0, data_length); 366 367 for (uint32_t e = 0; e < num_render; e++, info->num_engines++) { 368 info->engines[info->num_engines].engine.engine_class = 369 I915_ENGINE_CLASS_RENDER; 370 info->engines[info->num_engines].engine.engine_instance = e; 371 } 372 373 for (uint32_t e = 0; e < num_copy; e++, info->num_engines++) { 374 info->engines[info->num_engines].engine.engine_class = 375 I915_ENGINE_CLASS_COPY; 376 info->engines[info->num_engines].engine.engine_instance = e; 377 } 378 379 assert(info->num_engines == num_engines); 380 381 if (item->length > data_length) 382 item->length = data_length; 383 384 return 0; 385 } 386 } 387 388 case DRM_I915_QUERY_PERF_CONFIG: 389 /* This is known but not supported by the shim. Handling this here 390 * suppresses some spurious warning messages in shader-db runs. 391 */ 392 item->length = -EINVAL; 393 break; 394 395 case DRM_I915_QUERY_MEMORY_REGIONS: { 396 uint32_t num_regions = i915.devinfo.has_local_mem ? 2 : 1; 397 struct drm_i915_query_memory_regions *info = 398 (struct drm_i915_query_memory_regions*)(uintptr_t)item->data_ptr; 399 size_t data_length = sizeof(struct drm_i915_query_memory_regions) + 400 num_regions * sizeof(struct drm_i915_memory_region_info); 401 402 if (item->length == 0) { 403 item->length = data_length; 404 return 0; 405 } else if (item->length < (int32_t)data_length) { 406 item->length = -EINVAL; 407 return -1; 408 } else { 409 memset(info, 0, data_length); 410 info->num_regions = num_regions; 411 info->regions[0].region.memory_class = I915_MEMORY_CLASS_SYSTEM; 412 info->regions[0].region.memory_instance = 0; 413 /* Report 4Gb even if it's not actually true, it looks more like a 414 * real device. 415 */ 416 info->regions[0].probed_size = 4ull * 1024 * 1024 * 1024; 417 info->regions[0].unallocated_size = -1ll; 418 if (i915.devinfo.has_local_mem) { 419 info->regions[1].region.memory_class = I915_MEMORY_CLASS_DEVICE; 420 info->regions[1].region.memory_instance = 0; 421 info->regions[1].probed_size = 4ull * 1024 * 1024 * 1024; 422 info->regions[1].unallocated_size = -1ll; 423 } 424 return 0; 425 } 426 break; 427 } 428 429 default: 430 fprintf(stderr, "Unknown drm_i915_query_item id=%lli\n", item->query_id); 431 item->length = -EINVAL; 432 break; 433 } 434 } 435 436 return 0; 437} 438 439static int 440i915_gem_get_aperture(int fd, unsigned long request, void *arg) 441{ 442 struct drm_i915_gem_get_aperture *aperture = arg; 443 444 if (i915.devinfo.ver >= 8 && 445 i915.devinfo.platform != INTEL_PLATFORM_CHV) { 446 aperture->aper_size = 1ull << 48; 447 aperture->aper_available_size = 1ull << 48; 448 } else { 449 aperture->aper_size = 1ull << 31; 450 aperture->aper_size = 1ull << 31; 451 } 452 453 return 0; 454} 455 456static ioctl_fn_t driver_ioctls[] = { 457 [DRM_I915_GETPARAM] = i915_ioctl_get_param, 458 [DRM_I915_QUERY] = i915_ioctl_query, 459 460 [DRM_I915_GET_RESET_STATS] = i915_ioctl_noop, 461 462 [DRM_I915_GEM_CREATE] = i915_ioctl_gem_create, 463 [DRM_I915_GEM_MMAP] = i915_ioctl_gem_mmap, 464 [DRM_I915_GEM_SET_TILING] = i915_ioctl_gem_set_tiling, 465 [DRM_I915_GEM_CONTEXT_CREATE] = i915_ioctl_gem_context_create, 466 [DRM_I915_GEM_CONTEXT_DESTROY] = i915_ioctl_noop, 467 [DRM_I915_GEM_CONTEXT_GETPARAM] = i915_ioctl_gem_context_getparam, 468 [DRM_I915_GEM_CONTEXT_SETPARAM] = i915_ioctl_noop, 469 [DRM_I915_GEM_EXECBUFFER2] = i915_ioctl_noop, 470 /* [DRM_I915_GEM_EXECBUFFER2_WR] = i915_ioctl_noop, 471 same value as DRM_I915_GEM_EXECBUFFER2. */ 472 473 [DRM_I915_GEM_USERPTR] = i915_ioctl_gem_userptr, 474 475 [DRM_I915_GEM_GET_APERTURE] = i915_gem_get_aperture, 476 477 [DRM_I915_REG_READ] = i915_ioctl_noop, 478 479 [DRM_I915_GEM_SET_DOMAIN] = i915_ioctl_noop, 480 [DRM_I915_GEM_GET_CACHING] = i915_ioctl_noop, 481 [DRM_I915_GEM_SET_CACHING] = i915_ioctl_noop, 482 [DRM_I915_GEM_GET_TILING] = i915_ioctl_gem_get_tiling, 483 [DRM_I915_GEM_MADVISE] = i915_ioctl_noop, 484 [DRM_I915_GEM_WAIT] = i915_ioctl_noop, 485 [DRM_I915_GEM_BUSY] = i915_ioctl_noop, 486}; 487 488void 489drm_shim_driver_init(void) 490{ 491 const char *user_platform = getenv("INTEL_STUB_GPU_PLATFORM"); 492 493 /* Use SKL if nothing is specified. */ 494 i915.device_id = intel_device_name_to_pci_device_id(user_platform ?: "skl"); 495 if (!intel_get_device_info_from_pci_id(i915.device_id, &i915.devinfo)) 496 return; 497 498 shim_device.bus_type = DRM_BUS_PCI; 499 shim_device.driver_name = "i915"; 500 shim_device.driver_ioctls = driver_ioctls; 501 shim_device.driver_ioctl_count = ARRAY_SIZE(driver_ioctls); 502 503 char uevent_content[1024]; 504 snprintf(uevent_content, sizeof(uevent_content), 505 "DRIVER=i915\n" 506 "PCI_CLASS=30000\n" 507 "PCI_ID=8086:%x\n" 508 "PCI_SUBSYS_ID=1028:075B\n" 509 "PCI_SLOT_NAME=0000:00:02.0\n" 510 "MODALIAS=pci:v00008086d00005916sv00001028sd0000075Bbc03sc00i00\n", 511 i915.device_id); 512 drm_shim_override_file(uevent_content, 513 "/sys/dev/char/%d:%d/device/uevent", 514 DRM_MAJOR, render_node_minor); 515 drm_shim_override_file("0x0\n", 516 "/sys/dev/char/%d:%d/device/revision", 517 DRM_MAJOR, render_node_minor); 518 char device_content[10]; 519 snprintf(device_content, sizeof(device_content), 520 "0x%x\n", i915.device_id); 521 drm_shim_override_file("0x8086", 522 "/sys/dev/char/%d:%d/device/vendor", 523 DRM_MAJOR, render_node_minor); 524 drm_shim_override_file("0x8086", 525 "/sys/devices/pci0000:00/0000:00:02.0/vendor"); 526 drm_shim_override_file(device_content, 527 "/sys/dev/char/%d:%d/device/device", 528 DRM_MAJOR, render_node_minor); 529 drm_shim_override_file(device_content, 530 "/sys/devices/pci0000:00/0000:00:02.0/device"); 531 drm_shim_override_file("0x1234", 532 "/sys/dev/char/%d:%d/device/subsystem_vendor", 533 DRM_MAJOR, render_node_minor); 534 drm_shim_override_file("0x1234", 535 "/sys/devices/pci0000:00/0000:00:02.0/subsystem_vendor"); 536 drm_shim_override_file("0x1234", 537 "/sys/dev/char/%d:%d/device/subsystem_device", 538 DRM_MAJOR, render_node_minor); 539 drm_shim_override_file("0x1234", 540 "/sys/devices/pci0000:00/0000:00:02.0/subsystem_device"); 541} 542