This source file includes following definitions.
- hwloc_pci_forced_locality_parse_one
- hwloc_pci_forced_locality_parse
- hwloc_pci_discovery_init
- hwloc_pci_discovery_prepare
- hwloc_pci_discovery_exit
- hwloc_pci_traverse_print_cb
- hwloc_pci_traverse
- hwloc_pci_compare_busids
- hwloc_pci_add_object
- hwloc_pcidisc_tree_insert_by_busid
- hwloc_pcidisc_tree_attach
- hwloc_pci_fixup_busid_parent
- hwloc__pci_find_busid_parent
- hwloc_pcidisc_find_busid_parent
- hwloc_pci_belowroot_apply_locality
- hwloc__pci_belowroot_find_by_busid
- hwloc_pcidisc_find_by_busid
- hwloc_pcidisc_find_cap
- hwloc_pcidisc_find_linkspeed
- hwloc_pcidisc_check_bridge_type
- hwloc_pcidisc_setup_bridge_attr
- hwloc_pci_class_string
1
2
3
4
5
6 #include <private/autogen/config.h>
7 #include <hwloc.h>
8 #include <hwloc/plugins.h>
9 #include <private/private.h>
10 #include <private/debug.h>
11 #include <private/misc.h>
12
13 #include <fcntl.h>
14 #ifdef HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif
17 #include <sys/stat.h>
18
19 #ifdef HWLOC_WIN_SYS
20 #include <io.h>
21 #define open _open
22 #define read _read
23 #define close _close
24 #endif
25
26 static void
27 hwloc_pci_forced_locality_parse_one(struct hwloc_topology *topology,
28 const char *string ,
29 unsigned *allocated)
30 {
31 unsigned nr = topology->pci_forced_locality_nr;
32 unsigned domain, bus_first, bus_last, dummy;
33 hwloc_bitmap_t set;
34 char *tmp;
35
36 if (sscanf(string, "%x:%x-%x %x", &domain, &bus_first, &bus_last, &dummy) == 4) {
37
38 } else if (sscanf(string, "%x:%x %x", &domain, &bus_first, &dummy) == 3) {
39 bus_last = bus_first;
40 } else if (sscanf(string, "%x %x", &domain, &dummy) == 2) {
41 bus_first = 0;
42 bus_last = 255;
43 } else
44 return;
45
46 tmp = strchr(string, ' ');
47 if (!tmp)
48 return;
49 tmp++;
50
51 set = hwloc_bitmap_alloc();
52 hwloc_bitmap_sscanf(set, tmp);
53
54 if (!*allocated) {
55 topology->pci_forced_locality = malloc(sizeof(*topology->pci_forced_locality));
56 if (!topology->pci_forced_locality)
57 goto out_with_set;
58 *allocated = 1;
59 } else if (nr >= *allocated) {
60 struct hwloc_pci_forced_locality_s *tmplocs;
61 tmplocs = realloc(topology->pci_forced_locality,
62 2 * *allocated * sizeof(*topology->pci_forced_locality));
63 if (!tmplocs)
64 goto out_with_set;
65 topology->pci_forced_locality = tmplocs;
66 *allocated *= 2;
67 }
68
69 topology->pci_forced_locality[nr].domain = domain;
70 topology->pci_forced_locality[nr].bus_first = bus_first;
71 topology->pci_forced_locality[nr].bus_last = bus_last;
72 topology->pci_forced_locality[nr].cpuset = set;
73 topology->pci_forced_locality_nr++;
74 return;
75
76 out_with_set:
77 hwloc_bitmap_free(set);
78 return;
79 }
80
81 static void
82 hwloc_pci_forced_locality_parse(struct hwloc_topology *topology, const char *_env)
83 {
84 char *env = strdup(_env);
85 unsigned allocated = 0;
86 char *tmp = env;
87
88 while (1) {
89 size_t len = strcspn(tmp, ";\r\n");
90 char *next = NULL;
91
92 if (tmp[len] != '\0') {
93 tmp[len] = '\0';
94 if (tmp[len+1] != '\0')
95 next = &tmp[len]+1;
96 }
97
98 hwloc_pci_forced_locality_parse_one(topology, tmp, &allocated);
99
100 if (next)
101 tmp = next;
102 else
103 break;
104 }
105
106 free(env);
107 }
108
109 void
110 hwloc_pci_discovery_init(struct hwloc_topology *topology)
111 {
112 topology->need_pci_belowroot_apply_locality = 0;
113
114 topology->pci_has_forced_locality = 0;
115 topology->pci_forced_locality_nr = 0;
116 topology->pci_forced_locality = NULL;
117 }
118
119 void
120 hwloc_pci_discovery_prepare(struct hwloc_topology *topology)
121 {
122 char *env;
123
124 env = getenv("HWLOC_PCI_LOCALITY");
125 if (env) {
126 int fd;
127
128 topology->pci_has_forced_locality = 1;
129
130 fd = open(env, O_RDONLY);
131 if (fd >= 0) {
132 struct stat st;
133 char *buffer;
134 int err = fstat(fd, &st);
135 if (!err) {
136 if (st.st_size <= 64*1024) {
137 buffer = malloc(st.st_size+1);
138 if (read(fd, buffer, st.st_size) == st.st_size) {
139 buffer[st.st_size] = '\0';
140 hwloc_pci_forced_locality_parse(topology, buffer);
141 }
142 free(buffer);
143 } else {
144 fprintf(stderr, "Ignoring HWLOC_PCI_LOCALITY file `%s' too large (%lu bytes)\n",
145 env, (unsigned long) st.st_size);
146 }
147 }
148 close(fd);
149 } else
150 hwloc_pci_forced_locality_parse(topology, env);
151 }
152 }
153
154 void
155 hwloc_pci_discovery_exit(struct hwloc_topology *topology __hwloc_attribute_unused)
156 {
157 unsigned i;
158 for(i=0; i<topology->pci_forced_locality_nr; i++)
159 hwloc_bitmap_free(topology->pci_forced_locality[i].cpuset);
160 free(topology->pci_forced_locality);
161
162 hwloc_pci_discovery_init(topology);
163 }
164
165 #ifdef HWLOC_DEBUG
166 static void
167 hwloc_pci_traverse_print_cb(void * cbdata __hwloc_attribute_unused,
168 struct hwloc_obj *pcidev)
169 {
170 char busid[14];
171 hwloc_obj_t parent;
172
173
174 parent = pcidev->parent;
175 while (parent) {
176 hwloc_debug("%s", " ");
177 parent = parent->parent;
178 }
179
180 snprintf(busid, sizeof(busid), "%04x:%02x:%02x.%01x",
181 pcidev->attr->pcidev.domain, pcidev->attr->pcidev.bus, pcidev->attr->pcidev.dev, pcidev->attr->pcidev.func);
182
183 if (pcidev->type == HWLOC_OBJ_BRIDGE) {
184 if (pcidev->attr->bridge.upstream_type == HWLOC_OBJ_BRIDGE_HOST)
185 hwloc_debug("HostBridge");
186 else
187 hwloc_debug("%s Bridge [%04x:%04x]", busid,
188 pcidev->attr->pcidev.vendor_id, pcidev->attr->pcidev.device_id);
189 hwloc_debug(" to %04x:[%02x:%02x]\n",
190 pcidev->attr->bridge.downstream.pci.domain, pcidev->attr->bridge.downstream.pci.secondary_bus, pcidev->attr->bridge.downstream.pci.subordinate_bus);
191 } else
192 hwloc_debug("%s Device [%04x:%04x (%04x:%04x) rev=%02x class=%04x]\n", busid,
193 pcidev->attr->pcidev.vendor_id, pcidev->attr->pcidev.device_id,
194 pcidev->attr->pcidev.subvendor_id, pcidev->attr->pcidev.subdevice_id,
195 pcidev->attr->pcidev.revision, pcidev->attr->pcidev.class_id);
196 }
197
198 static void
199 hwloc_pci_traverse(void * cbdata, struct hwloc_obj *tree,
200 void (*cb)(void * cbdata, struct hwloc_obj *))
201 {
202 hwloc_obj_t child;
203 cb(cbdata, tree);
204 for_each_io_child(child, tree) {
205 if (child->type == HWLOC_OBJ_BRIDGE)
206 hwloc_pci_traverse(cbdata, child, cb);
207 }
208 }
209 #endif
210
211 enum hwloc_pci_busid_comparison_e {
212 HWLOC_PCI_BUSID_LOWER,
213 HWLOC_PCI_BUSID_HIGHER,
214 HWLOC_PCI_BUSID_INCLUDED,
215 HWLOC_PCI_BUSID_SUPERSET
216 };
217
218 static enum hwloc_pci_busid_comparison_e
219 hwloc_pci_compare_busids(struct hwloc_obj *a, struct hwloc_obj *b)
220 {
221 #ifdef HWLOC_DEBUG
222 if (a->type == HWLOC_OBJ_BRIDGE)
223 assert(a->attr->bridge.upstream_type == HWLOC_OBJ_BRIDGE_PCI);
224 if (b->type == HWLOC_OBJ_BRIDGE)
225 assert(b->attr->bridge.upstream_type == HWLOC_OBJ_BRIDGE_PCI);
226 #endif
227
228 if (a->attr->pcidev.domain < b->attr->pcidev.domain)
229 return HWLOC_PCI_BUSID_LOWER;
230 if (a->attr->pcidev.domain > b->attr->pcidev.domain)
231 return HWLOC_PCI_BUSID_HIGHER;
232
233 if (a->type == HWLOC_OBJ_BRIDGE
234 && b->attr->pcidev.bus >= a->attr->bridge.downstream.pci.secondary_bus
235 && b->attr->pcidev.bus <= a->attr->bridge.downstream.pci.subordinate_bus)
236 return HWLOC_PCI_BUSID_SUPERSET;
237 if (b->type == HWLOC_OBJ_BRIDGE
238 && a->attr->pcidev.bus >= b->attr->bridge.downstream.pci.secondary_bus
239 && a->attr->pcidev.bus <= b->attr->bridge.downstream.pci.subordinate_bus)
240 return HWLOC_PCI_BUSID_INCLUDED;
241
242 if (a->attr->pcidev.bus < b->attr->pcidev.bus)
243 return HWLOC_PCI_BUSID_LOWER;
244 if (a->attr->pcidev.bus > b->attr->pcidev.bus)
245 return HWLOC_PCI_BUSID_HIGHER;
246
247 if (a->attr->pcidev.dev < b->attr->pcidev.dev)
248 return HWLOC_PCI_BUSID_LOWER;
249 if (a->attr->pcidev.dev > b->attr->pcidev.dev)
250 return HWLOC_PCI_BUSID_HIGHER;
251
252 if (a->attr->pcidev.func < b->attr->pcidev.func)
253 return HWLOC_PCI_BUSID_LOWER;
254 if (a->attr->pcidev.func > b->attr->pcidev.func)
255 return HWLOC_PCI_BUSID_HIGHER;
256
257
258
259 assert(0);
260 fprintf(stderr, "Bad assertion in hwloc %s:%d (aborting)\n", __FILE__, __LINE__);
261 exit(1);
262 }
263
264 static void
265 hwloc_pci_add_object(struct hwloc_obj *parent, struct hwloc_obj **parent_io_first_child_p, struct hwloc_obj *new)
266 {
267 struct hwloc_obj **curp, **childp;
268
269 curp = parent_io_first_child_p;
270 while (*curp) {
271 enum hwloc_pci_busid_comparison_e comp = hwloc_pci_compare_busids(new, *curp);
272 switch (comp) {
273 case HWLOC_PCI_BUSID_HIGHER:
274
275 curp = &(*curp)->next_sibling;
276 continue;
277 case HWLOC_PCI_BUSID_INCLUDED:
278
279 hwloc_pci_add_object(*curp, &(*curp)->io_first_child, new);
280 return;
281 case HWLOC_PCI_BUSID_LOWER:
282 case HWLOC_PCI_BUSID_SUPERSET: {
283
284 new->next_sibling = *curp;
285 *curp = new;
286 new->parent = parent;
287 if (new->type == HWLOC_OBJ_BRIDGE) {
288
289 childp = &new->io_first_child;
290 curp = &new->next_sibling;
291 while (*curp) {
292 hwloc_obj_t cur = *curp;
293 if (hwloc_pci_compare_busids(new, cur) == HWLOC_PCI_BUSID_LOWER) {
294
295 if (cur->attr->pcidev.domain > new->attr->pcidev.domain
296 || cur->attr->pcidev.bus > new->attr->bridge.downstream.pci.subordinate_bus)
297
298 return;
299 curp = &cur->next_sibling;
300 } else {
301
302 *childp = cur;
303 *curp = cur->next_sibling;
304 (*childp)->parent = new;
305 (*childp)->next_sibling = NULL;
306 childp = &(*childp)->next_sibling;
307 }
308 }
309 }
310 return;
311 }
312 }
313 }
314
315 new->parent = parent;
316 new->next_sibling = NULL;
317 *curp = new;
318 }
319
320 void
321 hwloc_pcidisc_tree_insert_by_busid(struct hwloc_obj **treep,
322 struct hwloc_obj *obj)
323 {
324 hwloc_pci_add_object(NULL , treep, obj);
325 }
326
327 int
328 hwloc_pcidisc_tree_attach(struct hwloc_topology *topology, struct hwloc_obj *old_tree)
329 {
330 struct hwloc_obj **next_hb_p;
331 enum hwloc_type_filter_e bfilter;
332
333 if (!old_tree)
334
335 return 0;
336
337 #ifdef HWLOC_DEBUG
338 hwloc_debug("%s", "\nPCI hierarchy:\n");
339 hwloc_pci_traverse(NULL, old_tree, hwloc_pci_traverse_print_cb);
340 hwloc_debug("%s", "\n");
341 #endif
342
343 next_hb_p = &hwloc_get_root_obj(topology)->io_first_child;
344 while (*next_hb_p)
345 next_hb_p = &((*next_hb_p)->next_sibling);
346
347 bfilter = topology->type_filter[HWLOC_OBJ_BRIDGE];
348 if (bfilter == HWLOC_TYPE_FILTER_KEEP_NONE) {
349 *next_hb_p = old_tree;
350 topology->modified = 1;
351 goto done;
352 }
353
354
355
356
357
358
359 while (old_tree) {
360
361 struct hwloc_obj *hostbridge = hwloc_alloc_setup_object(topology, HWLOC_OBJ_BRIDGE, HWLOC_UNKNOWN_INDEX);
362 struct hwloc_obj **dstnextp = &hostbridge->io_first_child;
363 struct hwloc_obj **srcnextp = &old_tree;
364 struct hwloc_obj *child = *srcnextp;
365 unsigned short current_domain = child->attr->pcidev.domain;
366 unsigned char current_bus = child->attr->pcidev.bus;
367 unsigned char current_subordinate = current_bus;
368
369 hwloc_debug("Starting new PCI hostbridge %04x:%02x\n", current_domain, current_bus);
370
371 next_child:
372
373 *srcnextp = child->next_sibling;
374
375 *dstnextp = child;
376 child->parent = hostbridge;
377 child->next_sibling = NULL;
378 dstnextp = &child->next_sibling;
379
380
381 if (child->type == HWLOC_OBJ_BRIDGE
382 && child->attr->bridge.downstream.pci.subordinate_bus > current_subordinate)
383 current_subordinate = child->attr->bridge.downstream.pci.subordinate_bus;
384
385
386 child = *srcnextp;
387 if (child
388 && child->attr->pcidev.domain == current_domain
389 && child->attr->pcidev.bus == current_bus)
390 goto next_child;
391
392
393 hostbridge->attr->bridge.upstream_type = HWLOC_OBJ_BRIDGE_HOST;
394 hostbridge->attr->bridge.downstream_type = HWLOC_OBJ_BRIDGE_PCI;
395 hostbridge->attr->bridge.downstream.pci.domain = current_domain;
396 hostbridge->attr->bridge.downstream.pci.secondary_bus = current_bus;
397 hostbridge->attr->bridge.downstream.pci.subordinate_bus = current_subordinate;
398 hwloc_debug("New PCI hostbridge %04x:[%02x-%02x]\n",
399 current_domain, current_bus, current_subordinate);
400
401 *next_hb_p = hostbridge;
402 next_hb_p = &hostbridge->next_sibling;
403 topology->modified = 1;
404
405
406 }
407
408 done:
409 topology->need_pci_belowroot_apply_locality = 1;
410 return 0;
411 }
412
413 static struct hwloc_obj *
414 hwloc_pci_fixup_busid_parent(struct hwloc_topology *topology __hwloc_attribute_unused,
415 struct hwloc_pcidev_attr_s *busid,
416 struct hwloc_obj *parent)
417 {
418
419
420
421 if (parent->depth >= 2
422 && parent->type == HWLOC_OBJ_NUMANODE
423 && parent->sibling_rank == 1 && parent->parent->arity == 2
424 && parent->parent->type == HWLOC_OBJ_PACKAGE
425 && parent->parent->sibling_rank == 0 && parent->parent->parent->arity == 2) {
426 const char *cpumodel = hwloc_obj_get_info_by_name(parent->parent, "CPUModel");
427 if (cpumodel && strstr(cpumodel, "Xeon")) {
428 if (!hwloc_hide_errors()) {
429 fprintf(stderr, "****************************************************************************\n");
430 fprintf(stderr, "* hwloc %s has encountered an incorrect PCI locality information.\n", HWLOC_VERSION);
431 fprintf(stderr, "* PCI bus %04x:%02x is supposedly close to 2nd NUMA node of 1st package,\n",
432 busid->domain, busid->bus);
433 fprintf(stderr, "* however hwloc believes this is impossible on this architecture.\n");
434 fprintf(stderr, "* Therefore the PCI bus will be moved to 1st NUMA node of 2nd package.\n");
435 fprintf(stderr, "*\n");
436 fprintf(stderr, "* If you feel this fixup is wrong, disable it by setting in your environment\n");
437 fprintf(stderr, "* HWLOC_PCI_%04x_%02x_LOCALCPUS= (empty value), and report the problem\n",
438 busid->domain, busid->bus);
439 fprintf(stderr, "* to the hwloc's user mailing list together with the XML output of lstopo.\n");
440 fprintf(stderr, "*\n");
441 fprintf(stderr, "* You may silence this message by setting HWLOC_HIDE_ERRORS=1 in your environment.\n");
442 fprintf(stderr, "****************************************************************************\n");
443 }
444 return parent->parent->next_sibling->first_child;
445 }
446 }
447
448 return parent;
449 }
450
451 static struct hwloc_obj *
452 hwloc__pci_find_busid_parent(struct hwloc_topology *topology, struct hwloc_pcidev_attr_s *busid)
453 {
454 hwloc_bitmap_t cpuset = hwloc_bitmap_alloc();
455 hwloc_obj_t parent;
456 int forced = 0;
457 int noquirks = 0;
458 unsigned i;
459 int err;
460
461
462 if (topology->pci_has_forced_locality) {
463 for(i=0; i<topology->pci_forced_locality_nr; i++) {
464 if (busid->domain == topology->pci_forced_locality[i].domain
465 && busid->bus >= topology->pci_forced_locality[i].bus_first
466 && busid->bus <= topology->pci_forced_locality[i].bus_last) {
467 hwloc_bitmap_copy(cpuset, topology->pci_forced_locality[i].cpuset);
468 forced = 1;
469 break;
470 }
471 }
472
473 noquirks = 1;
474 }
475
476
477 if (!forced) {
478 const char *env;
479 char envname[256];
480
481 snprintf(envname, sizeof(envname), "HWLOC_PCI_%04x_%02x_LOCALCPUS",
482 busid->domain, busid->bus);
483 env = getenv(envname);
484 if (env) {
485 static int reported = 0;
486 if (!topology->pci_has_forced_locality && !reported) {
487 fprintf(stderr, "Environment variable %s is deprecated, please use HWLOC_PCI_LOCALITY instead.\n", env);
488 reported = 1;
489 }
490 if (*env) {
491
492 hwloc_debug("Overriding localcpus using %s in the environment\n", envname);
493 hwloc_bitmap_sscanf(cpuset, env);
494 forced = 1;
495 }
496
497 noquirks = 1;
498 }
499 }
500
501 if (!forced) {
502
503 struct hwloc_backend *backend = topology->get_pci_busid_cpuset_backend;
504 if (backend)
505 err = backend->get_pci_busid_cpuset(backend, busid, cpuset);
506 else
507 err = -1;
508 if (err < 0)
509
510 hwloc_bitmap_copy(cpuset, hwloc_topology_get_topology_cpuset(topology));
511 }
512
513 hwloc_debug_bitmap("Attaching PCI tree to cpuset %s\n", cpuset);
514
515 parent = hwloc_find_insert_io_parent_by_complete_cpuset(topology, cpuset);
516 if (parent) {
517 if (!noquirks)
518
519 parent = hwloc_pci_fixup_busid_parent(topology, busid, parent);
520 } else {
521
522 parent = hwloc_get_root_obj(topology);
523 }
524
525 hwloc_bitmap_free(cpuset);
526 return parent;
527 }
528
529 struct hwloc_obj *
530 hwloc_pcidisc_find_busid_parent(struct hwloc_topology *topology,
531 unsigned domain, unsigned bus, unsigned dev, unsigned func)
532 {
533 struct hwloc_pcidev_attr_s busid;
534 busid.domain = domain;
535 busid.bus = bus;
536 busid.dev = dev;
537 busid.func = func;
538 return hwloc__pci_find_busid_parent(topology, &busid);
539 }
540
541 int
542 hwloc_pci_belowroot_apply_locality(struct hwloc_topology *topology)
543 {
544 struct hwloc_obj *root = hwloc_get_root_obj(topology);
545 struct hwloc_obj **listp, *obj;
546
547 if (!topology->need_pci_belowroot_apply_locality)
548 return 0;
549 topology->need_pci_belowroot_apply_locality = 0;
550
551
552
553
554 listp = &root->io_first_child;
555 while ((obj = *listp) != NULL) {
556 struct hwloc_pcidev_attr_s *busid;
557 struct hwloc_obj *parent;
558
559
560 if (obj->type != HWLOC_OBJ_PCI_DEVICE
561 && !(obj->type == HWLOC_OBJ_BRIDGE && obj->attr->bridge.downstream_type == HWLOC_OBJ_BRIDGE_PCI)
562 && !(obj->type == HWLOC_OBJ_BRIDGE && obj->attr->bridge.upstream_type == HWLOC_OBJ_BRIDGE_PCI)) {
563 listp = &obj->next_sibling;
564 continue;
565 }
566
567 if (obj->type == HWLOC_OBJ_PCI_DEVICE
568 || (obj->type == HWLOC_OBJ_BRIDGE
569 && obj->attr->bridge.upstream_type == HWLOC_OBJ_BRIDGE_PCI))
570 busid = &obj->attr->pcidev;
571 else {
572
573 hwloc_obj_t child = obj->io_first_child;
574 if (child && (child->type == HWLOC_OBJ_PCI_DEVICE
575 || (child->type == HWLOC_OBJ_BRIDGE
576 && child->attr->bridge.upstream_type == HWLOC_OBJ_BRIDGE_PCI)))
577 busid = &obj->io_first_child->attr->pcidev;
578 else
579 continue;
580 }
581
582
583 parent = hwloc__pci_find_busid_parent(topology, busid);
584 if (parent == root) {
585
586 listp = &obj->next_sibling;
587 } else {
588
589 *listp = obj->next_sibling;
590 obj->next_sibling = NULL;
591 hwloc_insert_object_by_parent(topology, parent, obj);
592 }
593 }
594
595 return 0;
596 }
597
598 static struct hwloc_obj *
599 hwloc__pci_belowroot_find_by_busid(hwloc_obj_t parent,
600 unsigned domain, unsigned bus, unsigned dev, unsigned func)
601 {
602 hwloc_obj_t child;
603
604 for_each_io_child(child, parent) {
605 if (child->type == HWLOC_OBJ_PCI_DEVICE
606 || (child->type == HWLOC_OBJ_BRIDGE
607 && child->attr->bridge.upstream_type == HWLOC_OBJ_BRIDGE_PCI)) {
608 if (child->attr->pcidev.domain == domain
609 && child->attr->pcidev.bus == bus
610 && child->attr->pcidev.dev == dev
611 && child->attr->pcidev.func == func)
612
613 return child;
614 if (child->attr->pcidev.domain > domain
615 || (child->attr->pcidev.domain == domain
616 && child->attr->pcidev.bus > bus))
617
618 return parent;
619 if (child->type == HWLOC_OBJ_BRIDGE
620 && child->attr->bridge.downstream_type == HWLOC_OBJ_BRIDGE_PCI
621 && child->attr->bridge.downstream.pci.domain == domain
622 && child->attr->bridge.downstream.pci.secondary_bus <= bus
623 && child->attr->bridge.downstream.pci.subordinate_bus >= bus)
624
625 return hwloc__pci_belowroot_find_by_busid(child, domain, bus, dev, func);
626
627 } else if (child->type == HWLOC_OBJ_BRIDGE
628 && child->attr->bridge.upstream_type != HWLOC_OBJ_BRIDGE_PCI
629 && child->attr->bridge.downstream_type == HWLOC_OBJ_BRIDGE_PCI
630
631 && child->attr->bridge.downstream.pci.domain == domain
632 && child->attr->bridge.downstream.pci.secondary_bus <= bus
633 && child->attr->bridge.downstream.pci.subordinate_bus >= bus) {
634
635 return hwloc__pci_belowroot_find_by_busid(child, domain, bus, dev, func);
636 }
637 }
638
639 return parent;
640 }
641
642 struct hwloc_obj *
643 hwloc_pcidisc_find_by_busid(struct hwloc_topology *topology,
644 unsigned domain, unsigned bus, unsigned dev, unsigned func)
645 {
646 hwloc_obj_t root = hwloc_get_root_obj(topology);
647 hwloc_obj_t parent = hwloc__pci_belowroot_find_by_busid(root, domain, bus, dev, func);
648 if (parent == root)
649 return NULL;
650 else
651 return parent;
652 }
653
654 #define HWLOC_PCI_STATUS 0x06
655 #define HWLOC_PCI_STATUS_CAP_LIST 0x10
656 #define HWLOC_PCI_CAPABILITY_LIST 0x34
657 #define HWLOC_PCI_CAP_LIST_ID 0
658 #define HWLOC_PCI_CAP_LIST_NEXT 1
659
660 unsigned
661 hwloc_pcidisc_find_cap(const unsigned char *config, unsigned cap)
662 {
663 unsigned char seen[256] = { 0 };
664 unsigned char ptr;
665
666 if (!(config[HWLOC_PCI_STATUS] & HWLOC_PCI_STATUS_CAP_LIST))
667 return 0;
668
669 for (ptr = config[HWLOC_PCI_CAPABILITY_LIST] & ~3;
670 ptr;
671 ptr = config[ptr + HWLOC_PCI_CAP_LIST_NEXT] & ~3) {
672 unsigned char id;
673
674
675 if (seen[ptr])
676 break;
677 seen[ptr] = 1;
678
679 id = config[ptr + HWLOC_PCI_CAP_LIST_ID];
680 if (id == cap)
681 return ptr;
682 if (id == 0xff)
683 break;
684 }
685 return 0;
686 }
687
688 #define HWLOC_PCI_EXP_LNKSTA 0x12
689 #define HWLOC_PCI_EXP_LNKSTA_SPEED 0x000f
690 #define HWLOC_PCI_EXP_LNKSTA_WIDTH 0x03f0
691
692 int
693 hwloc_pcidisc_find_linkspeed(const unsigned char *config,
694 unsigned offset, float *linkspeed)
695 {
696 unsigned linksta, speed, width;
697 float lanespeed;
698
699 memcpy(&linksta, &config[offset + HWLOC_PCI_EXP_LNKSTA], 4);
700 speed = linksta & HWLOC_PCI_EXP_LNKSTA_SPEED;
701 width = (linksta & HWLOC_PCI_EXP_LNKSTA_WIDTH) >> 4;
702
703
704
705
706
707
708
709 if (speed <= 2)
710 lanespeed = 2.5f * speed * 0.8f;
711 else
712 lanespeed = 8.0f * (1<<(speed-3)) * 128/130;
713
714
715 *linkspeed = lanespeed * width / 8;
716 return 0;
717 }
718
719 #define HWLOC_PCI_HEADER_TYPE 0x0e
720 #define HWLOC_PCI_HEADER_TYPE_BRIDGE 1
721 #define HWLOC_PCI_CLASS_BRIDGE_PCI 0x0604
722
723 hwloc_obj_type_t
724 hwloc_pcidisc_check_bridge_type(unsigned device_class, const unsigned char *config)
725 {
726 unsigned char headertype;
727
728 if (device_class != HWLOC_PCI_CLASS_BRIDGE_PCI)
729 return HWLOC_OBJ_PCI_DEVICE;
730
731 headertype = config[HWLOC_PCI_HEADER_TYPE] & 0x7f;
732 return (headertype == HWLOC_PCI_HEADER_TYPE_BRIDGE)
733 ? HWLOC_OBJ_BRIDGE : HWLOC_OBJ_PCI_DEVICE;
734 }
735
736 #define HWLOC_PCI_PRIMARY_BUS 0x18
737 #define HWLOC_PCI_SECONDARY_BUS 0x19
738 #define HWLOC_PCI_SUBORDINATE_BUS 0x1a
739
740 int
741 hwloc_pcidisc_setup_bridge_attr(hwloc_obj_t obj,
742 const unsigned char *config)
743 {
744 struct hwloc_bridge_attr_s *battr = &obj->attr->bridge;
745 struct hwloc_pcidev_attr_s *pattr = &battr->upstream.pci;
746
747 if (config[HWLOC_PCI_PRIMARY_BUS] != pattr->bus) {
748
749
750
751
752 hwloc_debug(" %04x:%02x:%02x.%01x bridge with (ignored) invalid PCI_PRIMARY_BUS %02x\n",
753 pattr->domain, pattr->bus, pattr->dev, pattr->func, config[HWLOC_PCI_PRIMARY_BUS]);
754 }
755
756 obj->type = HWLOC_OBJ_BRIDGE;
757 battr->upstream_type = HWLOC_OBJ_BRIDGE_PCI;
758 battr->downstream_type = HWLOC_OBJ_BRIDGE_PCI;
759 battr->downstream.pci.domain = pattr->domain;
760 battr->downstream.pci.secondary_bus = config[HWLOC_PCI_SECONDARY_BUS];
761 battr->downstream.pci.subordinate_bus = config[HWLOC_PCI_SUBORDINATE_BUS];
762
763 if (battr->downstream.pci.secondary_bus <= pattr->bus
764 || battr->downstream.pci.subordinate_bus <= pattr->bus
765 || battr->downstream.pci.secondary_bus > battr->downstream.pci.subordinate_bus) {
766
767
768
769
770
771
772 hwloc_debug(" %04x:%02x:%02x.%01x bridge has invalid secondary-subordinate buses [%02x-%02x]\n",
773 pattr->domain, pattr->bus, pattr->dev, pattr->func,
774 battr->downstream.pci.secondary_bus, battr->downstream.pci.subordinate_bus);
775 hwloc_free_unlinked_object(obj);
776 return -1;
777 }
778
779 return 0;
780 }
781
782 const char *
783 hwloc_pci_class_string(unsigned short class_id)
784 {
785
786 switch ((class_id & 0xff00) >> 8) {
787 case 0x00:
788 switch (class_id) {
789 case 0x0001: return "VGA";
790 }
791 break;
792 case 0x01:
793 switch (class_id) {
794 case 0x0100: return "SCSI";
795 case 0x0101: return "IDE";
796 case 0x0102: return "Floppy";
797 case 0x0103: return "IPI";
798 case 0x0104: return "RAID";
799 case 0x0105: return "ATA";
800 case 0x0106: return "SATA";
801 case 0x0107: return "SAS";
802 case 0x0108: return "NVMExp";
803 }
804 return "Storage";
805 case 0x02:
806 switch (class_id) {
807 case 0x0200: return "Ethernet";
808 case 0x0201: return "TokenRing";
809 case 0x0202: return "FDDI";
810 case 0x0203: return "ATM";
811 case 0x0204: return "ISDN";
812 case 0x0205: return "WorldFip";
813 case 0x0206: return "PICMG";
814 case 0x0207: return "InfiniBand";
815 case 0x0208: return "Fabric";
816 }
817 return "Network";
818 case 0x03:
819 switch (class_id) {
820 case 0x0300: return "VGA";
821 case 0x0301: return "XGA";
822 case 0x0302: return "3D";
823 }
824 return "Display";
825 case 0x04:
826 switch (class_id) {
827 case 0x0400: return "MultimediaVideo";
828 case 0x0401: return "MultimediaAudio";
829 case 0x0402: return "Telephony";
830 case 0x0403: return "AudioDevice";
831 }
832 return "Multimedia";
833 case 0x05:
834 switch (class_id) {
835 case 0x0500: return "RAM";
836 case 0x0501: return "Flash";
837 }
838 return "Memory";
839 case 0x06:
840 switch (class_id) {
841 case 0x0600: return "HostBridge";
842 case 0x0601: return "ISABridge";
843 case 0x0602: return "EISABridge";
844 case 0x0603: return "MicroChannelBridge";
845 case 0x0604: return "PCIBridge";
846 case 0x0605: return "PCMCIABridge";
847 case 0x0606: return "NubusBridge";
848 case 0x0607: return "CardBusBridge";
849 case 0x0608: return "RACEwayBridge";
850 case 0x0609: return "SemiTransparentPCIBridge";
851 case 0x060a: return "InfiniBandPCIHostBridge";
852 }
853 return "Bridge";
854 case 0x07:
855 switch (class_id) {
856 case 0x0700: return "Serial";
857 case 0x0701: return "Parallel";
858 case 0x0702: return "MultiportSerial";
859 case 0x0703: return "Model";
860 case 0x0704: return "GPIB";
861 case 0x0705: return "SmartCard";
862 }
863 return "Communication";
864 case 0x08:
865 switch (class_id) {
866 case 0x0800: return "PIC";
867 case 0x0801: return "DMA";
868 case 0x0802: return "Timer";
869 case 0x0803: return "RTC";
870 case 0x0804: return "PCIHotPlug";
871 case 0x0805: return "SDHost";
872 case 0x0806: return "IOMMU";
873 }
874 return "SystemPeripheral";
875 case 0x09:
876 switch (class_id) {
877 case 0x0900: return "Keyboard";
878 case 0x0901: return "DigitizerPen";
879 case 0x0902: return "Mouse";
880 case 0x0903: return "Scanern";
881 case 0x0904: return "Gameport";
882 }
883 return "Input";
884 case 0x0a:
885 return "DockingStation";
886 case 0x0b:
887 switch (class_id) {
888 case 0x0b00: return "386";
889 case 0x0b01: return "486";
890 case 0x0b02: return "Pentium";
891
892 case 0x0b10: return "Alpha";
893 case 0x0b20: return "PowerPC";
894 case 0x0b30: return "MIPS";
895 case 0x0b40: return "Co-Processor";
896 }
897 return "Processor";
898 case 0x0c:
899 switch (class_id) {
900 case 0x0c00: return "FireWire";
901 case 0x0c01: return "ACCESS";
902 case 0x0c02: return "SSA";
903 case 0x0c03: return "USB";
904 case 0x0c04: return "FibreChannel";
905 case 0x0c05: return "SMBus";
906 case 0x0c06: return "InfiniBand";
907 case 0x0c07: return "IPMI-SMIC";
908 case 0x0c08: return "SERCOS";
909 case 0x0c09: return "CANBUS";
910 }
911 return "SerialBus";
912 case 0x0d:
913 switch (class_id) {
914 case 0x0d00: return "IRDA";
915 case 0x0d01: return "ConsumerIR";
916 case 0x0d10: return "RF";
917 case 0x0d11: return "Bluetooth";
918 case 0x0d12: return "Broadband";
919 case 0x0d20: return "802.1a";
920 case 0x0d21: return "802.1b";
921 }
922 return "Wireless";
923 case 0x0e:
924 switch (class_id) {
925 case 0x0e00: return "I2O";
926 }
927 return "Intelligent";
928 case 0x0f:
929 return "Satellite";
930 case 0x10:
931 return "Encryption";
932 case 0x11:
933 return "SignalProcessing";
934 case 0x12:
935 return "ProcessingAccelerator";
936 case 0x13:
937 return "Instrumentation";
938 case 0x40:
939 return "Co-Processor";
940 }
941 return "Other";
942 }