xref: /aosp_15_r20/external/angle/src/gpu_info_util/SystemInfo_libpci.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2013 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::__anonbd9a802b0111::LibPCI30     LibPCI()
31     {
32         if (access("/sys/bus/pci/", F_OK) != 0 && access("/sys/bus/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             (PCIReadByte = reinterpret_cast<decltype(PCIReadByte)>(
61                  dlsym(mHandle, "pci_read_byte"))) != nullptr;
62     }
63 
IsValidangle::__anonbd9a802b0111::LibPCI64     bool IsValid() const { return mValid; }
65 
~LibPCIangle::__anonbd9a802b0111::LibPCI66     ~LibPCI()
67     {
68         if (mHandle != nullptr)
69         {
70             dlclose(mHandle);
71         }
72     }
73 
74     decltype(&::pci_alloc) Alloc            = nullptr;
75     decltype(&::pci_init) Init              = nullptr;
76     decltype(&::pci_cleanup) Cleanup        = nullptr;
77     decltype(&::pci_scan_bus) ScanBus       = nullptr;
78     decltype(&::pci_fill_info) FillInfo     = nullptr;
79     decltype(&::pci_lookup_name) LookupName = nullptr;
80     decltype(&::pci_read_byte) PCIReadByte  = nullptr;
81 
82   private:
83     void *mHandle = nullptr;
84     bool mValid   = false;
85 };
86 
87 }  // anonymous namespace
88 
89 // Adds an entry per PCI GPU found and fills the device and vendor ID.
GetPCIDevicesWithLibPCI(std::vector<GPUDeviceInfo> * devices)90 bool GetPCIDevicesWithLibPCI(std::vector<GPUDeviceInfo> *devices)
91 {
92     LibPCI pci;
93     if (!pci.IsValid())
94     {
95         return false;
96     }
97 
98     pci_access *access = pci.Alloc();
99     ASSERT(access != nullptr);
100     pci.Init(access);
101     pci.ScanBus(access);
102 
103     for (pci_dev *device = access->devices; device != nullptr; device = device->next)
104     {
105         pci.FillInfo(device, PCI_FILL_IDENT | PCI_FILL_CLASS);
106 
107         // Skip non-GPU devices
108         if (device->device_class >> 8 != PCI_BASE_CLASS_DISPLAY)
109         {
110             continue;
111         }
112 
113         // Skip unknown devices
114         if (device->vendor_id == 0 || device->device_id == 0)
115         {
116             continue;
117         }
118 
119         GPUDeviceInfo info;
120         info.vendorId   = device->vendor_id;
121         info.deviceId   = device->device_id;
122         info.revisionId = pci.PCIReadByte(device, PCI_REVISION_ID);
123 
124         devices->push_back(info);
125     }
126 
127     pci.Cleanup(access);
128 
129     return true;
130 }
131 }  // namespace angle
132