]>
git.ipfire.org Git - thirdparty/pciutils.git/blob - ls-tree.c
2 * The PCI Utilities -- Show Bus Tree
4 * Copyright (c) 1997--2020 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
, 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
)
29 new_bus(struct bridge
*b
, unsigned int domain
, unsigned int n
)
31 struct bus
*bus
= xmalloc(sizeof(struct bus
));
34 bus
->sibling
= b
->first_bus
;
35 bus
->first_dev
= NULL
;
36 bus
->last_dev
= &bus
->first_dev
;
37 bus
->parent_bridge
= b
;
43 insert_dev(struct device
*d
, struct bridge
*b
)
45 struct pci_dev
*p
= d
->dev
;
48 if (! (bus
= find_bus(b
, p
->domain
, p
->bus
)))
51 for (c
=b
->child
; c
; c
=c
->next
)
52 if (c
->domain
== (unsigned)p
->domain
&& c
->secondary
<= p
->bus
&& p
->bus
<= c
->subordinate
)
57 bus
= new_bus(b
, p
->domain
, p
->bus
);
59 /* Simple insertion at the end _does_ guarantee the correct order as the
60 * original device list was sorted by (domain, bus, devfn) lexicographically
61 * and all devices on the new list have the same bus number.
64 bus
->last_dev
= &d
->bus_next
;
73 struct bridge
**last_br
, *b
;
75 /* Build list of bridges */
77 last_br
= &host_bridge
.chain
;
78 for (d
=first_dev
; d
; d
=d
->next
)
80 struct pci_dev
*dd
= d
->dev
;
81 word
class = dd
->device_class
;
82 byte ht
= get_conf_byte(d
, PCI_HEADER_TYPE
) & 0x7f;
83 if ((class >> 8) == PCI_BASE_CLASS_BRIDGE
&&
84 (ht
== PCI_HEADER_TYPE_BRIDGE
|| ht
== PCI_HEADER_TYPE_CARDBUS
))
86 b
= xmalloc(sizeof(struct bridge
));
87 b
->domain
= dd
->domain
;
88 if (ht
== PCI_HEADER_TYPE_BRIDGE
)
90 b
->primary
= get_conf_byte(d
, PCI_PRIMARY_BUS
);
91 b
->secondary
= get_conf_byte(d
, PCI_SECONDARY_BUS
);
92 b
->subordinate
= get_conf_byte(d
, PCI_SUBORDINATE_BUS
);
96 b
->primary
= get_conf_byte(d
, PCI_CB_PRIMARY_BUS
);
97 b
->secondary
= get_conf_byte(d
, PCI_CB_CARD_BUS
);
98 b
->subordinate
= get_conf_byte(d
, PCI_CB_SUBORDINATE_BUS
);
102 b
->next
= b
->child
= NULL
;
106 pacc
->debug("Tree: bridge %04x:%02x:%02x.%d: %02x -> %02x-%02x\n",
107 dd
->domain
, dd
->bus
, dd
->dev
, dd
->func
,
108 b
->primary
, b
->secondary
, b
->subordinate
);
113 /* Create a bridge tree */
115 for (b
=&host_bridge
; b
; b
=b
->chain
)
117 struct bridge
*c
, *best
;
119 for (c
=&host_bridge
; c
; c
=c
->chain
)
120 if (c
!= b
&& (c
== &host_bridge
|| b
->domain
== c
->domain
) &&
121 b
->primary
>= c
->secondary
&& b
->primary
<= c
->subordinate
&&
122 (!best
|| best
->subordinate
- best
->primary
> c
->subordinate
- c
->primary
))
126 b
->next
= best
->child
;
131 /* Insert secondary bus for each bridge */
133 for (b
=&host_bridge
; b
; b
=b
->chain
)
134 if (!find_bus(b
, b
->domain
, b
->secondary
))
135 new_bus(b
, b
->domain
, b
->secondary
);
137 /* Create bus structs and link devices */
139 for (d
=first_dev
; d
; d
=d
->next
)
140 insert_dev(d
, &host_bridge
);
144 print_it(char *line
, char *p
)
149 for (p
=line
; *p
; p
++)
150 if (*p
== '+' || *p
== '|')
156 static void show_tree_bridge(struct bridge
*, char *, char *);
158 #define LINE_BUF_SIZE 1024
160 static char * FORMAT_CHECK(printf
, 3, 4)
161 tree_printf(char *line
, char *p
, char *fmt
, ...)
164 char *end
= line
+ LINE_BUF_SIZE
- 2;
170 int res
= vsnprintf(p
, end
- p
, fmt
, args
);
173 /* Ancient C libraries return -1 on overflow */
184 show_tree_dev(struct device
*d
, char *line
, char *p
)
186 struct pci_dev
*q
= d
->dev
;
190 p
= tree_printf(line
, p
, "%02x.%x", q
->dev
, q
->func
);
191 for (b
=&host_bridge
; b
; b
=b
->chain
)
194 if (b
->secondary
== b
->subordinate
)
195 p
= tree_printf(line
, p
, "-[%02x]-", b
->secondary
);
197 p
= tree_printf(line
, p
, "-[%02x-%02x]-", b
->secondary
, b
->subordinate
);
198 show_tree_bridge(b
, line
, p
);
202 p
= tree_printf(line
, p
, " %s",
203 pci_lookup_name(pacc
, namebuf
, sizeof(namebuf
),
204 PCI_LOOKUP_VENDOR
| PCI_LOOKUP_DEVICE
,
205 q
->vendor_id
, q
->device_id
));
210 show_tree_bus(struct bus
*b
, char *line
, char *p
)
214 else if (!b
->first_dev
->bus_next
)
216 p
= tree_printf(line
, p
, "--");
217 show_tree_dev(b
->first_dev
, line
, p
);
221 struct device
*d
= b
->first_dev
;
224 char *p2
= tree_printf(line
, p
, "+-");
225 show_tree_dev(d
, line
, p2
);
228 p
= tree_printf(line
, p
, "\\-");
229 show_tree_dev(d
, line
, p
);
234 show_tree_bridge(struct bridge
*b
, char *line
, char *p
)
237 if (!b
->first_bus
->sibling
)
239 if (b
== &host_bridge
)
240 p
= tree_printf(line
, p
, "[%04x:%02x]-", b
->domain
, b
->first_bus
->number
);
241 show_tree_bus(b
->first_bus
, line
, p
);
245 struct bus
*u
= b
->first_bus
;
250 k
= tree_printf(line
, p
, "+-[%04x:%02x]-", u
->domain
, u
->number
);
251 show_tree_bus(u
, line
, k
);
254 k
= tree_printf(line
, p
, "\\-[%04x:%02x]-", u
->domain
, u
->number
);
255 show_tree_bus(u
, line
, k
);
260 show_forest(struct pci_filter
*filter
)
262 char line
[LINE_BUF_SIZE
];
264 show_tree_bridge(&host_bridge
, line
, line
);
268 for (b
=&host_bridge
; b
; b
=b
->chain
)
270 if (b
->br_dev
&& pci_filter_match(filter
, b
->br_dev
->dev
))
272 struct pci_dev
*d
= b
->br_dev
->dev
;
274 p
= tree_printf(line
, p
, "%04x:%02x:", d
->domain_16
, d
->bus
);
275 show_tree_dev(b
->br_dev
, line
, p
);