| // | |
| // 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 <dlfcn.h> | |
| #include <pci/pci.h> | |
| #include <unistd.h> | |
| #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<decltype(Alloc)>(dlsym(mHandle, "pci_alloc"))) != nullptr && | |
| (Init = reinterpret_cast<decltype(Init)>(dlsym(mHandle, "pci_init"))) != nullptr && | |
| (Cleanup = reinterpret_cast<decltype(Cleanup)>(dlsym(mHandle, "pci_cleanup"))) != | |
| nullptr && | |
| (ScanBus = reinterpret_cast<decltype(ScanBus)>(dlsym(mHandle, "pci_scan_bus"))) != | |
| nullptr && | |
| (FillInfo = reinterpret_cast<decltype(FillInfo)>(dlsym(mHandle, "pci_fill_info"))) != | |
| nullptr && | |
| (LookupName = reinterpret_cast<decltype(LookupName)>( | |
| 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<GPUDeviceInfo> *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; | |
| } | |
| } // namespace angle |