1 //
2 // Copyright (c) 2013-2017 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // SystemInfo_libpci.cpp: implementation of the libPCI-specific parts of SystemInfo.h
8
9 #include "gpu_info_util/SystemInfo_internal.h"
10
11 #include <dlfcn.h>
12 #include <pci/pci.h>
13 #include <unistd.h>
14
15 #include "common/angleutils.h"
16 #include "common/debug.h"
17
18 #if !defined(GPU_INFO_USE_LIBPCI)
19 #error SystemInfo_libpci.cpp compiled without GPU_INFO_USE_LIBPCI
20 #endif
21
22 namespace angle
23 {
24
25 namespace
26 {
27
28 struct LibPCI : private angle::NonCopyable
29 {
LibPCIangle::__anond751c6210111::LibPCI30 LibPCI()
31 {
32 if (access("/sys/bus/pci/", F_OK) != 0 && access("/sys/bs/pci_express/", F_OK) != 0)
33 {
34 return;
35 }
36
37 mHandle = dlopen("libpci.so.3", RTLD_LAZY);
38
39 if (mHandle == nullptr)
40 {
41 mHandle = dlopen("libpci.so", RTLD_LAZY);
42 }
43
44 if (mHandle == nullptr)
45 {
46 return;
47 }
48
49 mValid =
50 (Alloc = reinterpret_cast<decltype(Alloc)>(dlsym(mHandle, "pci_alloc"))) != nullptr &&
51 (Init = reinterpret_cast<decltype(Init)>(dlsym(mHandle, "pci_init"))) != nullptr &&
52 (Cleanup = reinterpret_cast<decltype(Cleanup)>(dlsym(mHandle, "pci_cleanup"))) !=
53 nullptr &&
54 (ScanBus = reinterpret_cast<decltype(ScanBus)>(dlsym(mHandle, "pci_scan_bus"))) !=
55 nullptr &&
56 (FillInfo = reinterpret_cast<decltype(FillInfo)>(dlsym(mHandle, "pci_fill_info"))) !=
57 nullptr &&
58 (LookupName = reinterpret_cast<decltype(LookupName)>(
59 dlsym(mHandle, "pci_lookup_name"))) != nullptr;
60 }
61
IsValidangle::__anond751c6210111::LibPCI62 bool IsValid() const { return mValid; }
63
~LibPCIangle::__anond751c6210111::LibPCI64 ~LibPCI()
65 {
66 if (mHandle != nullptr)
67 {
68 dlclose(mHandle);
69 }
70 }
71
72 decltype(&::pci_alloc) Alloc = nullptr;
73 decltype(&::pci_init) Init = nullptr;
74 decltype(&::pci_cleanup) Cleanup = nullptr;
75 decltype(&::pci_scan_bus) ScanBus = nullptr;
76 decltype(&::pci_fill_info) FillInfo = nullptr;
77 decltype(&::pci_lookup_name) LookupName = nullptr;
78
79 private:
80 void *mHandle = nullptr;
81 bool mValid = false;
82 };
83
84 } // anonymous namespace
85
86 // Adds an entry per PCI GPU found and fills the device and vendor ID.
GetPCIDevicesWithLibPCI(std::vector<GPUDeviceInfo> * devices)87 bool GetPCIDevicesWithLibPCI(std::vector<GPUDeviceInfo> *devices)
88 {
89 LibPCI pci;
90 if (!pci.IsValid())
91 {
92 return false;
93 }
94
95 pci_access *access = pci.Alloc();
96 ASSERT(access != nullptr);
97 pci.Init(access);
98 pci.ScanBus(access);
99
100 for (pci_dev *device = access->devices; device != nullptr; device = device->next)
101 {
102 pci.FillInfo(device, PCI_FILL_IDENT | PCI_FILL_CLASS);
103
104 // Skip non-GPU devices
105 switch (device->device_class)
106 {
107 case PCI_CLASS_DISPLAY_VGA:
108 case PCI_CLASS_DISPLAY_XGA:
109 case PCI_CLASS_DISPLAY_3D:
110 break;
111 default:
112 continue;
113 }
114
115 // Skip unknown devices
116 if (device->vendor_id == 0 || device->device_id == 0)
117 {
118 continue;
119 }
120
121 GPUDeviceInfo info;
122 info.vendorId = device->vendor_id;
123 info.deviceId = device->device_id;
124
125 devices->push_back(info);
126 }
127
128 pci.Cleanup(access);
129
130 return true;
131 }
132 }
133