This source file includes following definitions.
- hwloc_look_pci
- hwloc_pci_component_instantiate
- hwloc_pci_component_init
1
2
3
4
5
6
7
8
9
10
11 #include <private/autogen/config.h>
12 #include <hwloc.h>
13 #include <hwloc/helper.h>
14 #include <hwloc/plugins.h>
15
16
17 #include <private/debug.h>
18 #include <private/misc.h>
19
20 #include <stdio.h>
21 #include <fcntl.h>
22 #include <string.h>
23 #include <assert.h>
24 #include <stdarg.h>
25 #ifdef HWLOC_LINUX_SYS
26 #include <dirent.h>
27 #endif
28
29 #include <pciaccess.h>
30
31 #ifndef PCI_HEADER_TYPE
32 #define PCI_HEADER_TYPE 0x0e
33 #endif
34 #ifndef PCI_HEADER_TYPE_BRIDGE
35 #define PCI_HEADER_TYPE_BRIDGE 1
36 #endif
37
38 #ifndef PCI_CLASS_DEVICE
39 #define PCI_CLASS_DEVICE 0x0a
40 #endif
41 #ifndef PCI_CLASS_BRIDGE_PCI
42 #define PCI_CLASS_BRIDGE_PCI 0x0604
43 #endif
44
45 #ifndef PCI_REVISION_ID
46 #define PCI_REVISION_ID 0x08
47 #endif
48
49 #ifndef PCI_SUBSYSTEM_VENDOR_ID
50 #define PCI_SUBSYSTEM_VENDOR_ID 0x2c
51 #endif
52 #ifndef PCI_SUBSYSTEM_ID
53 #define PCI_SUBSYSTEM_ID 0x2e
54 #endif
55
56 #ifndef PCI_PRIMARY_BUS
57 #define PCI_PRIMARY_BUS 0x18
58 #endif
59 #ifndef PCI_SECONDARY_BUS
60 #define PCI_SECONDARY_BUS 0x19
61 #endif
62 #ifndef PCI_SUBORDINATE_BUS
63 #define PCI_SUBORDINATE_BUS 0x1a
64 #endif
65
66 #ifndef PCI_CAP_ID_EXP
67 #define PCI_CAP_ID_EXP 0x10
68 #endif
69
70 #ifndef PCI_CAP_NORMAL
71 #define PCI_CAP_NORMAL 1
72 #endif
73
74 #define CONFIG_SPACE_CACHESIZE 256
75
76 #ifdef HWLOC_WIN_SYS
77 #error pciaccess locking currently not implemented on Windows
78
79 #elif defined HWLOC_HAVE_PTHREAD_MUTEX
80
81 #include <pthread.h>
82 static pthread_mutex_t hwloc_pciaccess_mutex = PTHREAD_MUTEX_INITIALIZER;
83 #define HWLOC_PCIACCESS_LOCK() pthread_mutex_lock(&hwloc_pciaccess_mutex)
84 #define HWLOC_PCIACCESS_UNLOCK() pthread_mutex_unlock(&hwloc_pciaccess_mutex)
85
86 #else
87 #error No mutex implementation available
88 #endif
89
90 static int
91 hwloc_look_pci(struct hwloc_backend *backend)
92 {
93 struct hwloc_topology *topology = backend->topology;
94 enum hwloc_type_filter_e pfilter, bfilter;
95 struct hwloc_obj *tree = NULL, *tmp;
96 int ret;
97 struct pci_device_iterator *iter;
98 struct pci_device *pcidev;
99
100 hwloc_topology_get_type_filter(topology, HWLOC_OBJ_PCI_DEVICE, &pfilter);
101 hwloc_topology_get_type_filter(topology, HWLOC_OBJ_BRIDGE, &bfilter);
102 if (bfilter == HWLOC_TYPE_FILTER_KEEP_NONE
103 && pfilter == HWLOC_TYPE_FILTER_KEEP_NONE)
104 return 0;
105
106
107
108
109 tmp = hwloc_get_root_obj(topology)->io_first_child;
110 while (tmp) {
111 if (tmp->type == HWLOC_OBJ_PCI_DEVICE
112 || (tmp->type == HWLOC_OBJ_BRIDGE && tmp->attr->bridge.downstream_type == HWLOC_OBJ_BRIDGE_PCI)) {
113 hwloc_debug("%s", "PCI objects already added, ignoring linuxpci backend.\n");
114 return 0;
115 }
116 tmp = tmp->next_sibling;
117 }
118
119 hwloc_debug("%s", "\nScanning PCI buses...\n");
120
121
122
123
124 HWLOC_PCIACCESS_LOCK();
125
126
127 ret = pci_system_init();
128 if (ret) {
129 HWLOC_PCIACCESS_UNLOCK();
130 hwloc_debug("%s", "Can not initialize libpciaccess\n");
131 return -1;
132 }
133
134 iter = pci_slot_match_iterator_create(NULL);
135
136
137 for (pcidev = pci_device_next(iter);
138 pcidev;
139 pcidev = pci_device_next(iter))
140 {
141 const char *vendorname, *devicename;
142 unsigned char config_space_cache[CONFIG_SPACE_CACHESIZE];
143 hwloc_obj_type_t type;
144 struct hwloc_obj *obj;
145 unsigned domain;
146 unsigned device_class;
147 unsigned short tmp16;
148 unsigned offset;
149
150
151 memset(config_space_cache, 0xff, CONFIG_SPACE_CACHESIZE);
152 pci_device_probe(pcidev);
153 pci_device_cfg_read(pcidev, config_space_cache, 0, CONFIG_SPACE_CACHESIZE, NULL);
154
155
156 domain = pcidev->domain;
157
158
159 device_class = pcidev->device_class >> 8;
160
161
162 type = hwloc_pcidisc_check_bridge_type(device_class, config_space_cache);
163
164
165 if (type == HWLOC_OBJ_PCI_DEVICE) {
166 enum hwloc_type_filter_e filter;
167 hwloc_topology_get_type_filter(topology, HWLOC_OBJ_PCI_DEVICE, &filter);
168 if (filter == HWLOC_TYPE_FILTER_KEEP_NONE)
169 continue;
170 if (filter == HWLOC_TYPE_FILTER_KEEP_IMPORTANT
171 && !hwloc_filter_check_pcidev_subtype_important(device_class))
172 continue;
173 } else if (type == HWLOC_OBJ_BRIDGE) {
174 enum hwloc_type_filter_e filter;
175 hwloc_topology_get_type_filter(topology, HWLOC_OBJ_BRIDGE, &filter);
176 if (filter == HWLOC_TYPE_FILTER_KEEP_NONE)
177 continue;
178
179 }
180
181
182 if (0xffff == pcidev->vendor_id && 0xffff == pcidev->device_id) {
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202 #ifdef HWLOC_LINUX_SYS
203
204 char path[64];
205 char value[16];
206 FILE *file;
207 size_t read;
208
209 snprintf(path, sizeof(path), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/vendor",
210 domain, pcidev->bus, pcidev->dev, pcidev->func);
211 file = fopen(path, "r");
212 if (file) {
213 read = fread(value, 1, sizeof(value), file);
214 fclose(file);
215 if (read)
216
217 pcidev->vendor_id = strtoul(value, NULL, 16);
218 }
219
220 snprintf(path, sizeof(path), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/device",
221 domain, pcidev->bus, pcidev->dev, pcidev->func);
222 file = fopen(path, "r");
223 if (file) {
224 read = fread(value, 1, sizeof(value), file);
225 fclose(file);
226 if (read)
227
228 pcidev->device_id = strtoul(value, NULL, 16);
229 }
230 #endif
231 }
232
233 obj = hwloc_alloc_setup_object(topology, type, HWLOC_UNKNOWN_INDEX);
234 obj->attr->pcidev.domain = domain;
235 obj->attr->pcidev.bus = pcidev->bus;
236 obj->attr->pcidev.dev = pcidev->dev;
237 obj->attr->pcidev.func = pcidev->func;
238 obj->attr->pcidev.vendor_id = pcidev->vendor_id;
239 obj->attr->pcidev.device_id = pcidev->device_id;
240 obj->attr->pcidev.class_id = device_class;
241 obj->attr->pcidev.revision = config_space_cache[PCI_REVISION_ID];
242
243 obj->attr->pcidev.linkspeed = 0;
244 offset = hwloc_pcidisc_find_cap(config_space_cache, PCI_CAP_ID_EXP);
245
246 if (offset > 0 && offset + 20 <= CONFIG_SPACE_CACHESIZE)
247 hwloc_pcidisc_find_linkspeed(config_space_cache, offset, &obj->attr->pcidev.linkspeed);
248
249 if (type == HWLOC_OBJ_BRIDGE) {
250 if (hwloc_pcidisc_setup_bridge_attr(obj, config_space_cache) < 0)
251 continue;
252 }
253
254 if (obj->type == HWLOC_OBJ_PCI_DEVICE) {
255 memcpy(&tmp16, &config_space_cache[PCI_SUBSYSTEM_VENDOR_ID], sizeof(tmp16));
256 obj->attr->pcidev.subvendor_id = tmp16;
257 memcpy(&tmp16, &config_space_cache[PCI_SUBSYSTEM_ID], sizeof(tmp16));
258 obj->attr->pcidev.subdevice_id = tmp16;
259 } else {
260
261
262
263
264 }
265
266
267 vendorname = pci_device_get_vendor_name(pcidev);
268 if (vendorname && *vendorname)
269 hwloc_obj_add_info(obj, "PCIVendor", vendorname);
270
271
272 devicename = pci_device_get_device_name(pcidev);
273 if (devicename && *devicename)
274 hwloc_obj_add_info(obj, "PCIDevice", devicename);
275
276 hwloc_debug(" %04x:%02x:%02x.%01x %04x %04x:%04x %s %s\n",
277 domain, pcidev->bus, pcidev->dev, pcidev->func,
278 device_class, pcidev->vendor_id, pcidev->device_id,
279 vendorname && *vendorname ? vendorname : "??",
280 devicename && *devicename ? devicename : "??");
281
282 hwloc_pcidisc_tree_insert_by_busid(&tree, obj);
283 }
284
285
286 pci_iterator_destroy(iter);
287 pci_system_cleanup();
288 HWLOC_PCIACCESS_UNLOCK();
289
290 hwloc_pcidisc_tree_attach(topology, tree);
291 return 0;
292 }
293
294 static struct hwloc_backend *
295 hwloc_pci_component_instantiate(struct hwloc_disc_component *component,
296 const void *_data1 __hwloc_attribute_unused,
297 const void *_data2 __hwloc_attribute_unused,
298 const void *_data3 __hwloc_attribute_unused)
299 {
300 struct hwloc_backend *backend;
301
302 #ifdef HWLOC_SOLARIS_SYS
303 if ((uid_t)0 != geteuid())
304 return NULL;
305 #endif
306
307 backend = hwloc_backend_alloc(component);
308 if (!backend)
309 return NULL;
310 backend->discover = hwloc_look_pci;
311 return backend;
312 }
313
314 static struct hwloc_disc_component hwloc_pci_disc_component = {
315 HWLOC_DISC_COMPONENT_TYPE_MISC,
316 "pci",
317 HWLOC_DISC_COMPONENT_TYPE_GLOBAL,
318 hwloc_pci_component_instantiate,
319 20,
320 1,
321 NULL
322 };
323
324 static int
325 hwloc_pci_component_init(unsigned long flags)
326 {
327 if (flags)
328 return -1;
329 if (hwloc_plugin_check_namespace("pci", "hwloc_backend_alloc") < 0)
330 return -1;
331 return 0;
332 }
333
334 #ifdef HWLOC_INSIDE_PLUGIN
335 HWLOC_DECLSPEC extern const struct hwloc_component hwloc_pci_component;
336 #endif
337
338 const struct hwloc_component hwloc_pci_component = {
339 HWLOC_COMPONENT_ABI,
340 hwloc_pci_component_init, NULL,
341 HWLOC_COMPONENT_TYPE_DISC,
342 0,
343 &hwloc_pci_disc_component
344 };