]>
git.ipfire.org Git - thirdparty/pciutils.git/blob - ls-tree.c
2 * The PCI Utilities -- Show Bus Tree
4 * Copyright (c) 1997--2021 Martin Mares <mj@ucw.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL v2+.
8 * SPDX-License-Identifier: GPL-2.0-or-later
17 struct bridge host_bridge
= { NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, ~0, ~0, ~0, ~0, NULL
};
20 find_bus(struct bridge
*b
, unsigned int domain
, unsigned int n
)
24 for (bus
=b
->first_bus
; bus
; bus
=bus
->sibling
)
25 if (bus
->domain
== domain
&& bus
->number
== n
)
30 static struct device
*
31 find_device(struct pci_dev
*dd
)
37 for (d
=first_dev
; d
; d
=d
->next
)
44 new_bus(struct bridge
*b
, unsigned int domain
, unsigned int n
)
46 struct bus
*bus
= xmalloc(sizeof(struct bus
));
50 bus
->first_dev
= NULL
;
51 bus
->last_dev
= &bus
->first_dev
;
52 bus
->parent_bridge
= b
;
54 b
->last_bus
->sibling
= bus
;
62 insert_dev(struct device
*d
, struct bridge
*b
)
64 struct pci_dev
*p
= d
->dev
;
65 struct device
*parent
= NULL
;
66 struct bus
*bus
= NULL
;
68 if (p
->known_fields
& PCI_FILL_PARENT
)
69 parent
= find_device(p
->parent
);
71 if (parent
&& parent
->bridge
)
73 bus
= parent
->bridge
->first_bus
;
75 bus
= new_bus(parent
->bridge
, p
->domain
, p
->bus
);
78 if (!bus
&& b
== &host_bridge
)
80 for (b
=b
->child
; b
; b
=b
->prev
)
81 if (b
->domain
== (unsigned)p
->domain
)
87 if (!bus
&& ! (bus
= find_bus(b
, p
->domain
, p
->bus
)))
90 for (c
=b
->child
; c
; c
=c
->prev
)
91 if (c
->domain
== (unsigned)p
->domain
&& c
->secondary
<= p
->bus
&& p
->bus
<= c
->subordinate
)
96 bus
= new_bus(b
, p
->domain
, p
->bus
);
98 /* Simple insertion at the end _does_ guarantee the correct order as the
99 * original device list was sorted by (domain, bus, devfn) lexicographically
100 * and all devices on the new list have the same bus number.
103 bus
->last_dev
= &d
->bus_next
;
112 struct bridge
**last_br
, *b
;
114 last_br
= &host_bridge
.chain
;
116 /* Build list of top level domain bridges */
118 for (d
=first_dev
; d
; d
=d
->next
)
120 for (b
=host_bridge
.chain
; b
; b
=b
->chain
)
121 if (b
->domain
== (unsigned)d
->dev
->domain
)
125 b
= xmalloc(sizeof(struct bridge
));
126 b
->domain
= d
->dev
->domain
;
132 b
->prev
= b
->next
= b
->child
= NULL
;
137 pacc
->debug("Tree: domain %04x\n", b
->domain
);
140 /* Build list of bridges */
142 for (d
=first_dev
; d
; d
=d
->next
)
144 struct pci_dev
*dd
= d
->dev
;
145 word
class = dd
->device_class
;
146 byte ht
= d
->no_config_access
? -1 : (get_conf_byte(d
, PCI_HEADER_TYPE
) & 0x7f);
147 if ((class >> 8) == PCI_BASE_CLASS_BRIDGE
&&
148 (ht
== PCI_HEADER_TYPE_BRIDGE
|| ht
== PCI_HEADER_TYPE_CARDBUS
))
150 b
= xmalloc(sizeof(struct bridge
));
151 b
->domain
= dd
->domain
;
152 b
->primary
= dd
->bus
;
153 if (ht
== PCI_HEADER_TYPE_BRIDGE
)
155 b
->secondary
= get_conf_byte(d
, PCI_SECONDARY_BUS
);
156 b
->subordinate
= get_conf_byte(d
, PCI_SUBORDINATE_BUS
);
160 b
->secondary
= get_conf_byte(d
, PCI_CB_CARD_BUS
);
161 b
->subordinate
= get_conf_byte(d
, PCI_CB_SUBORDINATE_BUS
);
165 b
->prev
= b
->next
= b
->child
= NULL
;
170 pacc
->debug("Tree: bridge %04x:%02x:%02x.%d: %02x -> %02x-%02x\n",
171 dd
->domain
, dd
->bus
, dd
->dev
, dd
->func
,
172 b
->primary
, b
->secondary
, b
->subordinate
);
176 /* Append additional bridges reported by libpci via d->parent */
178 for (d
=first_dev
; d
; d
=d
->next
)
180 struct device
*parent
= NULL
;
181 if (d
->dev
->known_fields
& PCI_FILL_PARENT
)
182 parent
= find_device(d
->dev
->parent
);
183 if (!parent
|| parent
->bridge
)
185 b
= xmalloc(sizeof(struct bridge
));
186 b
->domain
= parent
->dev
->domain
;
187 b
->primary
= parent
->dev
->bus
;
188 b
->secondary
= d
->dev
->bus
;
189 /* At this stage subordinate number is unknown, so set it to secondary bus number. */
190 b
->subordinate
= b
->secondary
;
193 b
->prev
= b
->next
= b
->child
= NULL
;
198 pacc
->debug("Tree: bridge %04x:%02x:%02x.%d\n", b
->domain
,
199 parent
->dev
->bus
, parent
->dev
->dev
, parent
->dev
->func
);
203 /* Create a bridge tree */
205 for (b
=host_bridge
.chain
; b
; b
=b
->chain
)
207 struct device
*br_dev
= b
->br_dev
;
208 struct bridge
*c
, *best
= NULL
;
209 struct device
*parent
= NULL
;
211 if (br_dev
&& (br_dev
->dev
->known_fields
& PCI_FILL_PARENT
))
212 parent
= find_device(br_dev
->dev
->parent
);
214 best
= parent
->bridge
;
216 for (c
=&host_bridge
; c
; c
=c
->chain
)
217 if (c
!= b
&& (c
== &host_bridge
|| b
->domain
== c
->domain
) &&
218 b
->primary
>= c
->secondary
&& b
->primary
<= c
->subordinate
&&
219 (!best
|| best
== &host_bridge
|| best
->subordinate
- best
->primary
> c
->subordinate
- c
->primary
))
223 b
->prev
= best
->child
;
228 /* Insert secondary bus for each bridge */
230 for (b
=host_bridge
.chain
; b
; b
=b
->chain
)
231 if (b
->br_dev
&& !find_bus(b
, b
->domain
, b
->secondary
))
232 new_bus(b
, b
->domain
, b
->secondary
);
234 /* Create bus structs and link devices */
236 for (d
=first_dev
; d
; d
=d
->next
)
237 insert_dev(d
, &host_bridge
);
240 #define LINE_BUF_SIZE 1024
243 print_it(char *line
, char *p
)
247 if (p
>= line
+ LINE_BUF_SIZE
- 1)
248 fputs("...", stdout
);
250 for (p
=line
; *p
; p
++)
251 if (*p
== '+' || *p
== '|')
257 static void show_tree_bridge(struct pci_filter
*filter
, struct bridge
*, char *, char *);
259 static char * FORMAT_CHECK(printf
, 3, 4)
260 tree_printf(char *line
, char *p
, char *fmt
, ...)
263 int space
= line
+ LINE_BUF_SIZE
- 1 - p
;
269 int res
= vsnprintf(p
, space
, fmt
, args
);
272 /* Ancient C libraries return -1 on overflow and they do not truncate the output properly. */
276 else if (res
>= space
)
278 /* Ancient C libraries do not truncate the output properly. */
290 show_tree_dev(struct pci_filter
*filter
, struct device
*d
, char *line
, char *p
)
292 struct pci_dev
*q
= d
->dev
;
296 p
= tree_printf(line
, p
, "%02x.%x", q
->dev
, q
->func
);
297 for (b
=host_bridge
.chain
; b
; b
=b
->chain
)
300 if (b
->secondary
== 0)
301 p
= tree_printf(line
, p
, "-");
302 else if (b
->secondary
== b
->subordinate
)
303 p
= tree_printf(line
, p
, "-[%02x]-", b
->secondary
);
305 p
= tree_printf(line
, p
, "-[%02x-%02x]-", b
->secondary
, b
->subordinate
);
306 show_tree_bridge(filter
, b
, line
, p
);
310 p
= tree_printf(line
, p
, " %s",
311 pci_lookup_name(pacc
, namebuf
, sizeof(namebuf
),
312 PCI_LOOKUP_VENDOR
| PCI_LOOKUP_DEVICE
,
313 q
->vendor_id
, q
->device_id
));
317 static struct pci_filter
*
318 get_filter_for_child(struct pci_filter
*filter
, struct device
*d
)
323 if (pci_filter_match(filter
, d
->dev
))
330 check_bus_filter(struct pci_filter
*filter
, struct bus
*b
);
333 check_dev_filter(struct pci_filter
*filter
, struct device
*d
)
341 if (pci_filter_match(filter
, d
->dev
))
344 for (br
= host_bridge
.chain
; br
; br
= br
->chain
)
347 for (b
= br
->first_bus
; b
; b
= b
->sibling
)
348 if (check_bus_filter(filter
, b
))
357 check_bus_filter(struct pci_filter
*filter
, struct bus
*b
)
364 for (d
= b
->first_dev
; d
; d
= d
->bus_next
)
365 if (check_dev_filter(filter
, d
))
372 show_tree_bus(struct pci_filter
*filter
, struct bus
*b
, char *line
, char *p
)
376 else if (!b
->first_dev
->bus_next
)
378 if (check_dev_filter(filter
, b
->first_dev
))
380 p
= tree_printf(line
, p
, "--");
381 show_tree_dev(get_filter_for_child(filter
, b
->first_dev
), b
->first_dev
, line
, p
);
389 struct device
*d
= b
->first_dev
;
393 if (check_dev_filter(filter
, d
))
399 for (i
= 0, d
= b
->first_dev
; d
; d
= d
->bus_next
)
401 if (!check_dev_filter(filter
, d
))
403 char *p2
= tree_printf(line
, p
, count
== 1 ? "--" : count
== i
+1 ? "\\-" : "+-");
404 show_tree_dev(get_filter_for_child(filter
, d
), d
, line
, p2
);
414 show_tree_bridge(struct pci_filter
*filter
, struct bridge
*b
, char *line
, char *p
)
417 if (!b
->first_bus
->sibling
)
419 if (check_bus_filter(filter
, b
->first_bus
))
422 p
= tree_printf(line
, p
, "[%04x:%02x]-", b
->first_bus
->domain
, b
->first_bus
->number
);
423 show_tree_bus(filter
, b
->first_bus
, line
, p
);
431 struct bus
*u
= b
->first_bus
;
436 if (check_bus_filter(filter
, u
))
442 for (i
= 0, u
= b
->first_bus
; u
; u
= u
->sibling
)
444 if (!check_bus_filter(filter
, u
))
446 k
= tree_printf(line
, p
, count
== 1 ? "[%04x:%02x]-" : count
== i
+1 ? "\\-[%04x:%02x]-" : "+-[%04x:%02x]-", u
->domain
, u
->number
);
447 show_tree_bus(filter
, u
, line
, k
);
457 show_forest(struct pci_filter
*filter
)
459 char line
[LINE_BUF_SIZE
];
461 if (host_bridge
.child
)
463 for (b
=host_bridge
.child
; b
->prev
; b
=b
->prev
)
466 show_tree_bridge(filter
, b
, line
, line
);