/*
* The PCI Utilities -- List All PCI Devices
*
- * Copyright (c) 1997--2016 Martin Mares <mj@ucw.cz>
+ * Copyright (c) 1997--2018 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
int verbose; /* Show detailed information */
static int opt_hex; /* Show contents of config space as hexadecimal numbers */
struct pci_filter filter; /* Device filter */
+static int opt_filter; /* Any filter was given */
static int opt_tree; /* Show bus tree */
+static int opt_path; /* Show bridge path */
static int opt_machine; /* Generate machine-readable output */
static int opt_map_mode; /* Bus mapping mode enabled */
static int opt_domains; /* Show domain numbers (0=disabled, 1=auto-detected, 2=requested) */
const char program_name[] = "lspci";
-static char options[] = "nvbxs:d:ti:mgp:qkMDQ" GENERIC_OPTIONS ;
+static char options[] = "nvbxs:d:tPi:mgp:qkMDQ" GENERIC_OPTIONS ;
static char help_msg[] =
"Usage: lspci [<switches>]\n"
"-t\t\tShow bus tree\n"
"\n"
"Display options:\n"
-"-v\t\tBe verbose (-vv for very verbose)\n"
+"-v\t\tBe verbose (-vv or -vvv for higher verbosity)\n"
#ifdef PCI_OS_LINUX
"-k\t\tShow kernel drivers handling each device\n"
#endif
"-xxxx\t\tShow hex-dump of the 4096-byte extended config space (root only)\n"
"-b\t\tBus-centric view (addresses and IRQ's as seen by the bus)\n"
"-D\t\tAlways show domain numbers\n"
+"-P\t\tDisplay bridge path in addition to bus and device number\n"
+"-PP\t\tDisplay bus path in addition to bus and device number\n"
"\n"
"Resolving of device ID's to names:\n"
"-n\t\tShow numeric ID's\n"
struct pci_access *pacc;
struct device *first_dev;
static int seen_errors;
+static int need_topology;
int
config_fetch(struct device *d, unsigned int pos, unsigned int len)
if (p->domain && !opt_domains)
opt_domains = 1;
- if (!pci_filter_match(&filter, p))
+ if (!pci_filter_match(&filter, p) && !need_topology)
return NULL;
d = xmalloc(sizeof(struct device));
memset(d, 0, sizeof(*d));
/*** Normal output ***/
+static void
+show_slot_path(struct device *d)
+{
+ struct pci_dev *p = d->dev;
+
+ if (opt_path)
+ {
+ struct bus *bus = d->parent_bus;
+ struct bridge *br = bus->parent_bridge;
+
+ if (br && br->br_dev)
+ {
+ show_slot_path(br->br_dev);
+ if (opt_path > 1)
+ printf("/%02x:%02x.%d", p->bus, p->dev, p->func);
+ else
+ printf("/%02x.%d", p->dev, p->func);
+ return;
+ }
+ }
+ printf("%02x:%02x.%d", p->bus, p->dev, p->func);
+}
+
static void
show_slot_name(struct device *d)
{
if (!opt_machine ? opt_domains : (p->domain || opt_domains >= 2))
printf("%04x:", p->domain);
- printf("%02x:%02x.%d", p->bus, p->dev, p->func);
+ show_slot_path(d);
}
void
static void
show_range(char *prefix, u64 base, u64 limit, int is_64bit)
{
- if (base > limit)
+ if (base > limit && verbose < 3)
{
- if (!verbose)
- return;
- else if (verbose < 3)
- {
- printf("%s: None\n", prefix);
- return;
- }
+ printf("%s: None\n", prefix);
+ return;
}
-
printf("%s: ", prefix);
if (is_64bit)
printf("%016" PCI_U64_FMT_X "-%016" PCI_U64_FMT_X, base, limit);
struct device *d;
for (d=first_dev; d; d=d->next)
- show_device(d);
+ if (pci_filter_match(&filter, d->dev))
+ show_device(d);
}
/* Main */
case 's':
if (msg = pci_filter_parse_slot(&filter, optarg))
die("-s: %s", msg);
+ opt_filter = 1;
break;
case 'd':
if (msg = pci_filter_parse_id(&filter, optarg))
die("-d: %s", msg);
+ opt_filter = 1;
break;
case 'x':
opt_hex++;
break;
+ case 'P':
+ opt_path++;
+ need_topology = 1;
+ break;
case 't':
opt_tree++;
+ need_topology = 1;
break;
case 'i':
pci_set_name_list_path(pacc, optarg, 0);
pci_init(pacc);
if (opt_map_mode)
- map_the_bus();
+ {
+ if (need_topology)
+ die("Bus mapping mode does not recognize bus topology");
+ map_the_bus();
+ }
else
{
scan_devices();
sort_them();
+ if (need_topology)
+ grow_tree();
if (opt_tree)
- show_forest();
+ show_forest(opt_filter ? &filter : NULL);
else
show();
}