// // Copyright (c) 2013-2017 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // SystemInfo_libpci.cpp: implementation of the libPCI-specific parts of SystemInfo.h #include "gpu_info_util/SystemInfo_internal.h" #include #include #include #include "common/angleutils.h" #include "common/debug.h" #if !defined(GPU_INFO_USE_LIBPCI) #error SystemInfo_libpci.cpp compiled without GPU_INFO_USE_LIBPCI #endif namespace angle { namespace { struct LibPCI : private angle::NonCopyable { LibPCI() { if (access("/sys/bus/pci/", F_OK) != 0 && access("/sys/bs/pci_express/", F_OK) != 0) { return; } mHandle = dlopen("libpci.so.3", RTLD_LAZY); if (mHandle == nullptr) { mHandle = dlopen("libpci.so", RTLD_LAZY); } if (mHandle == nullptr) { return; } mValid = (Alloc = reinterpret_cast(dlsym(mHandle, "pci_alloc"))) != nullptr && (Init = reinterpret_cast(dlsym(mHandle, "pci_init"))) != nullptr && (Cleanup = reinterpret_cast(dlsym(mHandle, "pci_cleanup"))) != nullptr && (ScanBus = reinterpret_cast(dlsym(mHandle, "pci_scan_bus"))) != nullptr && (FillInfo = reinterpret_cast(dlsym(mHandle, "pci_fill_info"))) != nullptr && (LookupName = reinterpret_cast( dlsym(mHandle, "pci_lookup_name"))) != nullptr; } bool IsValid() const { return mValid; } ~LibPCI() { if (mHandle != nullptr) { dlclose(mHandle); } } decltype(&::pci_alloc) Alloc = nullptr; decltype(&::pci_init) Init = nullptr; decltype(&::pci_cleanup) Cleanup = nullptr; decltype(&::pci_scan_bus) ScanBus = nullptr; decltype(&::pci_fill_info) FillInfo = nullptr; decltype(&::pci_lookup_name) LookupName = nullptr; private: void *mHandle = nullptr; bool mValid = false; }; } // anonymous namespace // Adds an entry per PCI GPU found and fills the device and vendor ID. bool GetPCIDevicesWithLibPCI(std::vector *devices) { LibPCI pci; if (!pci.IsValid()) { return false; } pci_access *access = pci.Alloc(); ASSERT(access != nullptr); pci.Init(access); pci.ScanBus(access); for (pci_dev *device = access->devices; device != nullptr; device = device->next) { pci.FillInfo(device, PCI_FILL_IDENT | PCI_FILL_CLASS); // Skip non-GPU devices switch (device->device_class) { case PCI_CLASS_DISPLAY_VGA: case PCI_CLASS_DISPLAY_XGA: case PCI_CLASS_DISPLAY_3D: break; default: continue; } // Skip unknown devices if (device->vendor_id == 0 || device->device_id == 0) { continue; } GPUDeviceInfo info; info.vendorId = device->vendor_id; info.deviceId = device->device_id; devices->push_back(info); } pci.Cleanup(access); return true; } }