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}; 50 51static struct i915_device i915 = {}; 52 53bool drm_shim_driver_prefers_first_render_node = true; 54 55static int 56i915_ioctl_noop(int fd, unsigned long request, void *arg) 57{ 58 return 0; 59} 60 61static int 62i915_ioctl_gem_create(int fd, unsigned long request, void *arg) 63{ 64 struct shim_fd *shim_fd = drm_shim_fd_lookup(fd); 65 struct drm_i915_gem_create *create = arg; 66 struct i915_bo *bo = calloc(1, sizeof(*bo)); 67 68 drm_shim_bo_init(&bo->base, create->size); 69 70 create->handle = drm_shim_bo_get_handle(shim_fd, &bo->base); 71 72 drm_shim_bo_put(&bo->base); 73 74 return 0; 75} 76 77static int 78i915_ioctl_gem_mmap(int fd, unsigned long request, void *arg) 79{ 80 struct shim_fd *shim_fd = drm_shim_fd_lookup(fd); 81 struct drm_i915_gem_mmap *mmap_arg = arg; 82 struct shim_bo *bo = drm_shim_bo_lookup(shim_fd, mmap_arg->handle); 83 84 if (!bo) 85 return -1; 86 87 if (!bo->map) 88 bo->map = drm_shim_mmap(shim_fd, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, -1, (uintptr_t)bo); 89 90 mmap_arg->addr_ptr = (uint64_t) (bo->map + mmap_arg->offset); 91 92 return 0; 93} 94 95static int 96i915_ioctl_gem_userptr(int fd, unsigned long request, void *arg) 97{ 98 struct shim_fd *shim_fd = drm_shim_fd_lookup(fd); 99 struct drm_i915_gem_userptr *userptr = arg; 100 struct i915_bo *bo = calloc(1, sizeof(*bo)); 101 102 drm_shim_bo_init(&bo->base, userptr->user_size); 103 104 userptr->handle = drm_shim_bo_get_handle(shim_fd, &bo->base); 105 106 drm_shim_bo_put(&bo->base); 107 108 return 0; 109} 110 111static int 112i915_ioctl_gem_context_create(int fd, unsigned long request, void *arg) 113{ 114 struct drm_i915_gem_context_create *create = arg; 115 116 create->ctx_id = 1; /* Just return a fake non zero ID. */ 117 118 return 0; 119} 120 121static int 122i915_ioctl_gem_context_getparam(int fd, unsigned long request, void *arg) 123{ 124 struct drm_i915_gem_context_param *param = arg; 125 126 if (param->param == I915_CONTEXT_PARAM_GTT_SIZE) { 127 if (i915.devinfo.ver >= 8 && !i915.devinfo.is_cherryview) 128 param->value = 1ull << 48; 129 else 130 param->value = 1ull << 31; 131 } else { 132 param->value = 0; 133 } 134 135 return 0; 136} 137 138static int 139i915_ioctl_get_param(int fd, unsigned long request, void *arg) 140{ 141 drm_i915_getparam_t *gp = arg; 142 143 switch (gp->param) { 144 case I915_PARAM_CHIPSET_ID: 145 *gp->value = i915.device_id; 146 return 0; 147 case I915_PARAM_REVISION: 148 *gp->value = 0; 149 return 0; 150 case I915_PARAM_CS_TIMESTAMP_FREQUENCY: 151 *gp->value = i915.devinfo.timestamp_frequency; 152 return 0; 153 case I915_PARAM_HAS_ALIASING_PPGTT: 154 if (i915.devinfo.ver < 6) 155 *gp->value = I915_GEM_PPGTT_NONE; 156 else if (i915.devinfo.ver <= 7) 157 *gp->value = I915_GEM_PPGTT_ALIASING; 158 else 159 *gp->value = I915_GEM_PPGTT_FULL; 160 return 0; 161 162 case I915_PARAM_NUM_FENCES_AVAIL: 163 *gp->value = 8; /* gfx2/3 value, unused in brw/iris */ 164 return 0; 165 166 case I915_PARAM_HAS_BLT: 167 *gp->value = 1; /* gfx2/3 value, unused in brw/iris */ 168 return 0; 169 170 case I915_PARAM_HAS_BSD: 171 case I915_PARAM_HAS_LLC: 172 case I915_PARAM_HAS_VEBOX: 173 *gp->value = 0; /* gfx2/3 value, unused in brw/iris */ 174 return 0; 175 176 case I915_PARAM_HAS_GEM: 177 case I915_PARAM_HAS_RELAXED_DELTA: 178 case I915_PARAM_HAS_RELAXED_FENCING: 179 case I915_PARAM_HAS_WAIT_TIMEOUT: 180 case I915_PARAM_HAS_EXECBUF2: 181 case I915_PARAM_HAS_EXEC_SOFTPIN: 182 case I915_PARAM_HAS_EXEC_CAPTURE: 183 case I915_PARAM_HAS_EXEC_FENCE: 184 case I915_PARAM_HAS_EXEC_FENCE_ARRAY: 185 case I915_PARAM_HAS_CONTEXT_ISOLATION: 186 case I915_PARAM_HAS_EXEC_ASYNC: 187 case I915_PARAM_HAS_EXEC_NO_RELOC: 188 case I915_PARAM_HAS_EXEC_BATCH_FIRST: 189 *gp->value = true; 190 return 0; 191 case I915_PARAM_HAS_EXEC_TIMELINE_FENCES: 192 *gp->value = false; 193 return 0; 194 case I915_PARAM_CMD_PARSER_VERSION: 195 /* Most recent version in drivers/gpu/drm/i915/i915_cmd_parser.c */ 196 *gp->value = 10; 197 return 0; 198 case I915_PARAM_MMAP_VERSION: 199 case I915_PARAM_MMAP_GTT_VERSION: 200 *gp->value = 1; 201 return 0; 202 case I915_PARAM_SUBSLICE_TOTAL: 203 *gp->value = 0; 204 for (uint32_t s = 0; s < i915.devinfo.num_slices; s++) 205 *gp->value += i915.devinfo.num_subslices[s]; 206 return 0; 207 case I915_PARAM_EU_TOTAL: 208 *gp->value = 0; 209 for (uint32_t s = 0; s < i915.devinfo.num_slices; s++) 210 *gp->value += i915.devinfo.num_subslices[s] * i915.devinfo.num_eu_per_subslice; 211 return 0; 212 case I915_PARAM_PERF_REVISION: 213 *gp->value = 3; 214 return 0; 215 default: 216 break; 217 } 218 219 fprintf(stderr, "Unknown DRM_IOCTL_I915_GET_PARAM %d\n", gp->param); 220 return -1; 221} 222 223static int 224query_write_topology(struct drm_i915_query_item *item) 225{ 226 struct drm_i915_query_topology_info *info = 227 (void *) (uintptr_t) item->data_ptr; 228 int32_t length = 229 sizeof(*info) + 230 DIV_ROUND_UP(i915.devinfo.num_slices, 8) + 231 i915.devinfo.num_slices * DIV_ROUND_UP(i915.devinfo.num_subslices[0], 8) + 232 i915.devinfo.num_slices * i915.devinfo.num_subslices[0] * 233 DIV_ROUND_UP(i915.devinfo.num_eu_per_subslice, 8); 234 235 if (item->length == 0) { 236 item->length = length; 237 return 0; 238 } 239 240 if (item->length < length) { 241 fprintf(stderr, "size too small\n"); 242 return -EINVAL; 243 } 244 245 if (info->flags) { 246 fprintf(stderr, "invalid topology flags\n"); 247 return -EINVAL; 248 } 249 250 info->max_slices = i915.devinfo.num_slices; 251 info->max_subslices = i915.devinfo.num_subslices[0]; 252 info->max_eus_per_subslice = i915.devinfo.num_eu_per_subslice; 253 254 info->subslice_offset = DIV_ROUND_UP(i915.devinfo.num_slices, 8); 255 info->subslice_stride = DIV_ROUND_UP(i915.devinfo.num_subslices[0], 8); 256 info->eu_offset = info->subslice_offset + info->max_slices * info->subslice_stride; 257 258 uint32_t slice_mask = (1u << i915.devinfo.num_slices) - 1; 259 for (uint32_t i = 0; i < info->subslice_offset; i++) 260 info->data[i] = (slice_mask >> (8 * i)) & 0xff; 261 262 for (uint32_t s = 0; s < i915.devinfo.num_slices; s++) { 263 uint32_t subslice_mask = (1u << i915.devinfo.num_subslices[s]) - 1; 264 for (uint32_t i = 0; i < info->subslice_stride; i++) { 265 info->data[info->subslice_offset + s * info->subslice_stride + i] = 266 (subslice_mask >> (8 * i)) & 0xff; 267 } 268 } 269 270 for (uint32_t s = 0; s < i915.devinfo.num_slices; s++) { 271 for (uint32_t ss = 0; ss < i915.devinfo.num_subslices[s]; ss++) { 272 uint32_t eu_mask = (1u << info->max_eus_per_subslice) - 1; 273 for (uint32_t i = 0; i < DIV_ROUND_UP(info->max_eus_per_subslice, 8); i++) { 274 info->data[info->eu_offset + 275 (s * info->max_subslices + ss) * DIV_ROUND_UP(info->max_eus_per_subslice, 8) + i] = 276 (eu_mask >> (8 * i)) & 0xff; 277 } 278 } 279 } 280 281 return 0; 282} 283 284static int 285i915_ioctl_query(int fd, unsigned long request, void *arg) 286{ 287 struct drm_i915_query *query = arg; 288 struct drm_i915_query_item *items = (void *) (uintptr_t) query->items_ptr; 289 290 if (query->flags) { 291 fprintf(stderr, "invalid query flags\n"); 292 return -EINVAL; 293 } 294 295 for (uint32_t i = 0; i < query->num_items; i++) { 296 struct drm_i915_query_item *item = &items[i]; 297 298 switch (item->query_id) { 299 case DRM_I915_QUERY_TOPOLOGY_INFO: { 300 int ret = query_write_topology(item); 301 if (ret) 302 item->length = ret; 303 break; 304 } 305 306 default: 307 fprintf(stderr, "Unknown drm_i915_query_item id=%lli\n", item->query_id); 308 item->length = -EINVAL; 309 break; 310 } 311 } 312 313 return 0; 314} 315 316static int 317i915_gem_get_aperture(int fd, unsigned long request, void *arg) 318{ 319 struct drm_i915_gem_get_aperture *aperture = arg; 320 321 if (i915.devinfo.ver >= 8 && 322 !i915.devinfo.is_cherryview) { 323 aperture->aper_size = 1ull << 48; 324 aperture->aper_available_size = 1ull << 48; 325 } else { 326 aperture->aper_size = 1ull << 31; 327 aperture->aper_size = 1ull << 31; 328 } 329 330 return 0; 331} 332 333static ioctl_fn_t driver_ioctls[] = { 334 [DRM_I915_GETPARAM] = i915_ioctl_get_param, 335 [DRM_I915_QUERY] = i915_ioctl_query, 336 337 [DRM_I915_GET_RESET_STATS] = i915_ioctl_noop, 338 339 [DRM_I915_GEM_CREATE] = i915_ioctl_gem_create, 340 [DRM_I915_GEM_MMAP] = i915_ioctl_gem_mmap, 341 [DRM_I915_GEM_SET_TILING] = i915_ioctl_noop, 342 [DRM_I915_GEM_CONTEXT_CREATE] = i915_ioctl_gem_context_create, 343 [DRM_I915_GEM_CONTEXT_DESTROY] = i915_ioctl_noop, 344 [DRM_I915_GEM_CONTEXT_GETPARAM] = i915_ioctl_gem_context_getparam, 345 [DRM_I915_GEM_CONTEXT_SETPARAM] = i915_ioctl_noop, 346 [DRM_I915_GEM_EXECBUFFER2] = i915_ioctl_noop, 347 /* [DRM_I915_GEM_EXECBUFFER2_WR] = i915_ioctl_noop, 348 same value as DRM_I915_GEM_EXECBUFFER2. */ 349 350 [DRM_I915_GEM_USERPTR] = i915_ioctl_gem_userptr, 351 352 [DRM_I915_GEM_GET_APERTURE] = i915_gem_get_aperture, 353 354 [DRM_I915_REG_READ] = i915_ioctl_noop, 355 356 [DRM_I915_GEM_SET_DOMAIN] = i915_ioctl_noop, 357 [DRM_I915_GEM_GET_CACHING] = i915_ioctl_noop, 358 [DRM_I915_GEM_SET_CACHING] = i915_ioctl_noop, 359 [DRM_I915_GEM_GET_TILING] = i915_ioctl_noop, 360 [DRM_I915_GEM_MADVISE] = i915_ioctl_noop, 361 [DRM_I915_GEM_WAIT] = i915_ioctl_noop, 362 [DRM_I915_GEM_BUSY] = i915_ioctl_noop, 363}; 364 365void 366drm_shim_driver_init(void) 367{ 368 const char *user_platform = getenv("INTEL_STUB_GPU_PLATFORM"); 369 370 /* Use SKL if nothing is specified. */ 371 i915.device_id = intel_device_name_to_pci_device_id(user_platform ?: "skl"); 372 if (!intel_get_device_info_from_pci_id(i915.device_id, &i915.devinfo)) 373 return; 374 375 shim_device.bus_type = DRM_BUS_PCI; 376 shim_device.driver_name = "i915"; 377 shim_device.driver_ioctls = driver_ioctls; 378 shim_device.driver_ioctl_count = ARRAY_SIZE(driver_ioctls); 379 380 char uevent_content[1024]; 381 snprintf(uevent_content, sizeof(uevent_content), 382 "DRIVER=i915\n" 383 "PCI_CLASS=30000\n" 384 "PCI_ID=8086:%x\n" 385 "PCI_SUBSYS_ID=1028:075B\n" 386 "PCI_SLOT_NAME=0000:00:02.0\n" 387 "MODALIAS=pci:v00008086d00005916sv00001028sd0000075Bbc03sc00i00\n", 388 i915.device_id); 389 drm_shim_override_file(uevent_content, 390 "/sys/dev/char/%d:%d/device/uevent", 391 DRM_MAJOR, render_node_minor); 392 drm_shim_override_file("0x0\n", 393 "/sys/dev/char/%d:%d/device/revision", 394 DRM_MAJOR, render_node_minor); 395 char device_content[10]; 396 snprintf(device_content, sizeof(device_content), 397 "0x%x\n", i915.device_id); 398 drm_shim_override_file("0x8086", 399 "/sys/dev/char/%d:%d/device/vendor", 400 DRM_MAJOR, render_node_minor); 401 drm_shim_override_file("0x8086", 402 "/sys/devices/pci0000:00/0000:00:02.0/vendor"); 403 drm_shim_override_file(device_content, 404 "/sys/dev/char/%d:%d/device/device", 405 DRM_MAJOR, render_node_minor); 406 drm_shim_override_file(device_content, 407 "/sys/devices/pci0000:00/0000:00:02.0/device"); 408 drm_shim_override_file("0x1234", 409 "/sys/dev/char/%d:%d/device/subsystem_vendor", 410 DRM_MAJOR, render_node_minor); 411 drm_shim_override_file("0x1234", 412 "/sys/devices/pci0000:00/0000:00:02.0/subsystem_vendor"); 413 drm_shim_override_file("0x1234", 414 "/sys/dev/char/%d:%d/device/subsystem_device", 415 DRM_MAJOR, render_node_minor); 416 drm_shim_override_file("0x1234", 417 "/sys/devices/pci0000:00/0000:00:02.0/subsystem_device"); 418} 419