blob: 21d9cbc62982dd8291ae3b371770e4718b2a3845 [file] [log] [blame]
//
// 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/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