132 lines
3.5 KiB
C++
132 lines
3.5 KiB
C++
//
|
|
// Copyright 2013 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/bus/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 &&
|
|
(PCIReadByte = reinterpret_cast<decltype(PCIReadByte)>(
|
|
dlsym(mHandle, "pci_read_byte"))) != 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;
|
|
decltype(&::pci_read_byte) PCIReadByte = 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
|
|
if (device->device_class >> 8 != PCI_BASE_CLASS_DISPLAY)
|
|
{
|
|
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;
|
|
info.revisionId = pci.PCIReadByte(device, PCI_REVISION_ID);
|
|
|
|
devices->push_back(info);
|
|
}
|
|
|
|
pci.Cleanup(access);
|
|
|
|
return true;
|
|
}
|
|
} // namespace angle
|