]>
git.ipfire.org Git - thirdparty/pciutils.git/blob - ls-tree.c
2 * The PCI Utilities -- Show Bus Tree
4 * Copyright (c) 1997--2018 Martin Mares <mj@ucw.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL.
14 struct bridge host_bridge
= { NULL
, NULL
, NULL
, NULL
, 0, ~0, 0, ~0, NULL
};
17 find_bus(struct bridge
*b
, unsigned int domain
, unsigned int n
)
21 for (bus
=b
->first_bus
; bus
; bus
=bus
->sibling
)
22 if (bus
->domain
== domain
&& bus
->number
== n
)
28 new_bus(struct bridge
*b
, unsigned int domain
, unsigned int n
)
30 struct bus
*bus
= xmalloc(sizeof(struct bus
));
33 bus
->sibling
= b
->first_bus
;
34 bus
->first_dev
= NULL
;
35 bus
->last_dev
= &bus
->first_dev
;
36 bus
->parent_bridge
= b
;
42 insert_dev(struct device
*d
, struct bridge
*b
)
44 struct pci_dev
*p
= d
->dev
;
47 if (! (bus
= find_bus(b
, p
->domain
, p
->bus
)))
50 for (c
=b
->child
; c
; c
=c
->next
)
51 if (c
->domain
== (unsigned)p
->domain
&& c
->secondary
<= p
->bus
&& p
->bus
<= c
->subordinate
)
56 bus
= new_bus(b
, p
->domain
, p
->bus
);
58 /* Simple insertion at the end _does_ guarantee the correct order as the
59 * original device list was sorted by (domain, bus, devfn) lexicographically
60 * and all devices on the new list have the same bus number.
63 bus
->last_dev
= &d
->bus_next
;
72 struct bridge
**last_br
, *b
;
74 /* Build list of bridges */
76 last_br
= &host_bridge
.chain
;
77 for (d
=first_dev
; d
; d
=d
->next
)
79 struct pci_dev
*dd
= d
->dev
;
80 word
class = dd
->device_class
;
81 byte ht
= get_conf_byte(d
, PCI_HEADER_TYPE
) & 0x7f;
82 if ((class >> 8) == PCI_BASE_CLASS_BRIDGE
&&
83 (ht
== PCI_HEADER_TYPE_BRIDGE
|| ht
== PCI_HEADER_TYPE_CARDBUS
))
85 b
= xmalloc(sizeof(struct bridge
));
86 b
->domain
= dd
->domain
;
87 if (ht
== PCI_HEADER_TYPE_BRIDGE
)
89 b
->primary
= get_conf_byte(d
, PCI_PRIMARY_BUS
);
90 b
->secondary
= get_conf_byte(d
, PCI_SECONDARY_BUS
);
91 b
->subordinate
= get_conf_byte(d
, PCI_SUBORDINATE_BUS
);
95 b
->primary
= get_conf_byte(d
, PCI_CB_PRIMARY_BUS
);
96 b
->secondary
= get_conf_byte(d
, PCI_CB_CARD_BUS
);
97 b
->subordinate
= get_conf_byte(d
, PCI_CB_SUBORDINATE_BUS
);
101 b
->next
= b
->child
= NULL
;
105 pacc
->debug("Tree: bridge %04x:%02x:%02x.%d: %02x -> %02x-%02x\n",
106 dd
->domain
, dd
->bus
, dd
->dev
, dd
->func
,
107 b
->primary
, b
->secondary
, b
->subordinate
);
112 /* Create a bridge tree */
114 for (b
=&host_bridge
; b
; b
=b
->chain
)
116 struct bridge
*c
, *best
;
118 for (c
=&host_bridge
; c
; c
=c
->chain
)
119 if (c
!= b
&& (c
== &host_bridge
|| b
->domain
== c
->domain
) &&
120 b
->primary
>= c
->secondary
&& b
->primary
<= c
->subordinate
&&
121 (!best
|| best
->subordinate
- best
->primary
> c
->subordinate
- c
->primary
))
125 b
->next
= best
->child
;
130 /* Insert secondary bus for each bridge */
132 for (b
=&host_bridge
; b
; b
=b
->chain
)
133 if (!find_bus(b
, b
->domain
, b
->secondary
))
134 new_bus(b
, b
->domain
, b
->secondary
);
136 /* Create bus structs and link devices */
138 for (d
=first_dev
; d
; d
=d
->next
)
139 insert_dev(d
, &host_bridge
);
143 print_it(char *line
, char *p
)
148 for (p
=line
; *p
; p
++)
149 if (*p
== '+' || *p
== '|')
155 static void show_tree_bridge(struct bridge
*, char *, char *);
158 show_tree_dev(struct device
*d
, char *line
, char *p
)
160 struct pci_dev
*q
= d
->dev
;
164 p
+= sprintf(p
, "%02x.%x", q
->dev
, q
->func
);
165 for (b
=&host_bridge
; b
; b
=b
->chain
)
168 if (b
->secondary
== b
->subordinate
)
169 p
+= sprintf(p
, "-[%02x]-", b
->secondary
);
171 p
+= sprintf(p
, "-[%02x-%02x]-", b
->secondary
, b
->subordinate
);
172 show_tree_bridge(b
, line
, p
);
176 p
+= sprintf(p
, " %s",
177 pci_lookup_name(pacc
, namebuf
, sizeof(namebuf
),
178 PCI_LOOKUP_VENDOR
| PCI_LOOKUP_DEVICE
,
179 q
->vendor_id
, q
->device_id
));
184 show_tree_bus(struct bus
*b
, char *line
, char *p
)
188 else if (!b
->first_dev
->bus_next
)
192 show_tree_dev(b
->first_dev
, line
, p
);
196 struct device
*d
= b
->first_dev
;
201 show_tree_dev(d
, line
, p
+2);
206 show_tree_dev(d
, line
, p
+2);
211 show_tree_bridge(struct bridge
*b
, char *line
, char *p
)
214 if (!b
->first_bus
->sibling
)
216 if (b
== &host_bridge
)
217 p
+= sprintf(p
, "[%04x:%02x]-", b
->domain
, b
->first_bus
->number
);
218 show_tree_bus(b
->first_bus
, line
, p
);
222 struct bus
*u
= b
->first_bus
;
227 k
= p
+ sprintf(p
, "+-[%04x:%02x]-", u
->domain
, u
->number
);
228 show_tree_bus(u
, line
, k
);
231 k
= p
+ sprintf(p
, "\\-[%04x:%02x]-", u
->domain
, u
->number
);
232 show_tree_bus(u
, line
, k
);
237 show_forest(struct pci_filter
*filter
)
241 show_tree_bridge(&host_bridge
, line
, line
);
245 for (b
=&host_bridge
; b
; b
=b
->chain
)
247 if (b
->br_dev
&& pci_filter_match(filter
, b
->br_dev
->dev
))
249 struct pci_dev
*d
= b
->br_dev
->dev
;
251 p
+= sprintf(line
, "%04x:%02x:", d
->domain_16
, d
->bus
);
252 show_tree_dev(b
->br_dev
, line
, p
);