]>
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.
15 struct bridge host_bridge
= { NULL
, NULL
, NULL
, NULL
, NULL
, 0, ~0, 0, ~0, NULL
};
18 find_bus(struct bridge
*b
, unsigned int domain
, unsigned int n
)
22 for (bus
=b
->first_bus
; bus
; bus
=bus
->sibling
)
23 if (bus
->domain
== domain
&& bus
->number
== n
)
28 static struct device
*
29 find_device(struct pci_dev
*dd
)
35 for (d
=first_dev
; d
; d
=d
->next
)
42 new_bus(struct bridge
*b
, unsigned int domain
, unsigned int n
)
44 struct bus
*bus
= xmalloc(sizeof(struct bus
));
48 bus
->first_dev
= NULL
;
49 bus
->last_dev
= &bus
->first_dev
;
50 bus
->parent_bridge
= b
;
52 b
->last_bus
->sibling
= bus
;
60 insert_dev(struct device
*d
, struct bridge
*b
)
62 struct pci_dev
*p
= d
->dev
;
63 struct device
*parent
= NULL
;
64 struct bus
*bus
= NULL
;
66 if (p
->known_fields
& PCI_FILL_PARENT
)
67 parent
= find_device(p
->parent
);
69 if (parent
&& parent
->bridge
)
71 bus
= parent
->bridge
->first_bus
;
73 bus
= new_bus(parent
->bridge
, p
->domain
, p
->bus
);
76 if (!bus
&& ! (bus
= find_bus(b
, p
->domain
, p
->bus
)))
79 for (c
=b
->child
; c
; c
=c
->next
)
80 if (c
->domain
== (unsigned)p
->domain
&& c
->secondary
<= p
->bus
&& p
->bus
<= c
->subordinate
)
85 bus
= new_bus(b
, p
->domain
, p
->bus
);
87 /* Simple insertion at the end _does_ guarantee the correct order as the
88 * original device list was sorted by (domain, bus, devfn) lexicographically
89 * and all devices on the new list have the same bus number.
92 bus
->last_dev
= &d
->bus_next
;
101 struct bridge
**last_br
, *b
;
103 /* Build list of bridges */
105 last_br
= &host_bridge
.chain
;
106 for (d
=first_dev
; d
; d
=d
->next
)
108 struct pci_dev
*dd
= d
->dev
;
109 word
class = dd
->device_class
;
110 byte ht
= d
->no_config_access
? -1 : (get_conf_byte(d
, PCI_HEADER_TYPE
) & 0x7f);
111 if ((class >> 8) == PCI_BASE_CLASS_BRIDGE
&&
112 (ht
== PCI_HEADER_TYPE_BRIDGE
|| ht
== PCI_HEADER_TYPE_CARDBUS
))
114 b
= xmalloc(sizeof(struct bridge
));
115 b
->domain
= dd
->domain
;
116 if (ht
== PCI_HEADER_TYPE_BRIDGE
)
118 b
->primary
= get_conf_byte(d
, PCI_PRIMARY_BUS
);
119 b
->secondary
= get_conf_byte(d
, PCI_SECONDARY_BUS
);
120 b
->subordinate
= get_conf_byte(d
, PCI_SUBORDINATE_BUS
);
124 b
->primary
= get_conf_byte(d
, PCI_CB_PRIMARY_BUS
);
125 b
->secondary
= get_conf_byte(d
, PCI_CB_CARD_BUS
);
126 b
->subordinate
= get_conf_byte(d
, PCI_CB_SUBORDINATE_BUS
);
130 b
->next
= b
->child
= NULL
;
135 pacc
->debug("Tree: bridge %04x:%02x:%02x.%d: %02x -> %02x-%02x\n",
136 dd
->domain
, dd
->bus
, dd
->dev
, dd
->func
,
137 b
->primary
, b
->secondary
, b
->subordinate
);
141 /* Append additional bridges reported by libpci via d->parent */
143 for (d
=first_dev
; d
; d
=d
->next
)
145 struct device
*parent
= NULL
;
146 if (d
->dev
->known_fields
& PCI_FILL_PARENT
)
147 parent
= find_device(d
->dev
->parent
);
148 if (!parent
|| parent
->bridge
)
150 b
= xmalloc(sizeof(struct bridge
));
151 b
->domain
= parent
->dev
->domain
;
152 b
->primary
= parent
->dev
->bus
;
153 b
->secondary
= d
->dev
->bus
;
154 /* At this stage subordinate number is unknown, so set it to secondary bus number. */
155 b
->subordinate
= b
->secondary
;
158 b
->next
= b
->child
= NULL
;
163 pacc
->debug("Tree: bridge %04x:%02x:%02x.%d\n", b
->domain
,
164 parent
->dev
->bus
, parent
->dev
->dev
, parent
->dev
->func
);
168 /* Create a bridge tree */
170 for (b
=&host_bridge
; b
; b
=b
->chain
)
172 struct device
*br_dev
= b
->br_dev
;
173 struct bridge
*c
, *best
= NULL
;
174 struct device
*parent
= NULL
;
176 if (br_dev
&& (br_dev
->dev
->known_fields
& PCI_FILL_PARENT
))
177 parent
= find_device(br_dev
->dev
->parent
);
179 best
= parent
->bridge
;
181 for (c
=&host_bridge
; c
; c
=c
->chain
)
182 if (c
!= b
&& (c
== &host_bridge
|| b
->domain
== c
->domain
) &&
183 b
->primary
>= c
->secondary
&& b
->primary
<= c
->subordinate
&&
184 (!best
|| best
->subordinate
- best
->primary
> c
->subordinate
- c
->primary
))
188 b
->next
= best
->child
;
193 /* Insert secondary bus for each bridge */
195 for (b
=&host_bridge
; b
; b
=b
->chain
)
196 if (!find_bus(b
, b
->domain
, b
->secondary
))
197 new_bus(b
, b
->domain
, b
->secondary
);
199 /* Create bus structs and link devices */
201 for (d
=first_dev
; d
; d
=d
->next
)
202 insert_dev(d
, &host_bridge
);
205 #define LINE_BUF_SIZE 1024
208 print_it(char *line
, char *p
)
212 if (p
>= line
+ LINE_BUF_SIZE
- 1)
213 fputs("...", stdout
);
215 for (p
=line
; *p
; p
++)
216 if (*p
== '+' || *p
== '|')
222 static void show_tree_bridge(struct pci_filter
*filter
, struct bridge
*, char *, char *);
224 static char * FORMAT_CHECK(printf
, 3, 4)
225 tree_printf(char *line
, char *p
, char *fmt
, ...)
228 int space
= line
+ LINE_BUF_SIZE
- 1 - p
;
234 int res
= vsnprintf(p
, space
, fmt
, args
);
237 /* Ancient C libraries return -1 on overflow and they do not truncate the output properly. */
241 else if (res
>= space
)
243 /* Ancient C libraries do not truncate the output properly. */
255 show_tree_dev(struct pci_filter
*filter
, struct device
*d
, char *line
, char *p
)
257 struct pci_dev
*q
= d
->dev
;
261 p
= tree_printf(line
, p
, "%02x.%x", q
->dev
, q
->func
);
262 for (b
=&host_bridge
; b
; b
=b
->chain
)
265 if (b
->secondary
== 0)
266 p
= tree_printf(line
, p
, "-");
267 else if (b
->secondary
== b
->subordinate
)
268 p
= tree_printf(line
, p
, "-[%02x]-", b
->secondary
);
270 p
= tree_printf(line
, p
, "-[%02x-%02x]-", b
->secondary
, b
->subordinate
);
271 show_tree_bridge(filter
, b
, line
, p
);
275 p
= tree_printf(line
, p
, " %s",
276 pci_lookup_name(pacc
, namebuf
, sizeof(namebuf
),
277 PCI_LOOKUP_VENDOR
| PCI_LOOKUP_DEVICE
,
278 q
->vendor_id
, q
->device_id
));
283 check_bus_filter(struct pci_filter
*filter
, struct bus
*b
);
286 check_dev_filter(struct pci_filter
*filter
, struct device
*d
)
294 if (pci_filter_match(filter
, d
->dev
))
297 for (br
= &host_bridge
; br
; br
= br
->chain
)
300 for (b
= br
->first_bus
; b
; b
= b
->sibling
)
301 if (check_bus_filter(filter
, b
))
310 check_bus_filter(struct pci_filter
*filter
, struct bus
*b
)
317 for (d
= b
->first_dev
; d
; d
= d
->bus_next
)
318 if (check_dev_filter(filter
, d
))
325 show_tree_bus(struct pci_filter
*filter
, struct bus
*b
, char *line
, char *p
)
329 else if (!b
->first_dev
->bus_next
)
331 if (check_dev_filter(filter
, b
->first_dev
))
333 p
= tree_printf(line
, p
, "--");
334 show_tree_dev(filter
, b
->first_dev
, line
, p
);
342 struct device
*d
= b
->first_dev
;
345 if (check_dev_filter(filter
, d
))
347 char *p2
= tree_printf(line
, p
, "+-");
348 show_tree_dev(filter
, d
, line
, p2
);
353 if (check_dev_filter(filter
, d
))
355 p
= tree_printf(line
, p
, "\\-");
356 show_tree_dev(filter
, d
, line
, p
);
365 show_tree_bridge(struct pci_filter
*filter
, struct bridge
*b
, char *line
, char *p
)
368 if (!b
->first_bus
->sibling
)
370 if (check_bus_filter(filter
, b
->first_bus
))
372 if (b
== &host_bridge
)
373 p
= tree_printf(line
, p
, "[%04x:%02x]-", b
->domain
, b
->first_bus
->number
);
374 show_tree_bus(filter
, b
->first_bus
, line
, p
);
382 struct bus
*u
= b
->first_bus
;
387 if (check_bus_filter(filter
, u
))
389 k
= tree_printf(line
, p
, "+-[%04x:%02x]-", u
->domain
, u
->number
);
390 show_tree_bus(filter
, u
, line
, k
);
395 if (check_bus_filter(filter
, u
))
397 k
= tree_printf(line
, p
, "\\-[%04x:%02x]-", u
->domain
, u
->number
);
398 show_tree_bus(filter
, u
, line
, k
);
407 show_forest(struct pci_filter
*filter
)
409 char line
[LINE_BUF_SIZE
];
410 show_tree_bridge(filter
, &host_bridge
, line
, line
);