| /* |
| * XGL 3-D graphics library |
| * |
| * Copyright (C) 2014 LunarG, Inc. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included |
| * in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| * DEALINGS IN THE SOFTWARE. |
| * |
| * Authors: |
| * Courtney Goeltzenleuchter <courtney@lunarg.com> |
| * Chia-I Wu <olv@lunarg.com> |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #include <stdio.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <assert.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <fnmatch.h> |
| |
| #include <libudev.h> |
| |
| #include "gpu.h" |
| #include "intel.h" |
| |
| static int intel_devid_override; |
| int intel_debug = -1; |
| |
| static void intel_debug_init(void) |
| { |
| const char *env; |
| |
| if (intel_debug >= 0) |
| return; |
| |
| intel_debug = 0; |
| |
| /* parse comma-separated debug options */ |
| env = getenv("INTEL_DEBUG"); |
| while (env) { |
| const char *p = strchr(env, ','); |
| size_t len; |
| |
| if (p) |
| len = p - env; |
| else |
| len = strlen(env); |
| |
| if (strncmp(env, "batch", len) == 0) { |
| intel_debug |= INTEL_DEBUG_BATCH; |
| } else if (strncmp(env, "nohw", len) == 0) { |
| intel_debug |= INTEL_DEBUG_NOHW; |
| } else if (strncmp(env, "0x", 2) == 0) { |
| intel_debug |= INTEL_DEBUG_NOHW; |
| intel_devid_override = strtol(env, NULL, 16); |
| } |
| |
| if (!p) |
| break; |
| |
| env = p + 1; |
| } |
| } |
| |
| static int is_render_node(int fd, struct stat *st) |
| { |
| if (fstat(fd, st)) |
| return 0; |
| |
| if (!S_ISCHR(st->st_mode)) |
| return 0; |
| |
| return st->st_rdev & 0x80; |
| } |
| |
| ICD_EXPORT XGL_RESULT XGLAPI xglInitAndEnumerateGpus(const XGL_APPLICATION_INFO * |
| pAppInfo, |
| const XGL_ALLOC_CALLBACKS * |
| pAllocCb, XGL_UINT maxGpus, |
| XGL_UINT * pGpuCount, |
| XGL_PHYSICAL_GPU * pGpus) |
| { |
| struct udev *udev; |
| struct udev_enumerate *e; |
| struct udev_device *device, *parent; |
| struct udev_list_entry *entry; |
| const char *pci_id, *path; |
| const char *usub, *dnode; |
| int fd; |
| struct stat st; |
| char *pci_glob = "*:*"; |
| XGL_RESULT ret; |
| XGL_UINT count = 0; |
| |
| intel_debug_init(); |
| |
| ret = icd_set_allocator(pAllocCb); |
| if (ret != XGL_SUCCESS) |
| return ret; |
| |
| /* |
| * xglInitAndEnumerateGpus() can be called multiple times. Calling it more than once |
| * forces driver reinitialization. |
| */ |
| intel_gpu_remove_all(); |
| |
| if (!maxGpus) { |
| *pGpuCount = 0; |
| return XGL_SUCCESS; |
| } |
| |
| // TODO: Do we need any other validation for incoming pointers? |
| |
| udev = udev_new(); |
| if (udev == NULL) { |
| icd_log(XGL_DBG_MSG_ERROR, XGL_VALIDATION_LEVEL_0, |
| XGL_NULL_HANDLE, 0, 0, "failed to initialize udev context"); |
| return XGL_ERROR_OUT_OF_MEMORY; |
| } |
| |
| fd = -1; |
| e = udev_enumerate_new(udev); |
| udev_enumerate_add_match_subsystem(e, "drm"); |
| udev_enumerate_scan_devices(e); |
| udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) { |
| unsigned int ven_id, dev_id; |
| struct intel_gpu *gpu; |
| |
| path = udev_list_entry_get_name(entry); |
| device = udev_device_new_from_syspath(udev, path); |
| parent = udev_device_get_parent(device); |
| usub = udev_device_get_subsystem(parent); |
| /* Filter out KMS output devices. */ |
| if (!usub || (strcmp(usub, "pci") != 0)) { |
| udev_device_unref(device); |
| continue; |
| } |
| pci_id = udev_device_get_property_value(parent, "PCI_ID"); |
| if (fnmatch(pci_glob, pci_id, 0) != 0) { |
| udev_device_unref(device); |
| continue; |
| } |
| sscanf(pci_id, "%x:%x", &ven_id, &dev_id); |
| if (ven_id != 0x8086) { |
| udev_device_unref(device); |
| continue; |
| } |
| |
| dnode = udev_device_get_devnode(device); |
| /* TODO do not open the device at this point */ |
| fd = open(dnode, O_RDWR); |
| if (fd < 0) { |
| udev_device_unref(device); |
| continue; |
| } |
| if (!is_render_node(fd, &st)) { |
| close(fd); |
| fd = -1; |
| udev_device_unref(device); |
| continue; |
| } |
| close(fd); |
| |
| if (intel_devid_override) |
| dev_id = intel_devid_override; |
| ret = intel_gpu_add(dev_id, dnode, &gpu); |
| |
| udev_device_unref(device); |
| |
| if (ret == XGL_SUCCESS) { |
| pGpus[count++] = (XGL_PHYSICAL_GPU) gpu; |
| if (count >= maxGpus) |
| break; |
| } |
| } |
| |
| udev_enumerate_unref(e); |
| udev_unref(udev); |
| |
| *pGpuCount = count; |
| |
| return (count > 0) ? XGL_SUCCESS : XGL_ERROR_UNAVAILABLE; |
| } |