198e39e09SMartin Mares /*
24284af58SMartin Mares * The PCI Utilities -- List All PCI Devices
398e39e09SMartin Mares *
4bf72d3e9SMartin Mares * Copyright (c) 1997--2020 Martin Mares <[email protected]>
598e39e09SMartin Mares *
661829219SMartin Mares * Can be freely distributed and used under the terms of the GNU GPL v2+.
761829219SMartin Mares *
861829219SMartin Mares * SPDX-License-Identifier: GPL-2.0-or-later
998e39e09SMartin Mares */
1098e39e09SMartin Mares
1198e39e09SMartin Mares #include <stdio.h>
1298e39e09SMartin Mares #include <string.h>
1398e39e09SMartin Mares #include <stdlib.h>
14727ce158SMartin Mares #include <stdarg.h>
1598e39e09SMartin Mares
16c7a34993SMartin Mares #include "lspci.h"
1798e39e09SMartin Mares
1898e39e09SMartin Mares /* Options */
1998e39e09SMartin Mares
20c7a34993SMartin Mares int verbose; /* Show detailed information */
21a387042eSMartin Mares static int opt_hex; /* Show contents of config space as hexadecimal numbers */
22c7a34993SMartin Mares struct pci_filter filter; /* Device filter */
23ce22dfecSMartin Mares static int opt_filter; /* Any filter was given */
24a387042eSMartin Mares static int opt_tree; /* Show bus tree */
2562e78fa6SMartin Mares static int opt_path; /* Show bridge path */
26a387042eSMartin Mares static int opt_machine; /* Generate machine-readable output */
27a387042eSMartin Mares static int opt_map_mode; /* Bus mapping mode enabled */
28a387042eSMartin Mares static int opt_domains; /* Show domain numbers (0=disabled, 1=auto-detected, 2=requested) */
2911339c0dSMartin Mares static int opt_kernel; /* Show kernel drivers */
30cca2f7c6SMartin Mares static int opt_query_dns; /* Query the DNS (0=disabled, 1=enabled, 2=refresh cache) */
31cca2f7c6SMartin Mares static int opt_query_all; /* Query the DNS for all entries */
32c7a34993SMartin Mares char *opt_pcimap; /* Override path to Linux modules.pcimap */
3398e39e09SMartin Mares
3481afa98cSMartin Mares const char program_name[] = "lspci";
3581afa98cSMartin Mares
3662e78fa6SMartin Mares static char options[] = "nvbxs:d:tPi:mgp:qkMDQ" GENERIC_OPTIONS ;
3798e39e09SMartin Mares
38cca2f7c6SMartin Mares static char help_msg[] =
39cca2f7c6SMartin Mares "Usage: lspci [<switches>]\n"
40cca2f7c6SMartin Mares "\n"
411b99a704SMartin Mares "Basic display modes:\n"
421b99a704SMartin Mares "-mm\t\tProduce machine-readable output (single -m for an obsolete format)\n"
431b99a704SMartin Mares "-t\t\tShow bus tree\n"
441b99a704SMartin Mares "\n"
451b99a704SMartin Mares "Display options:\n"
46c5751fb0SKelsey Skunberg "-v\t\tBe verbose (-vv or -vvv for higher verbosity)\n"
471b99a704SMartin Mares #ifdef PCI_OS_LINUX
481b99a704SMartin Mares "-k\t\tShow kernel drivers handling each device\n"
491b99a704SMartin Mares #endif
501b99a704SMartin Mares "-x\t\tShow hex-dump of the standard part of the config space\n"
511b99a704SMartin Mares "-xxx\t\tShow hex-dump of the whole config space (dangerous; root only)\n"
521b99a704SMartin Mares "-xxxx\t\tShow hex-dump of the 4096-byte extended config space (root only)\n"
531b99a704SMartin Mares "-b\t\tBus-centric view (addresses and IRQ's as seen by the bus)\n"
541b99a704SMartin Mares "-D\t\tAlways show domain numbers\n"
5562e78fa6SMartin Mares "-P\t\tDisplay bridge path in addition to bus and device number\n"
5662e78fa6SMartin Mares "-PP\t\tDisplay bus path in addition to bus and device number\n"
571b99a704SMartin Mares "\n"
581b99a704SMartin Mares "Resolving of device ID's to names:\n"
59cca2f7c6SMartin Mares "-n\t\tShow numeric ID's\n"
60cca2f7c6SMartin Mares "-nn\t\tShow both textual and numeric ID's (names & numbers)\n"
61cca2f7c6SMartin Mares #ifdef PCI_USE_DNS
62cca2f7c6SMartin Mares "-q\t\tQuery the PCI ID database for unknown ID's via DNS\n"
63cca2f7c6SMartin Mares "-qq\t\tAs above, but re-query locally cached entries\n"
64cca2f7c6SMartin Mares "-Q\t\tQuery the PCI ID database for all ID's via DNS\n"
65c1c952d2SMartin Mares #endif
661b99a704SMartin Mares "\n"
671b99a704SMartin Mares "Selection of devices:\n"
68cca2f7c6SMartin Mares "-s [[[[<domain>]:]<bus>]:][<slot>][.[<func>]]\tShow only devices in selected slots\n"
694d1c9525SMatthew Wilcox "-d [<vendor>]:[<device>][:<class>]\t\tShow only devices with specified ID's\n"
701b99a704SMartin Mares "\n"
711b99a704SMartin Mares "Other options:\n"
72cca2f7c6SMartin Mares "-i <file>\tUse specified ID database instead of %s\n"
73cca2f7c6SMartin Mares #ifdef PCI_OS_LINUX
74cca2f7c6SMartin Mares "-p <file>\tLook up kernel modules in a given file instead of default modules.pcimap\n"
75cca2f7c6SMartin Mares #endif
76cca2f7c6SMartin Mares "-M\t\tEnable `bus mapping' mode (dangerous; root only)\n"
771b99a704SMartin Mares "\n"
781b99a704SMartin Mares "PCI access options:\n"
79727ce158SMartin Mares GENERIC_HELP
80727ce158SMartin Mares ;
8198e39e09SMartin Mares
82a387042eSMartin Mares /*** Our view of the PCI bus ***/
8398e39e09SMartin Mares
84c7a34993SMartin Mares struct pci_access *pacc;
85c7a34993SMartin Mares struct device *first_dev;
86934e7e36SMartin Mares static int seen_errors;
87ce22dfecSMartin Mares static int need_topology;
8898e39e09SMartin Mares
89c7a34993SMartin Mares int
config_fetch(struct device * d,unsigned int pos,unsigned int len)90ec25b52dSMartin Mares config_fetch(struct device *d, unsigned int pos, unsigned int len)
91ec25b52dSMartin Mares {
92ec25b52dSMartin Mares unsigned int end = pos+len;
93ec25b52dSMartin Mares int result;
9484d437d6SMartin Mares
9584d437d6SMartin Mares while (pos < d->config_bufsize && len && d->present[pos])
9684d437d6SMartin Mares pos++, len--;
9784d437d6SMartin Mares while (pos+len <= d->config_bufsize && len && d->present[pos+len-1])
9884d437d6SMartin Mares len--;
9984d437d6SMartin Mares if (!len)
100ec25b52dSMartin Mares return 1;
10184d437d6SMartin Mares
102ec25b52dSMartin Mares if (end > d->config_bufsize)
103ec25b52dSMartin Mares {
10484d437d6SMartin Mares int orig_size = d->config_bufsize;
105ec25b52dSMartin Mares while (end > d->config_bufsize)
106ec25b52dSMartin Mares d->config_bufsize *= 2;
107ec25b52dSMartin Mares d->config = xrealloc(d->config, d->config_bufsize);
10884d437d6SMartin Mares d->present = xrealloc(d->present, d->config_bufsize);
1091ac3a99dSMartin Mares memset(d->present + orig_size, 0, d->config_bufsize - orig_size);
1100ce6ff4aSNikita Proshkin pci_setup_cache(d->dev, d->config, d->dev->cache_len);
111ec25b52dSMartin Mares }
112ec25b52dSMartin Mares result = pci_read_block(d->dev, pos, d->config + pos, len);
11384d437d6SMartin Mares if (result)
11484d437d6SMartin Mares memset(d->present + pos, 1, len);
115ec25b52dSMartin Mares return result;
116ec25b52dSMartin Mares }
117ec25b52dSMartin Mares
118c7a34993SMartin Mares struct device *
scan_device(struct pci_dev * p)1191812a795SMartin Mares scan_device(struct pci_dev *p)
12098e39e09SMartin Mares {
1211812a795SMartin Mares struct device *d;
12298e39e09SMartin Mares
123a387042eSMartin Mares if (p->domain && !opt_domains)
124a387042eSMartin Mares opt_domains = 1;
125ce22dfecSMartin Mares if (!pci_filter_match(&filter, p) && !need_topology)
1261812a795SMartin Mares return NULL;
127727ce158SMartin Mares d = xmalloc(sizeof(struct device));
1281ac3a99dSMartin Mares memset(d, 0, sizeof(*d));
129727ce158SMartin Mares d->dev = p;
130832b07a8SPali Rohár d->no_config_access = p->no_config_access;
13184d437d6SMartin Mares d->config_cached = d->config_bufsize = 64;
132ec25b52dSMartin Mares d->config = xmalloc(64);
13384d437d6SMartin Mares d->present = xmalloc(64);
13484d437d6SMartin Mares memset(d->present, 1, 64);
135832b07a8SPali Rohár if (!d->no_config_access && !pci_read_block(p, 0, d->config, 64))
136934e7e36SMartin Mares {
137832b07a8SPali Rohár d->no_config_access = 1;
138832b07a8SPali Rohár d->config_cached = d->config_bufsize = 0;
139832b07a8SPali Rohár memset(d->present, 0, 64);
140934e7e36SMartin Mares }
141832b07a8SPali Rohár if (!d->no_config_access && (d->config[PCI_HEADER_TYPE] & 0x7f) == PCI_HEADER_TYPE_CARDBUS)
14298e39e09SMartin Mares {
143ec25b52dSMartin Mares /* For cardbus bridges, we need to fetch 64 bytes more to get the
144ec25b52dSMartin Mares * full standard header... */
14584d437d6SMartin Mares if (config_fetch(d, 64, 64))
14684d437d6SMartin Mares d->config_cached += 64;
14798e39e09SMartin Mares }
14884d437d6SMartin Mares pci_setup_cache(p, d->config, d->config_cached);
14967954c8bSPali Rohár pci_fill_info(p, PCI_FILL_IDENT | PCI_FILL_CLASS | PCI_FILL_CLASS_EXT | PCI_FILL_SUBSYS | (need_topology ? PCI_FILL_PARENT : 0));
1501812a795SMartin Mares return d;
1511812a795SMartin Mares }
1521812a795SMartin Mares
1531812a795SMartin Mares static void
scan_devices(void)1541812a795SMartin Mares scan_devices(void)
1551812a795SMartin Mares {
1561812a795SMartin Mares struct device *d;
1571812a795SMartin Mares struct pci_dev *p;
1581812a795SMartin Mares
1591812a795SMartin Mares pci_scan_bus(pacc);
1601812a795SMartin Mares for (p=pacc->devices; p; p=p->next)
1611812a795SMartin Mares if (d = scan_device(p))
1621812a795SMartin Mares {
1631812a795SMartin Mares d->next = first_dev;
1641812a795SMartin Mares first_dev = d;
16598e39e09SMartin Mares }
16698e39e09SMartin Mares }
16798e39e09SMartin Mares
168a387042eSMartin Mares /*** Config space accesses ***/
16998e39e09SMartin Mares
17084d437d6SMartin Mares static void
check_conf_range(struct device * d,unsigned int pos,unsigned int len)17184d437d6SMartin Mares check_conf_range(struct device *d, unsigned int pos, unsigned int len)
17284d437d6SMartin Mares {
17384d437d6SMartin Mares while (len)
17484d437d6SMartin Mares if (!d->present[pos])
17584d437d6SMartin Mares die("Internal bug: Accessing non-read configuration byte at position %x", pos);
17684d437d6SMartin Mares else
17784d437d6SMartin Mares pos++, len--;
17884d437d6SMartin Mares }
17984d437d6SMartin Mares
180c7a34993SMartin Mares byte
get_conf_byte(struct device * d,unsigned int pos)18198e39e09SMartin Mares get_conf_byte(struct device *d, unsigned int pos)
18298e39e09SMartin Mares {
18384d437d6SMartin Mares check_conf_range(d, pos, 1);
18498e39e09SMartin Mares return d->config[pos];
18598e39e09SMartin Mares }
18698e39e09SMartin Mares
187c7a34993SMartin Mares word
get_conf_word(struct device * d,unsigned int pos)18898e39e09SMartin Mares get_conf_word(struct device *d, unsigned int pos)
18998e39e09SMartin Mares {
19084d437d6SMartin Mares check_conf_range(d, pos, 2);
19198e39e09SMartin Mares return d->config[pos] | (d->config[pos+1] << 8);
19298e39e09SMartin Mares }
19398e39e09SMartin Mares
194c7a34993SMartin Mares u32
get_conf_long(struct device * d,unsigned int pos)19598e39e09SMartin Mares get_conf_long(struct device *d, unsigned int pos)
19698e39e09SMartin Mares {
19784d437d6SMartin Mares check_conf_range(d, pos, 4);
19898e39e09SMartin Mares return d->config[pos] |
19998e39e09SMartin Mares (d->config[pos+1] << 8) |
20098e39e09SMartin Mares (d->config[pos+2] << 16) |
20198e39e09SMartin Mares (d->config[pos+3] << 24);
20298e39e09SMartin Mares }
20398e39e09SMartin Mares
204a387042eSMartin Mares /*** Sorting ***/
20598e39e09SMartin Mares
20698e39e09SMartin Mares static int
compare_them(const void * A,const void * B)20798e39e09SMartin Mares compare_them(const void *A, const void *B)
20898e39e09SMartin Mares {
209727ce158SMartin Mares const struct pci_dev *a = (*(const struct device **)A)->dev;
210727ce158SMartin Mares const struct pci_dev *b = (*(const struct device **)B)->dev;
21198e39e09SMartin Mares
21284c8d1bbSMartin Mares if (a->domain < b->domain)
21384c8d1bbSMartin Mares return -1;
21484c8d1bbSMartin Mares if (a->domain > b->domain)
21584c8d1bbSMartin Mares return 1;
21698e39e09SMartin Mares if (a->bus < b->bus)
21798e39e09SMartin Mares return -1;
21898e39e09SMartin Mares if (a->bus > b->bus)
21998e39e09SMartin Mares return 1;
220727ce158SMartin Mares if (a->dev < b->dev)
22198e39e09SMartin Mares return -1;
222727ce158SMartin Mares if (a->dev > b->dev)
223727ce158SMartin Mares return 1;
224727ce158SMartin Mares if (a->func < b->func)
225727ce158SMartin Mares return -1;
226727ce158SMartin Mares if (a->func > b->func)
22798e39e09SMartin Mares return 1;
22898e39e09SMartin Mares return 0;
22998e39e09SMartin Mares }
23098e39e09SMartin Mares
23198e39e09SMartin Mares static void
sort_them(void)23298e39e09SMartin Mares sort_them(void)
23398e39e09SMartin Mares {
234727ce158SMartin Mares struct device **index, **h, **last_dev;
23598e39e09SMartin Mares int cnt;
23698e39e09SMartin Mares struct device *d;
23798e39e09SMartin Mares
23898e39e09SMartin Mares cnt = 0;
23998e39e09SMartin Mares for (d=first_dev; d; d=d->next)
24098e39e09SMartin Mares cnt++;
24198e39e09SMartin Mares h = index = alloca(sizeof(struct device *) * cnt);
24298e39e09SMartin Mares for (d=first_dev; d; d=d->next)
24398e39e09SMartin Mares *h++ = d;
24498e39e09SMartin Mares qsort(index, cnt, sizeof(struct device *), compare_them);
24598e39e09SMartin Mares last_dev = &first_dev;
24698e39e09SMartin Mares h = index;
24798e39e09SMartin Mares while (cnt--)
24898e39e09SMartin Mares {
24998e39e09SMartin Mares *last_dev = *h;
25098e39e09SMartin Mares last_dev = &(*h)->next;
25198e39e09SMartin Mares h++;
25298e39e09SMartin Mares }
25398e39e09SMartin Mares *last_dev = NULL;
25498e39e09SMartin Mares }
25598e39e09SMartin Mares
256a387042eSMartin Mares /*** Normal output ***/
25798e39e09SMartin Mares
25898e39e09SMartin Mares static void
show_slot_path(struct device * d)25962e78fa6SMartin Mares show_slot_path(struct device *d)
26062e78fa6SMartin Mares {
26162e78fa6SMartin Mares struct pci_dev *p = d->dev;
26262e78fa6SMartin Mares
26362e78fa6SMartin Mares if (opt_path)
26462e78fa6SMartin Mares {
26562e78fa6SMartin Mares struct bus *bus = d->parent_bus;
26662e78fa6SMartin Mares struct bridge *br = bus->parent_bridge;
26762e78fa6SMartin Mares
26862e78fa6SMartin Mares if (br && br->br_dev)
26962e78fa6SMartin Mares {
27062e78fa6SMartin Mares show_slot_path(br->br_dev);
27162e78fa6SMartin Mares if (opt_path > 1)
27262e78fa6SMartin Mares printf("/%02x:%02x.%d", p->bus, p->dev, p->func);
27362e78fa6SMartin Mares else
27462e78fa6SMartin Mares printf("/%02x.%d", p->dev, p->func);
27562e78fa6SMartin Mares return;
27662e78fa6SMartin Mares }
27762e78fa6SMartin Mares }
27862e78fa6SMartin Mares printf("%02x:%02x.%d", p->bus, p->dev, p->func);
27962e78fa6SMartin Mares }
28062e78fa6SMartin Mares
28162e78fa6SMartin Mares static void
show_slot_name(struct device * d)28284c8d1bbSMartin Mares show_slot_name(struct device *d)
28384c8d1bbSMartin Mares {
28484c8d1bbSMartin Mares struct pci_dev *p = d->dev;
28584c8d1bbSMartin Mares
286a387042eSMartin Mares if (!opt_machine ? opt_domains : (p->domain || opt_domains >= 2))
28784c8d1bbSMartin Mares printf("%04x:", p->domain);
28862e78fa6SMartin Mares show_slot_path(d);
28984c8d1bbSMartin Mares }
29084c8d1bbSMartin Mares
29115841b0aSMartin Mares static void
show_terse(struct device * d)29298e39e09SMartin Mares show_terse(struct device *d)
29398e39e09SMartin Mares {
29498e39e09SMartin Mares int c;
295727ce158SMartin Mares struct pci_dev *p = d->dev;
2966e766463SMartin Mares char classbuf[256], devbuf[256];
29798e39e09SMartin Mares
29884c8d1bbSMartin Mares show_slot_name(d);
29984c8d1bbSMartin Mares printf(" %s: %s",
300727ce158SMartin Mares pci_lookup_name(pacc, classbuf, sizeof(classbuf),
301727ce158SMartin Mares PCI_LOOKUP_CLASS,
302c2b144efSMartin Mares p->device_class),
303727ce158SMartin Mares pci_lookup_name(pacc, devbuf, sizeof(devbuf),
304727ce158SMartin Mares PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
305224707baSMartin Mares p->vendor_id, p->device_id));
306fb570ee3SPali Rohár if ((p->known_fields & PCI_FILL_CLASS_EXT) && p->rev_id)
307fb570ee3SPali Rohár printf(" (rev %02x)", p->rev_id);
3088d047897SMartin Mares if (verbose)
309d4798a32SMartin Mares {
3108d047897SMartin Mares char *x;
311fb570ee3SPali Rohár c = (p->known_fields & PCI_FILL_CLASS_EXT) ? p->prog_if : 0;
3128d047897SMartin Mares x = pci_lookup_name(pacc, devbuf, sizeof(devbuf),
313aeaca5d3SMartin Mares PCI_LOOKUP_PROGIF | PCI_LOOKUP_NO_NUMBERS,
314c2b144efSMartin Mares p->device_class, c);
3158d047897SMartin Mares if (c || x)
3168d047897SMartin Mares {
317d4798a32SMartin Mares printf(" (prog-if %02x", c);
318d4798a32SMartin Mares if (x)
319d4798a32SMartin Mares printf(" [%s]", x);
320d4798a32SMartin Mares putchar(')');
321d4798a32SMartin Mares }
3228d047897SMartin Mares }
32398e39e09SMartin Mares putchar('\n');
32498e39e09SMartin Mares
32515841b0aSMartin Mares if (verbose || opt_kernel)
326c1c952d2SMartin Mares {
32715841b0aSMartin Mares char ssnamebuf[256];
328c1c952d2SMartin Mares
3292a39bc9eSViktor Prutyanov pci_fill_info(p, PCI_FILL_LABEL);
3302a39bc9eSViktor Prutyanov
331aecf5b35SThomas Renninger if (p->label)
332aecf5b35SThomas Renninger printf("\tDeviceName: %s", p->label);
333fb570ee3SPali Rohár if ((p->known_fields & PCI_FILL_SUBSYS) &&
334fb570ee3SPali Rohár p->subsys_vendor_id && p->subsys_vendor_id != 0xffff)
33515841b0aSMartin Mares printf("\tSubsystem: %s\n",
33615841b0aSMartin Mares pci_lookup_name(pacc, ssnamebuf, sizeof(ssnamebuf),
33715841b0aSMartin Mares PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
338fb570ee3SPali Rohár p->vendor_id, p->device_id, p->subsys_vendor_id, p->subsys_id));
339c1c952d2SMartin Mares }
340c1c952d2SMartin Mares }
341c1c952d2SMartin Mares
342a387042eSMartin Mares /*** Verbose output ***/
343a387042eSMartin Mares
344a387042eSMartin Mares static void
show_size(u64 x)34541d883cbSMartin Mares show_size(u64 x)
346a387042eSMartin Mares {
3470188807cSMartin Mares static const char suffix[][2] = { "", "K", "M", "G", "T" };
348f2f8adaaSMatthew Wilcox unsigned i;
349a387042eSMartin Mares if (!x)
350a387042eSMartin Mares return;
351f2f8adaaSMatthew Wilcox for (i = 0; i < (sizeof(suffix) / sizeof(*suffix) - 1); i++) {
352558f736bSSean O. Stalley if (x % 1024)
353f2f8adaaSMatthew Wilcox break;
354f2f8adaaSMatthew Wilcox x /= 1024;
355f2f8adaaSMatthew Wilcox }
356f2f8adaaSMatthew Wilcox printf(" [size=%u%s]", (unsigned)x, suffix[i]);
357a387042eSMartin Mares }
358a387042eSMartin Mares
359a387042eSMartin Mares static void
show_range(const char * prefix,u64 base,u64 limit,int bits,int disabled)36072cabfbbSPali Rohár show_range(const char *prefix, u64 base, u64 limit, int bits, int disabled)
36141d883cbSMartin Mares {
36241d883cbSMartin Mares printf("%s:", prefix);
363e6b0b6e1SKelsey Skunberg if (base <= limit || verbose > 2)
3643b26eaa8SPali Rohár printf(" %0*" PCI_U64_FMT_X "-%0*" PCI_U64_FMT_X, (bits+3)/4, base, (bits+3)/4, limit);
365ccf68033SPali Rohár if (!disabled && base <= limit)
36641d883cbSMartin Mares show_size(limit - base + 1);
36741d883cbSMartin Mares else
368e6b0b6e1SKelsey Skunberg printf(" [disabled]");
36972cabfbbSPali Rohár if (bits)
37066a85e51SPali Rohár printf(" [%d-bit]", bits);
37141d883cbSMartin Mares putchar('\n');
37241d883cbSMartin Mares }
37341d883cbSMartin Mares
37472cabfbbSPali Rohár static u32
ioflg_to_pciflg(pciaddr_t ioflg)37572cabfbbSPali Rohár ioflg_to_pciflg(pciaddr_t ioflg)
37672cabfbbSPali Rohár {
37772cabfbbSPali Rohár u32 flg;
37872cabfbbSPali Rohár
37972cabfbbSPali Rohár if (ioflg & PCI_IORESOURCE_IO)
38072cabfbbSPali Rohár flg = PCI_BASE_ADDRESS_SPACE_IO;
38172cabfbbSPali Rohár else if (!(ioflg & PCI_IORESOURCE_MEM))
38272cabfbbSPali Rohár flg = 0;
38372cabfbbSPali Rohár else
38472cabfbbSPali Rohár {
38572cabfbbSPali Rohár flg = PCI_BASE_ADDRESS_SPACE_MEMORY;
38672cabfbbSPali Rohár if (ioflg & PCI_IORESOURCE_MEM_64)
38772cabfbbSPali Rohár flg |= PCI_BASE_ADDRESS_MEM_TYPE_64;
38872cabfbbSPali Rohár else
38972cabfbbSPali Rohár flg |= PCI_BASE_ADDRESS_MEM_TYPE_32;
39072cabfbbSPali Rohár if (ioflg & PCI_IORESOURCE_PREFETCH)
39172cabfbbSPali Rohár flg |= PCI_BASE_ADDRESS_MEM_PREFETCH;
39272cabfbbSPali Rohár }
39372cabfbbSPali Rohár
39472cabfbbSPali Rohár return flg;
39572cabfbbSPali Rohár }
39672cabfbbSPali Rohár
39741d883cbSMartin Mares static void
show_bases(struct device * d,int cnt,int without_config_data)39872cabfbbSPali Rohár show_bases(struct device *d, int cnt, int without_config_data)
399a387042eSMartin Mares {
400a387042eSMartin Mares struct pci_dev *p = d->dev;
40172cabfbbSPali Rohár word cmd = without_config_data ? (PCI_COMMAND_IO | PCI_COMMAND_MEMORY) : get_conf_word(d, PCI_COMMAND);
402a387042eSMartin Mares int i;
403a387042eSMartin Mares
404a387042eSMartin Mares for (i=0; i<cnt; i++)
405a387042eSMartin Mares {
406a387042eSMartin Mares pciaddr_t pos = p->base_addr[i];
407a387042eSMartin Mares pciaddr_t len = (p->known_fields & PCI_FILL_SIZES) ? p->size[i] : 0;
408558f736bSSean O. Stalley pciaddr_t ioflg = (p->known_fields & PCI_FILL_IO_FLAGS) ? p->flags[i] : 0;
4097f96c3feSPali Rohár u32 flg = (p->known_fields & PCI_FILL_IO_FLAGS) ? ioflg_to_pciflg(ioflg) : without_config_data ? 0 : get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i);
4107f96c3feSPali Rohár u32 hw_lower = 0;
411bf72d3e9SMartin Mares u32 hw_upper = 0;
412bf72d3e9SMartin Mares int broken = 0;
4137f96c3feSPali Rohár int virtual = 0;
414bf72d3e9SMartin Mares
415a387042eSMartin Mares if (flg == 0xffffffff)
416a387042eSMartin Mares flg = 0;
417a387042eSMartin Mares if (!pos && !flg && !len)
418a387042eSMartin Mares continue;
419bf72d3e9SMartin Mares
420a387042eSMartin Mares if (verbose > 1)
421a387042eSMartin Mares printf("\tRegion %d: ", i);
422a387042eSMartin Mares else
423a387042eSMartin Mares putchar('\t');
424bf72d3e9SMartin Mares
4257f96c3feSPali Rohár /* Detect virtual regions, which are reported by the OS, but unassigned in the device */
4267f96c3feSPali Rohár if ((p->known_fields & PCI_FILL_IO_FLAGS) && !without_config_data)
427a387042eSMartin Mares {
4287f96c3feSPali Rohár /* Read address as seen by the hardware */
4297f96c3feSPali Rohár hw_lower = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i);
4307f96c3feSPali Rohár if ((hw_lower & PCI_BASE_ADDRESS_SPACE) == (ioflg_to_pciflg(ioflg) & PCI_BASE_ADDRESS_SPACE))
4317f96c3feSPali Rohár {
4327f96c3feSPali Rohár if ((ioflg & PCI_IORESOURCE_TYPE_BITS) == PCI_IORESOURCE_MEM &&
4337f96c3feSPali Rohár (hw_lower & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64)
434bf72d3e9SMartin Mares {
435bf72d3e9SMartin Mares if (i >= cnt - 1)
436bf72d3e9SMartin Mares broken = 1;
437bf72d3e9SMartin Mares else
4387f96c3feSPali Rohár hw_upper = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i + 1);
439bf72d3e9SMartin Mares }
4407f96c3feSPali Rohár if (pos && !hw_lower && !hw_upper && !(ioflg & PCI_IORESOURCE_PCI_EA_BEI))
441659d438bSYu Zhao virtual = 1;
442a387042eSMartin Mares }
4437f96c3feSPali Rohár }
444bf72d3e9SMartin Mares
445bf72d3e9SMartin Mares /* Print base address */
446a387042eSMartin Mares if (flg & PCI_BASE_ADDRESS_SPACE_IO)
447a387042eSMartin Mares {
448a387042eSMartin Mares pciaddr_t a = pos & PCI_BASE_ADDRESS_IO_MASK;
449a387042eSMartin Mares printf("I/O ports at ");
45000bf6625SAaron Sierra if (a || (cmd & PCI_COMMAND_IO))
451a387042eSMartin Mares printf(PCIADDR_PORT_FMT, a);
452bf72d3e9SMartin Mares else if (hw_lower)
453a387042eSMartin Mares printf("<ignored>");
454a387042eSMartin Mares else
455a387042eSMartin Mares printf("<unassigned>");
456bf72d3e9SMartin Mares if (virtual)
457bf72d3e9SMartin Mares printf(" [virtual]");
458bf72d3e9SMartin Mares else if (!(cmd & PCI_COMMAND_IO))
459a387042eSMartin Mares printf(" [disabled]");
460a387042eSMartin Mares }
461a387042eSMartin Mares else
462a387042eSMartin Mares {
463a387042eSMartin Mares int t = flg & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
464a387042eSMartin Mares pciaddr_t a = pos & PCI_ADDR_MEM_MASK;
465a387042eSMartin Mares
466a387042eSMartin Mares printf("Memory at ");
467bf72d3e9SMartin Mares if (broken)
468bf72d3e9SMartin Mares printf("<broken-64-bit-slot>");
469bf72d3e9SMartin Mares else if (a)
470a387042eSMartin Mares printf(PCIADDR_T_FMT, a);
471bf72d3e9SMartin Mares else if (hw_lower || hw_upper)
472bf72d3e9SMartin Mares printf("<ignored>");
473a387042eSMartin Mares else
474bf72d3e9SMartin Mares printf("<unassigned>");
475a387042eSMartin Mares printf(" (%s, %sprefetchable)",
476a387042eSMartin Mares (t == PCI_BASE_ADDRESS_MEM_TYPE_32) ? "32-bit" :
477a387042eSMartin Mares (t == PCI_BASE_ADDRESS_MEM_TYPE_64) ? "64-bit" :
478a387042eSMartin Mares (t == PCI_BASE_ADDRESS_MEM_TYPE_1M) ? "low-1M" : "type 3",
479a387042eSMartin Mares (flg & PCI_BASE_ADDRESS_MEM_PREFETCH) ? "" : "non-");
480bf72d3e9SMartin Mares if (virtual)
481bf72d3e9SMartin Mares printf(" [virtual]");
482bf72d3e9SMartin Mares else if (!(cmd & PCI_COMMAND_MEMORY))
483a387042eSMartin Mares printf(" [disabled]");
484a387042eSMartin Mares }
485bf72d3e9SMartin Mares
486bf72d3e9SMartin Mares if (ioflg & PCI_IORESOURCE_PCI_EA_BEI)
487bf72d3e9SMartin Mares printf(" [enhanced]");
488bf72d3e9SMartin Mares
489a387042eSMartin Mares show_size(len);
490a387042eSMartin Mares putchar('\n');
491a387042eSMartin Mares }
492a387042eSMartin Mares }
493a387042eSMartin Mares
494a387042eSMartin Mares static void
show_rom(struct device * d,int reg)495a387042eSMartin Mares show_rom(struct device *d, int reg)
496a387042eSMartin Mares {
497a387042eSMartin Mares struct pci_dev *p = d->dev;
498a387042eSMartin Mares pciaddr_t rom = p->rom_base_addr;
499a387042eSMartin Mares pciaddr_t len = (p->known_fields & PCI_FILL_SIZES) ? p->rom_size : 0;
500558f736bSSean O. Stalley pciaddr_t ioflg = (p->known_fields & PCI_FILL_IO_FLAGS) ? p->rom_flags : 0;
50172cabfbbSPali Rohár u32 flg = reg >= 0 ? get_conf_long(d, reg) : ioflg_to_pciflg(ioflg);
50272cabfbbSPali Rohár word cmd = reg >= 0 ? get_conf_word(d, PCI_COMMAND) : PCI_COMMAND_MEMORY;
503659d438bSYu Zhao int virtual = 0;
504a387042eSMartin Mares
505a387042eSMartin Mares if (!rom && !flg && !len)
506a387042eSMartin Mares return;
507cb94f26eSMartin Mares
50872cabfbbSPali Rohár if (reg >= 0 && (rom & PCI_ROM_ADDRESS_MASK) && !(flg & PCI_ROM_ADDRESS_MASK) && !(ioflg & PCI_IORESOURCE_PCI_EA_BEI))
509a387042eSMartin Mares {
510a387042eSMartin Mares flg = rom;
511659d438bSYu Zhao virtual = 1;
512a387042eSMartin Mares }
513cb94f26eSMartin Mares
514cb94f26eSMartin Mares printf("\tExpansion ROM at ");
515a387042eSMartin Mares if (rom & PCI_ROM_ADDRESS_MASK)
516a387042eSMartin Mares printf(PCIADDR_T_FMT, rom & PCI_ROM_ADDRESS_MASK);
517a387042eSMartin Mares else if (flg & PCI_ROM_ADDRESS_MASK)
518a387042eSMartin Mares printf("<ignored>");
519a387042eSMartin Mares else
520a387042eSMartin Mares printf("<unassigned>");
521cb94f26eSMartin Mares
522cb94f26eSMartin Mares if (virtual)
523cb94f26eSMartin Mares printf(" [virtual]");
524cb94f26eSMartin Mares
525a387042eSMartin Mares if (!(flg & PCI_ROM_ADDRESS_ENABLE))
526a387042eSMartin Mares printf(" [disabled]");
527659d438bSYu Zhao else if (!virtual && !(cmd & PCI_COMMAND_MEMORY))
528a387042eSMartin Mares printf(" [disabled by cmd]");
529cb94f26eSMartin Mares
530cb94f26eSMartin Mares if (ioflg & PCI_IORESOURCE_PCI_EA_BEI)
531cb94f26eSMartin Mares printf(" [enhanced]");
532cb94f26eSMartin Mares
533a387042eSMartin Mares show_size(len);
534a387042eSMartin Mares putchar('\n');
535a387042eSMartin Mares }
536a387042eSMartin Mares
53798e39e09SMartin Mares static void
show_htype0(struct device * d)538e95c8373SMartin Mares show_htype0(struct device *d)
539e95c8373SMartin Mares {
54072cabfbbSPali Rohár show_bases(d, 6, 0);
5416aa54f1bSMartin Mares show_rom(d, PCI_ROM_ADDRESS);
54221510591SMatthew Wilcox show_caps(d, PCI_CAPABILITY_LIST);
543e95c8373SMartin Mares }
544e95c8373SMartin Mares
545e95c8373SMartin Mares static void
show_htype1(struct device * d)54698e39e09SMartin Mares show_htype1(struct device *d)
54798e39e09SMartin Mares {
548ccf68033SPali Rohár struct pci_dev *p = d->dev;
54998e39e09SMartin Mares u32 io_base = get_conf_byte(d, PCI_IO_BASE);
55098e39e09SMartin Mares u32 io_limit = get_conf_byte(d, PCI_IO_LIMIT);
55198e39e09SMartin Mares u32 io_type = io_base & PCI_IO_RANGE_TYPE_MASK;
55298e39e09SMartin Mares u32 mem_base = get_conf_word(d, PCI_MEMORY_BASE);
55398e39e09SMartin Mares u32 mem_limit = get_conf_word(d, PCI_MEMORY_LIMIT);
55498e39e09SMartin Mares u32 mem_type = mem_base & PCI_MEMORY_RANGE_TYPE_MASK;
55598e39e09SMartin Mares u32 pref_base = get_conf_word(d, PCI_PREF_MEMORY_BASE);
55698e39e09SMartin Mares u32 pref_limit = get_conf_word(d, PCI_PREF_MEMORY_LIMIT);
55798e39e09SMartin Mares u32 pref_type = pref_base & PCI_PREF_RANGE_TYPE_MASK;
558138c0385SMartin Mares word sec_stat = get_conf_word(d, PCI_SEC_STATUS);
55998e39e09SMartin Mares word brc = get_conf_word(d, PCI_BRIDGE_CONTROL);
560ccf68033SPali Rohár int io_disabled = (p->known_fields & PCI_FILL_BRIDGE_BASES) && !p->bridge_size[0];
561ccf68033SPali Rohár int mem_disabled = (p->known_fields & PCI_FILL_BRIDGE_BASES) && !p->bridge_size[1];
562ccf68033SPali Rohár int pref_disabled = (p->known_fields & PCI_FILL_BRIDGE_BASES) && !p->bridge_size[2];
563ccf68033SPali Rohár int io_bits, pref_bits;
56498e39e09SMartin Mares
56572cabfbbSPali Rohár show_bases(d, 2, 0);
56698e39e09SMartin Mares printf("\tBus: primary=%02x, secondary=%02x, subordinate=%02x, sec-latency=%d\n",
56798e39e09SMartin Mares get_conf_byte(d, PCI_PRIMARY_BUS),
56898e39e09SMartin Mares get_conf_byte(d, PCI_SECONDARY_BUS),
56998e39e09SMartin Mares get_conf_byte(d, PCI_SUBORDINATE_BUS),
57098e39e09SMartin Mares get_conf_byte(d, PCI_SEC_LATENCY_TIMER));
57198e39e09SMartin Mares
572ccf68033SPali Rohár if ((p->known_fields & PCI_FILL_BRIDGE_BASES) && !io_disabled)
573ccf68033SPali Rohár {
574ccf68033SPali Rohár io_base = p->bridge_base_addr[0] & PCI_IO_RANGE_MASK;
575ccf68033SPali Rohár io_limit = io_base + p->bridge_size[0] - 1;
576ccf68033SPali Rohár io_type = p->bridge_base_addr[0] & PCI_IO_RANGE_TYPE_MASK;
577ccf68033SPali Rohár io_bits = (io_type == PCI_IO_RANGE_TYPE_32) ? 32 : 16;
578ccf68033SPali Rohár show_range("\tI/O behind bridge", io_base, io_limit, io_bits, io_disabled);
579ccf68033SPali Rohár }
580ccf68033SPali Rohár else if (io_type != (io_limit & PCI_IO_RANGE_TYPE_MASK) ||
58198e39e09SMartin Mares (io_type != PCI_IO_RANGE_TYPE_16 && io_type != PCI_IO_RANGE_TYPE_32))
58298e39e09SMartin Mares printf("\t!!! Unknown I/O range types %x/%x\n", io_base, io_limit);
58398e39e09SMartin Mares else
58498e39e09SMartin Mares {
58598e39e09SMartin Mares io_base = (io_base & PCI_IO_RANGE_MASK) << 8;
58698e39e09SMartin Mares io_limit = (io_limit & PCI_IO_RANGE_MASK) << 8;
58798e39e09SMartin Mares if (io_type == PCI_IO_RANGE_TYPE_32)
58898e39e09SMartin Mares {
58998e39e09SMartin Mares io_base |= (get_conf_word(d, PCI_IO_BASE_UPPER16) << 16);
59098e39e09SMartin Mares io_limit |= (get_conf_word(d, PCI_IO_LIMIT_UPPER16) << 16);
59198e39e09SMartin Mares }
592ccf68033SPali Rohár /* I/O is unsupported if both base and limit are zeros and resource is disabled */
593ccf68033SPali Rohár if (!(io_base == 0x0 && io_limit == 0x0 && io_disabled))
594ccf68033SPali Rohár {
595ccf68033SPali Rohár io_limit += 0xfff;
596ccf68033SPali Rohár io_bits = (io_type == PCI_IO_RANGE_TYPE_32) ? 32 : 16;
597ccf68033SPali Rohár show_range("\tI/O behind bridge", io_base, io_limit, io_bits, io_disabled);
598ccf68033SPali Rohár }
59998e39e09SMartin Mares }
60098e39e09SMartin Mares
601ccf68033SPali Rohár if ((p->known_fields & PCI_FILL_BRIDGE_BASES) && !mem_disabled)
602ccf68033SPali Rohár {
603ccf68033SPali Rohár mem_base = p->bridge_base_addr[1] & PCI_MEMORY_RANGE_MASK;
604ccf68033SPali Rohár mem_limit = mem_base + p->bridge_size[1] - 1;
605ccf68033SPali Rohár show_range("\tMemory behind bridge", mem_base, mem_limit, 32, mem_disabled);
606ccf68033SPali Rohár }
607ccf68033SPali Rohár else if (mem_type != (mem_limit & PCI_MEMORY_RANGE_TYPE_MASK) ||
60898e39e09SMartin Mares mem_type)
60998e39e09SMartin Mares printf("\t!!! Unknown memory range types %x/%x\n", mem_base, mem_limit);
610e306e911SMartin Mares else
61198e39e09SMartin Mares {
61298e39e09SMartin Mares mem_base = (mem_base & PCI_MEMORY_RANGE_MASK) << 16;
61398e39e09SMartin Mares mem_limit = (mem_limit & PCI_MEMORY_RANGE_MASK) << 16;
614ccf68033SPali Rohár show_range("\tMemory behind bridge", mem_base, mem_limit + 0xfffff, 32, mem_disabled);
61598e39e09SMartin Mares }
61698e39e09SMartin Mares
617ccf68033SPali Rohár if ((p->known_fields & PCI_FILL_BRIDGE_BASES) && !pref_disabled)
618ccf68033SPali Rohár {
619ccf68033SPali Rohár u64 pref_base_64 = p->bridge_base_addr[2] & PCI_MEMORY_RANGE_MASK;
620ccf68033SPali Rohár u64 pref_limit_64 = pref_base_64 + p->bridge_size[2] - 1;
621ccf68033SPali Rohár pref_type = p->bridge_base_addr[2] & PCI_MEMORY_RANGE_TYPE_MASK;
622ccf68033SPali Rohár pref_bits = (pref_type == PCI_PREF_RANGE_TYPE_64) ? 64 : 32;
623ccf68033SPali Rohár show_range("\tPrefetchable memory behind bridge", pref_base_64, pref_limit_64, pref_bits, pref_disabled);
624ccf68033SPali Rohár }
625ccf68033SPali Rohár else if (pref_type != (pref_limit & PCI_PREF_RANGE_TYPE_MASK) ||
62698e39e09SMartin Mares (pref_type != PCI_PREF_RANGE_TYPE_32 && pref_type != PCI_PREF_RANGE_TYPE_64))
62798e39e09SMartin Mares printf("\t!!! Unknown prefetchable memory range types %x/%x\n", pref_base, pref_limit);
628e306e911SMartin Mares else
62998e39e09SMartin Mares {
63041d883cbSMartin Mares u64 pref_base_64 = (pref_base & PCI_PREF_RANGE_MASK) << 16;
63141d883cbSMartin Mares u64 pref_limit_64 = (pref_limit & PCI_PREF_RANGE_MASK) << 16;
63241d883cbSMartin Mares if (pref_type == PCI_PREF_RANGE_TYPE_64)
633e306e911SMartin Mares {
63441d883cbSMartin Mares pref_base_64 |= (u64) get_conf_long(d, PCI_PREF_BASE_UPPER32) << 32;
63541d883cbSMartin Mares pref_limit_64 |= (u64) get_conf_long(d, PCI_PREF_LIMIT_UPPER32) << 32;
63698e39e09SMartin Mares }
637ccf68033SPali Rohár /* Prefetchable memory is unsupported if both base and limit are zeros and resource is disabled */
638ccf68033SPali Rohár if (!(pref_base_64 == 0x0 && pref_limit_64 == 0x0 && pref_disabled))
639ccf68033SPali Rohár {
640ccf68033SPali Rohár pref_limit_64 += 0xfffff;
641ccf68033SPali Rohár pref_bits = (pref_type == PCI_PREF_RANGE_TYPE_64) ? 64 : 32;
642ccf68033SPali Rohár show_range("\tPrefetchable memory behind bridge", pref_base_64, pref_limit_64, pref_bits, pref_disabled);
643ccf68033SPali Rohár }
644e306e911SMartin Mares }
64598e39e09SMartin Mares
646138c0385SMartin Mares if (verbose > 1)
647c1c2c30eSMartin Mares printf("\tSecondary status: 66MHz%c FastB2B%c ParErr%c DEVSEL=%s >TAbort%c <TAbort%c <MAbort%c <SERR%c <PERR%c\n",
648138c0385SMartin Mares FLAG(sec_stat, PCI_STATUS_66MHZ),
649138c0385SMartin Mares FLAG(sec_stat, PCI_STATUS_FAST_BACK),
650138c0385SMartin Mares FLAG(sec_stat, PCI_STATUS_PARITY),
651138c0385SMartin Mares ((sec_stat & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_SLOW) ? "slow" :
652138c0385SMartin Mares ((sec_stat & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_MEDIUM) ? "medium" :
653138c0385SMartin Mares ((sec_stat & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_FAST) ? "fast" : "??",
654138c0385SMartin Mares FLAG(sec_stat, PCI_STATUS_SIG_TARGET_ABORT),
655138c0385SMartin Mares FLAG(sec_stat, PCI_STATUS_REC_TARGET_ABORT),
656138c0385SMartin Mares FLAG(sec_stat, PCI_STATUS_REC_MASTER_ABORT),
657138c0385SMartin Mares FLAG(sec_stat, PCI_STATUS_SIG_SYSTEM_ERROR),
658138c0385SMartin Mares FLAG(sec_stat, PCI_STATUS_DETECTED_PARITY));
65998e39e09SMartin Mares
6606aa54f1bSMartin Mares show_rom(d, PCI_ROM_ADDRESS1);
66198e39e09SMartin Mares
66298e39e09SMartin Mares if (verbose > 1)
663da322bfbSMartin Mares {
664b2a45526SBjorn Helgaas printf("\tBridgeCtl: Parity%c SERR%c NoISA%c VGA%c VGA16%c MAbort%c >Reset%c FastB2B%c\n",
6651c31d620SMartin Mares FLAG(brc, PCI_BRIDGE_CTL_PARITY),
6661c31d620SMartin Mares FLAG(brc, PCI_BRIDGE_CTL_SERR),
6671c31d620SMartin Mares FLAG(brc, PCI_BRIDGE_CTL_NO_ISA),
6681c31d620SMartin Mares FLAG(brc, PCI_BRIDGE_CTL_VGA),
669b2a45526SBjorn Helgaas FLAG(brc, PCI_BRIDGE_CTL_VGA_16BIT),
6701c31d620SMartin Mares FLAG(brc, PCI_BRIDGE_CTL_MASTER_ABORT),
6711c31d620SMartin Mares FLAG(brc, PCI_BRIDGE_CTL_BUS_RESET),
6721c31d620SMartin Mares FLAG(brc, PCI_BRIDGE_CTL_FAST_BACK));
673da322bfbSMartin Mares printf("\t\tPriDiscTmr%c SecDiscTmr%c DiscTmrStat%c DiscTmrSERREn%c\n",
674da322bfbSMartin Mares FLAG(brc, PCI_BRIDGE_CTL_PRI_DISCARD_TIMER),
675da322bfbSMartin Mares FLAG(brc, PCI_BRIDGE_CTL_SEC_DISCARD_TIMER),
676da322bfbSMartin Mares FLAG(brc, PCI_BRIDGE_CTL_DISCARD_TIMER_STATUS),
677da322bfbSMartin Mares FLAG(brc, PCI_BRIDGE_CTL_DISCARD_TIMER_SERR_EN));
678da322bfbSMartin Mares }
679e95c8373SMartin Mares
68021510591SMatthew Wilcox show_caps(d, PCI_CAPABILITY_LIST);
68198e39e09SMartin Mares }
68298e39e09SMartin Mares
68398e39e09SMartin Mares static void
show_htype2(struct device * d)6842f48f637SMartin Mares show_htype2(struct device *d)
6852f48f637SMartin Mares {
68696e4f295SMartin Mares int i;
68796e4f295SMartin Mares word cmd = get_conf_word(d, PCI_COMMAND);
68896e4f295SMartin Mares word brc = get_conf_word(d, PCI_CB_BRIDGE_CONTROL);
68984d437d6SMartin Mares word exca;
690e306e911SMartin Mares int verb = verbose > 2;
69196e4f295SMartin Mares
69272cabfbbSPali Rohár show_bases(d, 1, 0);
69396e4f295SMartin Mares printf("\tBus: primary=%02x, secondary=%02x, subordinate=%02x, sec-latency=%d\n",
69496e4f295SMartin Mares get_conf_byte(d, PCI_CB_PRIMARY_BUS),
69596e4f295SMartin Mares get_conf_byte(d, PCI_CB_CARD_BUS),
69696e4f295SMartin Mares get_conf_byte(d, PCI_CB_SUBORDINATE_BUS),
69796e4f295SMartin Mares get_conf_byte(d, PCI_CB_LATENCY_TIMER));
69896e4f295SMartin Mares for (i=0; i<2; i++)
69996e4f295SMartin Mares {
70096e4f295SMartin Mares int p = 8*i;
70196e4f295SMartin Mares u32 base = get_conf_long(d, PCI_CB_MEMORY_BASE_0 + p);
70296e4f295SMartin Mares u32 limit = get_conf_long(d, PCI_CB_MEMORY_LIMIT_0 + p);
703f288d32fSBjorn Helgaas limit = limit + 0xfff;
704f288d32fSBjorn Helgaas if (base <= limit || verb)
70581077814SMartin Mares printf("\tMemory window %d: %08x-%08x%s%s\n", i, base, limit,
70696e4f295SMartin Mares (cmd & PCI_COMMAND_MEMORY) ? "" : " [disabled]",
70796e4f295SMartin Mares (brc & (PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 << i)) ? " (prefetchable)" : "");
70896e4f295SMartin Mares }
70996e4f295SMartin Mares for (i=0; i<2; i++)
71096e4f295SMartin Mares {
71196e4f295SMartin Mares int p = 8*i;
71296e4f295SMartin Mares u32 base = get_conf_long(d, PCI_CB_IO_BASE_0 + p);
71396e4f295SMartin Mares u32 limit = get_conf_long(d, PCI_CB_IO_LIMIT_0 + p);
71496e4f295SMartin Mares if (!(base & PCI_IO_RANGE_TYPE_32))
71596e4f295SMartin Mares {
71696e4f295SMartin Mares base &= 0xffff;
71796e4f295SMartin Mares limit &= 0xffff;
71896e4f295SMartin Mares }
71996e4f295SMartin Mares base &= PCI_CB_IO_RANGE_MASK;
72096e4f295SMartin Mares limit = (limit & PCI_CB_IO_RANGE_MASK) + 3;
721e306e911SMartin Mares if (base <= limit || verb)
722e306e911SMartin Mares printf("\tI/O window %d: %08x-%08x%s\n", i, base, limit,
72396e4f295SMartin Mares (cmd & PCI_COMMAND_IO) ? "" : " [disabled]");
72496e4f295SMartin Mares }
72596e4f295SMartin Mares
72696e4f295SMartin Mares if (get_conf_word(d, PCI_CB_SEC_STATUS) & PCI_STATUS_SIG_SYSTEM_ERROR)
72796e4f295SMartin Mares printf("\tSecondary status: SERR\n");
72896e4f295SMartin Mares if (verbose > 1)
72996e4f295SMartin Mares printf("\tBridgeCtl: Parity%c SERR%c ISA%c VGA%c MAbort%c >Reset%c 16bInt%c PostWrite%c\n",
7301c31d620SMartin Mares FLAG(brc, PCI_CB_BRIDGE_CTL_PARITY),
7311c31d620SMartin Mares FLAG(brc, PCI_CB_BRIDGE_CTL_SERR),
7321c31d620SMartin Mares FLAG(brc, PCI_CB_BRIDGE_CTL_ISA),
7331c31d620SMartin Mares FLAG(brc, PCI_CB_BRIDGE_CTL_VGA),
7341c31d620SMartin Mares FLAG(brc, PCI_CB_BRIDGE_CTL_MASTER_ABORT),
7351c31d620SMartin Mares FLAG(brc, PCI_CB_BRIDGE_CTL_CB_RESET),
7361c31d620SMartin Mares FLAG(brc, PCI_CB_BRIDGE_CTL_16BIT_INT),
7371c31d620SMartin Mares FLAG(brc, PCI_CB_BRIDGE_CTL_POST_WRITES));
73884d437d6SMartin Mares
73984d437d6SMartin Mares if (d->config_cached < 128)
74084d437d6SMartin Mares {
74184d437d6SMartin Mares printf("\t<access denied to the rest>\n");
74284d437d6SMartin Mares return;
74384d437d6SMartin Mares }
74484d437d6SMartin Mares
74584d437d6SMartin Mares exca = get_conf_word(d, PCI_CB_LEGACY_MODE_BASE);
74696e4f295SMartin Mares if (exca)
74796e4f295SMartin Mares printf("\t16-bit legacy interface ports at %04x\n", exca);
74821510591SMatthew Wilcox show_caps(d, PCI_CB_CAPABILITY_LIST);
7492f48f637SMartin Mares }
7502f48f637SMartin Mares
7512f48f637SMartin Mares static void
show_htype_unknown(struct device * d)75272cabfbbSPali Rohár show_htype_unknown(struct device *d)
75372cabfbbSPali Rohár {
75472cabfbbSPali Rohár struct pci_dev *p = d->dev;
75572cabfbbSPali Rohár u64 base, limit, flags;
75672cabfbbSPali Rohár const char *str;
75772cabfbbSPali Rohár int i, bits;
75872cabfbbSPali Rohár
75972cabfbbSPali Rohár if (pacc->buscentric)
76072cabfbbSPali Rohár return;
76172cabfbbSPali Rohár
76272cabfbbSPali Rohár show_bases(d, 6, 1);
76372cabfbbSPali Rohár for (i = 0; i < 4; i++)
76472cabfbbSPali Rohár {
76572cabfbbSPali Rohár if (!p->bridge_base_addr[i])
76672cabfbbSPali Rohár continue;
76772cabfbbSPali Rohár base = p->bridge_base_addr[i];
76872cabfbbSPali Rohár limit = base + p->bridge_size[i] - 1;
76972cabfbbSPali Rohár flags = p->bridge_flags[i];
77072cabfbbSPali Rohár if (flags & PCI_IORESOURCE_IO)
77172cabfbbSPali Rohár {
77272cabfbbSPali Rohár bits = (flags & PCI_IORESOURCE_IO_16BIT_ADDR) ? 16 : 32;
77372cabfbbSPali Rohár str = "\tI/O behind bridge";
77472cabfbbSPali Rohár }
77572cabfbbSPali Rohár else if (flags & PCI_IORESOURCE_MEM)
77672cabfbbSPali Rohár {
77772cabfbbSPali Rohár bits = (flags & PCI_IORESOURCE_MEM_64) ? 64 : 32;
77872cabfbbSPali Rohár if (flags & PCI_IORESOURCE_PREFETCH)
77972cabfbbSPali Rohár str = "\tPrefetchable memory behind bridge";
78072cabfbbSPali Rohár else
78172cabfbbSPali Rohár str = "\tMemory behind bridge";
78272cabfbbSPali Rohár }
78372cabfbbSPali Rohár else
78472cabfbbSPali Rohár {
78572cabfbbSPali Rohár bits = 0;
78672cabfbbSPali Rohár str = "\tUnknown resource behind bridge";
78772cabfbbSPali Rohár }
78872cabfbbSPali Rohár show_range(str, base, limit, bits, 0);
78972cabfbbSPali Rohár }
79072cabfbbSPali Rohár show_rom(d, -1);
79172cabfbbSPali Rohár }
79272cabfbbSPali Rohár
79372cabfbbSPali Rohár static void
show_verbose(struct device * d)79498e39e09SMartin Mares show_verbose(struct device *d)
79598e39e09SMartin Mares {
796727ce158SMartin Mares struct pci_dev *p = d->dev;
79772cabfbbSPali Rohár int unknown_config_data = 0;
798c2b144efSMartin Mares word class = p->device_class;
799832b07a8SPali Rohár byte htype = d->no_config_access ? -1 : (get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f);
80072cabfbbSPali Rohár byte bist;
80198e39e09SMartin Mares byte max_lat, min_gnt;
802a5065438SAlex Xu (Hello71) char *dt_node, *iommu_group;
80398e39e09SMartin Mares
80498e39e09SMartin Mares show_terse(d);
80598e39e09SMartin Mares
806ef6c9ec3SMartin Mares pci_fill_info(p, PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES |
807ccf68033SPali Rohár PCI_FILL_PHYS_SLOT | PCI_FILL_NUMA_NODE | PCI_FILL_DT_NODE | PCI_FILL_IOMMU_GROUP |
808*49efa87fSKobayashi Daisuke PCI_FILL_BRIDGE_BASES | PCI_FILL_CLASS_EXT | PCI_FILL_SUBSYS | PCI_FILL_RCD_LNK);
809ef6c9ec3SMartin Mares
8102f48f637SMartin Mares switch (htype)
81198e39e09SMartin Mares {
8122f48f637SMartin Mares case PCI_HEADER_TYPE_NORMAL:
8132f48f637SMartin Mares if (class == PCI_CLASS_BRIDGE_PCI)
81456164f4fSMartin Mares printf("\t!!! Invalid class %04x for header type %02x\n", class, htype);
81572cabfbbSPali Rohár bist = get_conf_byte(d, PCI_BIST);
81698e39e09SMartin Mares max_lat = get_conf_byte(d, PCI_MAX_LAT);
81798e39e09SMartin Mares min_gnt = get_conf_byte(d, PCI_MIN_GNT);
81898e39e09SMartin Mares break;
8192f48f637SMartin Mares case PCI_HEADER_TYPE_BRIDGE:
820cce2caacSMartin Mares if ((class >> 8) != PCI_BASE_CLASS_BRIDGE)
82156164f4fSMartin Mares printf("\t!!! Invalid class %04x for header type %02x\n", class, htype);
82272cabfbbSPali Rohár bist = get_conf_byte(d, PCI_BIST);
823001b9ac6SBjorn Helgaas min_gnt = max_lat = 0;
8242f48f637SMartin Mares break;
8252f48f637SMartin Mares case PCI_HEADER_TYPE_CARDBUS:
8262f48f637SMartin Mares if ((class >> 8) != PCI_BASE_CLASS_BRIDGE)
82756164f4fSMartin Mares printf("\t!!! Invalid class %04x for header type %02x\n", class, htype);
82872cabfbbSPali Rohár bist = get_conf_byte(d, PCI_BIST);
82996e4f295SMartin Mares min_gnt = max_lat = 0;
83098e39e09SMartin Mares break;
83198e39e09SMartin Mares default:
832832b07a8SPali Rohár if (!d->no_config_access)
83398e39e09SMartin Mares printf("\t!!! Unknown header type %02x\n", htype);
83472cabfbbSPali Rohár bist = 0;
83572cabfbbSPali Rohár min_gnt = max_lat = 0;
83672cabfbbSPali Rohár unknown_config_data = 1;
83798e39e09SMartin Mares }
83898e39e09SMartin Mares
8392849a165SAlex Chiang if (p->phy_slot)
8402849a165SAlex Chiang printf("\tPhysical Slot: %s\n", p->phy_slot);
8412849a165SAlex Chiang
842c02d903cSMartin Mares if (dt_node = pci_get_string_property(p, PCI_FILL_DT_NODE))
843c02d903cSMartin Mares printf("\tDevice tree node: %s\n", dt_node);
844c02d903cSMartin Mares
84572cabfbbSPali Rohár if (!unknown_config_data && verbose > 1)
84698e39e09SMartin Mares {
84772cabfbbSPali Rohár word cmd = get_conf_word(d, PCI_COMMAND);
84872cabfbbSPali Rohár word status = get_conf_word(d, PCI_STATUS);
849da322bfbSMartin Mares printf("\tControl: I/O%c Mem%c BusMaster%c SpecCycle%c MemWINV%c VGASnoop%c ParErr%c Stepping%c SERR%c FastB2B%c DisINTx%c\n",
8501c31d620SMartin Mares FLAG(cmd, PCI_COMMAND_IO),
8511c31d620SMartin Mares FLAG(cmd, PCI_COMMAND_MEMORY),
8521c31d620SMartin Mares FLAG(cmd, PCI_COMMAND_MASTER),
8531c31d620SMartin Mares FLAG(cmd, PCI_COMMAND_SPECIAL),
8541c31d620SMartin Mares FLAG(cmd, PCI_COMMAND_INVALIDATE),
8551c31d620SMartin Mares FLAG(cmd, PCI_COMMAND_VGA_PALETTE),
8561c31d620SMartin Mares FLAG(cmd, PCI_COMMAND_PARITY),
8571c31d620SMartin Mares FLAG(cmd, PCI_COMMAND_WAIT),
8581c31d620SMartin Mares FLAG(cmd, PCI_COMMAND_SERR),
859da322bfbSMartin Mares FLAG(cmd, PCI_COMMAND_FAST_BACK),
860da322bfbSMartin Mares FLAG(cmd, PCI_COMMAND_DISABLE_INTx));
861da322bfbSMartin Mares printf("\tStatus: Cap%c 66MHz%c UDF%c FastB2B%c ParErr%c DEVSEL=%s >TAbort%c <TAbort%c <MAbort%c >SERR%c <PERR%c INTx%c\n",
8621c31d620SMartin Mares FLAG(status, PCI_STATUS_CAP_LIST),
8631c31d620SMartin Mares FLAG(status, PCI_STATUS_66MHZ),
8641c31d620SMartin Mares FLAG(status, PCI_STATUS_UDF),
8651c31d620SMartin Mares FLAG(status, PCI_STATUS_FAST_BACK),
8661c31d620SMartin Mares FLAG(status, PCI_STATUS_PARITY),
86798e39e09SMartin Mares ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_SLOW) ? "slow" :
86898e39e09SMartin Mares ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_MEDIUM) ? "medium" :
86998e39e09SMartin Mares ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_FAST) ? "fast" : "??",
8701c31d620SMartin Mares FLAG(status, PCI_STATUS_SIG_TARGET_ABORT),
8711c31d620SMartin Mares FLAG(status, PCI_STATUS_REC_TARGET_ABORT),
8721c31d620SMartin Mares FLAG(status, PCI_STATUS_REC_MASTER_ABORT),
8731c31d620SMartin Mares FLAG(status, PCI_STATUS_SIG_SYSTEM_ERROR),
874da322bfbSMartin Mares FLAG(status, PCI_STATUS_DETECTED_PARITY),
875da322bfbSMartin Mares FLAG(status, PCI_STATUS_INTx));
87698e39e09SMartin Mares if (cmd & PCI_COMMAND_MASTER)
87798e39e09SMartin Mares {
87872cabfbbSPali Rohár byte latency = get_conf_byte(d, PCI_LATENCY_TIMER);
87972cabfbbSPali Rohár byte cache_line = get_conf_byte(d, PCI_CACHE_LINE_SIZE);
88056164f4fSMartin Mares printf("\tLatency: %d", latency);
88156164f4fSMartin Mares if (min_gnt || max_lat)
88256164f4fSMartin Mares {
88356164f4fSMartin Mares printf(" (");
88498e39e09SMartin Mares if (min_gnt)
88556164f4fSMartin Mares printf("%dns min", min_gnt*250);
88656164f4fSMartin Mares if (min_gnt && max_lat)
88756164f4fSMartin Mares printf(", ");
88898e39e09SMartin Mares if (max_lat)
88956164f4fSMartin Mares printf("%dns max", max_lat*250);
89056164f4fSMartin Mares putchar(')');
89156164f4fSMartin Mares }
89298e39e09SMartin Mares if (cache_line)
8937a61b93cSMartin Mares printf(", Cache Line Size: %d bytes", cache_line * 4);
89498e39e09SMartin Mares putchar('\n');
89598e39e09SMartin Mares }
89672cabfbbSPali Rohár }
89772cabfbbSPali Rohár
89872cabfbbSPali Rohár if (verbose > 1)
89972cabfbbSPali Rohár {
90072cabfbbSPali Rohár byte int_pin = unknown_config_data ? 0 : get_conf_byte(d, PCI_INTERRUPT_PIN);
90172cabfbbSPali Rohár if (int_pin || p->irq)
9029739916eSMartin Mares printf("\tInterrupt: pin %c routed to IRQ " PCIIRQ_FMT "\n",
90372cabfbbSPali Rohár (int_pin ? 'A' + int_pin - 1 : '?'), p->irq);
9041d9d1a01SMartin Mares if (p->numa_node != -1)
9051d9d1a01SMartin Mares printf("\tNUMA node: %d\n", p->numa_node);
906a5065438SAlex Xu (Hello71) if (iommu_group = pci_get_string_property(p, PCI_FILL_IOMMU_GROUP))
907a5065438SAlex Xu (Hello71) printf("\tIOMMU group: %s\n", iommu_group);
90898e39e09SMartin Mares }
90972cabfbbSPali Rohár
91072cabfbbSPali Rohár if (!unknown_config_data && verbose <= 1)
91198e39e09SMartin Mares {
91272cabfbbSPali Rohár word cmd = get_conf_word(d, PCI_COMMAND);
91372cabfbbSPali Rohár word status = get_conf_word(d, PCI_STATUS);
91472cabfbbSPali Rohár byte latency = get_conf_byte(d, PCI_LATENCY_TIMER);
91598e39e09SMartin Mares printf("\tFlags: ");
91698e39e09SMartin Mares if (cmd & PCI_COMMAND_MASTER)
91798e39e09SMartin Mares printf("bus master, ");
91898e39e09SMartin Mares if (cmd & PCI_COMMAND_VGA_PALETTE)
91998e39e09SMartin Mares printf("VGA palette snoop, ");
92098e39e09SMartin Mares if (cmd & PCI_COMMAND_WAIT)
92198e39e09SMartin Mares printf("stepping, ");
92298e39e09SMartin Mares if (cmd & PCI_COMMAND_FAST_BACK)
92398e39e09SMartin Mares printf("fast Back2Back, ");
92498e39e09SMartin Mares if (status & PCI_STATUS_66MHZ)
925c1c2c30eSMartin Mares printf("66MHz, ");
92698e39e09SMartin Mares if (status & PCI_STATUS_UDF)
92798e39e09SMartin Mares printf("user-definable features, ");
92898e39e09SMartin Mares printf("%s devsel",
92998e39e09SMartin Mares ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_SLOW) ? "slow" :
93098e39e09SMartin Mares ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_MEDIUM) ? "medium" :
93198e39e09SMartin Mares ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_FAST) ? "fast" : "??");
93298e39e09SMartin Mares if (cmd & PCI_COMMAND_MASTER)
93398e39e09SMartin Mares printf(", latency %d", latency);
93472cabfbbSPali Rohár if (p->irq)
93572cabfbbSPali Rohár printf(", IRQ " PCIIRQ_FMT, p->irq);
93690ec4a6dSMatthew Wilcox if (p->numa_node != -1)
93790ec4a6dSMatthew Wilcox printf(", NUMA node %d", p->numa_node);
938a5065438SAlex Xu (Hello71) if (iommu_group = pci_get_string_property(p, PCI_FILL_IOMMU_GROUP))
939a5065438SAlex Xu (Hello71) printf(", IOMMU group %s", iommu_group);
94098e39e09SMartin Mares putchar('\n');
94198e39e09SMartin Mares }
94298e39e09SMartin Mares
94398e39e09SMartin Mares if (bist & PCI_BIST_CAPABLE)
94498e39e09SMartin Mares {
94598e39e09SMartin Mares if (bist & PCI_BIST_START)
94698e39e09SMartin Mares printf("\tBIST is running\n");
94798e39e09SMartin Mares else
94898e39e09SMartin Mares printf("\tBIST result: %02x\n", bist & PCI_BIST_CODE_MASK);
94998e39e09SMartin Mares }
95098e39e09SMartin Mares
95198e39e09SMartin Mares switch (htype)
95298e39e09SMartin Mares {
9532f48f637SMartin Mares case PCI_HEADER_TYPE_NORMAL:
95498e39e09SMartin Mares show_htype0(d);
95598e39e09SMartin Mares break;
9562f48f637SMartin Mares case PCI_HEADER_TYPE_BRIDGE:
95798e39e09SMartin Mares show_htype1(d);
95898e39e09SMartin Mares break;
9592f48f637SMartin Mares case PCI_HEADER_TYPE_CARDBUS:
9602f48f637SMartin Mares show_htype2(d);
9612f48f637SMartin Mares break;
96272cabfbbSPali Rohár default:
96372cabfbbSPali Rohár show_htype_unknown(d);
96498e39e09SMartin Mares }
96598e39e09SMartin Mares }
96698e39e09SMartin Mares
967a387042eSMartin Mares /*** Machine-readable dumps ***/
968a387042eSMartin Mares
96998e39e09SMartin Mares static void
show_hex_dump(struct device * d)97098e39e09SMartin Mares show_hex_dump(struct device *d)
97198e39e09SMartin Mares {
97209817437SMartin Mares unsigned int i, cnt;
97398e39e09SMartin Mares
974832b07a8SPali Rohár if (d->no_config_access)
975832b07a8SPali Rohár {
976832b07a8SPali Rohár printf("WARNING: Cannot show hex-dump of the config space\n");
977832b07a8SPali Rohár return;
978832b07a8SPali Rohár }
979832b07a8SPali Rohár
98084d437d6SMartin Mares cnt = d->config_cached;
981a387042eSMartin Mares if (opt_hex >= 3 && config_fetch(d, cnt, 256-cnt))
98209817437SMartin Mares {
98309817437SMartin Mares cnt = 256;
984a387042eSMartin Mares if (opt_hex >= 4 && config_fetch(d, 256, 4096-256))
98509817437SMartin Mares cnt = 4096;
98609817437SMartin Mares }
98709817437SMartin Mares
98809817437SMartin Mares for (i=0; i<cnt; i++)
98998e39e09SMartin Mares {
99098e39e09SMartin Mares if (! (i & 15))
99198e39e09SMartin Mares printf("%02x:", i);
99298e39e09SMartin Mares printf(" %02x", get_conf_byte(d, i));
99398e39e09SMartin Mares if ((i & 15) == 15)
99498e39e09SMartin Mares putchar('\n');
99598e39e09SMartin Mares }
99698e39e09SMartin Mares }
99798e39e09SMartin Mares
99898e39e09SMartin Mares static void
print_shell_escaped(char * c)99913081e57SMartin Mares print_shell_escaped(char *c)
100013081e57SMartin Mares {
100113081e57SMartin Mares printf(" \"");
100213081e57SMartin Mares while (*c)
100313081e57SMartin Mares {
100413081e57SMartin Mares if (*c == '"' || *c == '\\')
100513081e57SMartin Mares putchar('\\');
100613081e57SMartin Mares putchar(*c++);
100713081e57SMartin Mares }
100813081e57SMartin Mares putchar('"');
100913081e57SMartin Mares }
101013081e57SMartin Mares
101113081e57SMartin Mares static void
show_machine(struct device * d)10120a33d0ecSMartin Mares show_machine(struct device *d)
10130a33d0ecSMartin Mares {
1014727ce158SMartin Mares struct pci_dev *p = d->dev;
10156e766463SMartin Mares char classbuf[256], vendbuf[256], devbuf[256], svbuf[256], sdbuf[256];
1016a5065438SAlex Xu (Hello71) char *dt_node, *iommu_group;
1017ce503b7fSMartin Mares
10180a33d0ecSMartin Mares if (verbose)
10190a33d0ecSMartin Mares {
1020a5065438SAlex Xu (Hello71) pci_fill_info(p, PCI_FILL_PHYS_SLOT | PCI_FILL_NUMA_NODE | PCI_FILL_DT_NODE | PCI_FILL_IOMMU_GROUP);
1021a387042eSMartin Mares printf((opt_machine >= 2) ? "Slot:\t" : "Device:\t");
102284c8d1bbSMartin Mares show_slot_name(d);
102384c8d1bbSMartin Mares putchar('\n');
1024727ce158SMartin Mares printf("Class:\t%s\n",
1025c2b144efSMartin Mares pci_lookup_name(pacc, classbuf, sizeof(classbuf), PCI_LOOKUP_CLASS, p->device_class));
1026727ce158SMartin Mares printf("Vendor:\t%s\n",
1027224707baSMartin Mares pci_lookup_name(pacc, vendbuf, sizeof(vendbuf), PCI_LOOKUP_VENDOR, p->vendor_id, p->device_id));
1028727ce158SMartin Mares printf("Device:\t%s\n",
1029224707baSMartin Mares pci_lookup_name(pacc, devbuf, sizeof(devbuf), PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id));
1030fb570ee3SPali Rohár if ((p->known_fields & PCI_FILL_SUBSYS) &&
1031fb570ee3SPali Rohár p->subsys_vendor_id && p->subsys_vendor_id != 0xffff)
1032ce503b7fSMartin Mares {
1033727ce158SMartin Mares printf("SVendor:\t%s\n",
1034fb570ee3SPali Rohár pci_lookup_name(pacc, svbuf, sizeof(svbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR, p->subsys_vendor_id));
1035727ce158SMartin Mares printf("SDevice:\t%s\n",
1036fb570ee3SPali Rohár pci_lookup_name(pacc, sdbuf, sizeof(sdbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id, p->subsys_vendor_id, p->subsys_id));
1037ce503b7fSMartin Mares }
10382849a165SAlex Chiang if (p->phy_slot)
10392849a165SAlex Chiang printf("PhySlot:\t%s\n", p->phy_slot);
1040fb570ee3SPali Rohár if ((p->known_fields & PCI_FILL_CLASS_EXT) && p->rev_id)
1041fb570ee3SPali Rohár printf("Rev:\t%02x\n", p->rev_id);
1042fb570ee3SPali Rohár if (p->known_fields & PCI_FILL_CLASS_EXT)
1043fb570ee3SPali Rohár printf("ProgIf:\t%02x\n", p->prog_if);
104411339c0dSMartin Mares if (opt_kernel)
104511339c0dSMartin Mares show_kernel_machine(d);
10461d9d1a01SMartin Mares if (p->numa_node != -1)
10471d9d1a01SMartin Mares printf("NUMANode:\t%d\n", p->numa_node);
1048c02d903cSMartin Mares if (dt_node = pci_get_string_property(p, PCI_FILL_DT_NODE))
1049c02d903cSMartin Mares printf("DTNode:\t%s\n", dt_node);
1050a5065438SAlex Xu (Hello71) if (iommu_group = pci_get_string_property(p, PCI_FILL_IOMMU_GROUP))
1051a5065438SAlex Xu (Hello71) printf("IOMMUGroup:\t%s\n", iommu_group);
10520a33d0ecSMartin Mares }
10530a33d0ecSMartin Mares else
10540a33d0ecSMartin Mares {
105584c8d1bbSMartin Mares show_slot_name(d);
105613081e57SMartin Mares print_shell_escaped(pci_lookup_name(pacc, classbuf, sizeof(classbuf), PCI_LOOKUP_CLASS, p->device_class));
105713081e57SMartin Mares print_shell_escaped(pci_lookup_name(pacc, vendbuf, sizeof(vendbuf), PCI_LOOKUP_VENDOR, p->vendor_id, p->device_id));
105813081e57SMartin Mares print_shell_escaped(pci_lookup_name(pacc, devbuf, sizeof(devbuf), PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id));
1059fb570ee3SPali Rohár if ((p->known_fields & PCI_FILL_CLASS_EXT) && p->rev_id)
1060fb570ee3SPali Rohár printf(" -r%02x", p->rev_id);
1061fb570ee3SPali Rohár if (p->known_fields & PCI_FILL_CLASS_EXT)
1062fb570ee3SPali Rohár printf(" -p%02x", p->prog_if);
1063fb570ee3SPali Rohár if ((p->known_fields & PCI_FILL_SUBSYS) &&
1064fb570ee3SPali Rohár p->subsys_vendor_id && p->subsys_vendor_id != 0xffff)
106513081e57SMartin Mares {
1066fb570ee3SPali Rohár print_shell_escaped(pci_lookup_name(pacc, svbuf, sizeof(svbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR, p->subsys_vendor_id));
1067fb570ee3SPali Rohár print_shell_escaped(pci_lookup_name(pacc, sdbuf, sizeof(sdbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id, p->subsys_vendor_id, p->subsys_id));
106813081e57SMartin Mares }
1069ce503b7fSMartin Mares else
1070ce503b7fSMartin Mares printf(" \"\" \"\"");
10710a33d0ecSMartin Mares putchar('\n');
10720a33d0ecSMartin Mares }
10730a33d0ecSMartin Mares }
10740a33d0ecSMartin Mares
1075a387042eSMartin Mares /*** Main show function ***/
1076a387042eSMartin Mares
1077c7a34993SMartin Mares void
show_device(struct device * d)10781812a795SMartin Mares show_device(struct device *d)
107998e39e09SMartin Mares {
1080a387042eSMartin Mares if (opt_machine)
10810a33d0ecSMartin Mares show_machine(d);
108211339c0dSMartin Mares else
108311339c0dSMartin Mares {
108411339c0dSMartin Mares if (verbose)
108598e39e09SMartin Mares show_verbose(d);
108698e39e09SMartin Mares else
108798e39e09SMartin Mares show_terse(d);
108811339c0dSMartin Mares if (opt_kernel || verbose)
108911339c0dSMartin Mares show_kernel(d);
109011339c0dSMartin Mares }
1091a387042eSMartin Mares if (opt_hex)
109298e39e09SMartin Mares show_hex_dump(d);
1093a387042eSMartin Mares if (verbose || opt_hex)
109498e39e09SMartin Mares putchar('\n');
109598e39e09SMartin Mares }
10961812a795SMartin Mares
10971812a795SMartin Mares static void
show(void)10981812a795SMartin Mares show(void)
10991812a795SMartin Mares {
11001812a795SMartin Mares struct device *d;
11011812a795SMartin Mares
11021812a795SMartin Mares for (d=first_dev; d; d=d->next)
1103ce22dfecSMartin Mares if (pci_filter_match(&filter, d->dev))
11041812a795SMartin Mares show_device(d);
110598e39e09SMartin Mares }
110698e39e09SMartin Mares
110798e39e09SMartin Mares /* Main */
110898e39e09SMartin Mares
110998e39e09SMartin Mares int
main(int argc,char ** argv)111098e39e09SMartin Mares main(int argc, char **argv)
111198e39e09SMartin Mares {
111298e39e09SMartin Mares int i;
1113e4842ff3SMartin Mares char *msg;
111498e39e09SMartin Mares
1115496d4021SMartin Mares if (argc == 2 && !strcmp(argv[1], "--version"))
1116496d4021SMartin Mares {
1117496d4021SMartin Mares puts("lspci version " PCIUTILS_VERSION);
1118496d4021SMartin Mares return 0;
1119496d4021SMartin Mares }
1120727ce158SMartin Mares
1121727ce158SMartin Mares pacc = pci_alloc();
1122727ce158SMartin Mares pacc->error = die;
1123727ce158SMartin Mares pci_filter_init(pacc, &filter);
1124727ce158SMartin Mares
112598e39e09SMartin Mares while ((i = getopt(argc, argv, options)) != -1)
112698e39e09SMartin Mares switch (i)
112798e39e09SMartin Mares {
112898e39e09SMartin Mares case 'n':
1129bc2eed2dSMartin Mares pacc->numeric_ids++;
113098e39e09SMartin Mares break;
113198e39e09SMartin Mares case 'v':
113298e39e09SMartin Mares verbose++;
113398e39e09SMartin Mares break;
113498e39e09SMartin Mares case 'b':
1135727ce158SMartin Mares pacc->buscentric = 1;
113698e39e09SMartin Mares break;
1137e4842ff3SMartin Mares case 's':
1138727ce158SMartin Mares if (msg = pci_filter_parse_slot(&filter, optarg))
1139b7fd8e19SMartin Mares die("-s: %s", msg);
1140ce22dfecSMartin Mares opt_filter = 1;
114198e39e09SMartin Mares break;
1142e4842ff3SMartin Mares case 'd':
1143727ce158SMartin Mares if (msg = pci_filter_parse_id(&filter, optarg))
1144727ce158SMartin Mares die("-d: %s", msg);
1145ce22dfecSMartin Mares opt_filter = 1;
114698e39e09SMartin Mares break;
114798e39e09SMartin Mares case 'x':
1148a387042eSMartin Mares opt_hex++;
114998e39e09SMartin Mares break;
115062e78fa6SMartin Mares case 'P':
115162e78fa6SMartin Mares opt_path++;
1152ce22dfecSMartin Mares need_topology = 1;
115362e78fa6SMartin Mares break;
11546d0dc0fdSMartin Mares case 't':
1155a387042eSMartin Mares opt_tree++;
1156ce22dfecSMartin Mares need_topology = 1;
11576d0dc0fdSMartin Mares break;
115818928b91SMartin Mares case 'i':
1159cc062b4aSMartin Mares pci_set_name_list_path(pacc, optarg, 0);
116018928b91SMartin Mares break;
11610a33d0ecSMartin Mares case 'm':
1162a387042eSMartin Mares opt_machine++;
11630a33d0ecSMartin Mares break;
1164c1c952d2SMartin Mares case 'p':
1165c1c952d2SMartin Mares opt_pcimap = optarg;
1166c1c952d2SMartin Mares break;
11671b99a704SMartin Mares #ifdef PCI_OS_LINUX
116811339c0dSMartin Mares case 'k':
116911339c0dSMartin Mares opt_kernel++;
117011339c0dSMartin Mares break;
11711b99a704SMartin Mares #endif
11721812a795SMartin Mares case 'M':
1173a387042eSMartin Mares opt_map_mode++;
11741812a795SMartin Mares break;
1175af61eb25SMartin Mares case 'D':
1176a387042eSMartin Mares opt_domains = 2;
1177af61eb25SMartin Mares break;
1178e022789dSMartin Mares #ifdef PCI_USE_DNS
1179cca2f7c6SMartin Mares case 'q':
1180cca2f7c6SMartin Mares opt_query_dns++;
1181cca2f7c6SMartin Mares break;
1182cca2f7c6SMartin Mares case 'Q':
1183cca2f7c6SMartin Mares opt_query_all = 1;
1184cca2f7c6SMartin Mares break;
1185e022789dSMartin Mares #else
1186e022789dSMartin Mares case 'q':
1187e022789dSMartin Mares case 'Q':
1188e022789dSMartin Mares die("DNS queries are not available in this version");
1189e022789dSMartin Mares #endif
119098e39e09SMartin Mares default:
1191727ce158SMartin Mares if (parse_generic_option(i, pacc, optarg))
1192727ce158SMartin Mares break;
119398e39e09SMartin Mares bad:
1194727ce158SMartin Mares fprintf(stderr, help_msg, pacc->id_file_name);
119598e39e09SMartin Mares return 1;
119698e39e09SMartin Mares }
119798e39e09SMartin Mares if (optind < argc)
119898e39e09SMartin Mares goto bad;
119998e39e09SMartin Mares
1200cca2f7c6SMartin Mares if (opt_query_dns)
1201cca2f7c6SMartin Mares {
1202103f074cSMartin Mares pacc->id_lookup_mode |= PCI_LOOKUP_NETWORK;
1203cca2f7c6SMartin Mares if (opt_query_dns > 1)
1204cca2f7c6SMartin Mares pacc->id_lookup_mode |= PCI_LOOKUP_REFRESH_CACHE;
1205cca2f7c6SMartin Mares }
1206cca2f7c6SMartin Mares if (opt_query_all)
1207cca2f7c6SMartin Mares pacc->id_lookup_mode |= PCI_LOOKUP_NETWORK | PCI_LOOKUP_SKIP_LOCAL;
1208cca2f7c6SMartin Mares
1209727ce158SMartin Mares pci_init(pacc);
1210a387042eSMartin Mares if (opt_map_mode)
121162e78fa6SMartin Mares {
1212ce22dfecSMartin Mares if (need_topology)
1213ce22dfecSMartin Mares die("Bus mapping mode does not recognize bus topology");
12141812a795SMartin Mares map_the_bus();
121562e78fa6SMartin Mares }
12161812a795SMartin Mares else
12171812a795SMartin Mares {
1218727ce158SMartin Mares scan_devices();
121998e39e09SMartin Mares sort_them();
1220ce22dfecSMartin Mares if (need_topology)
1221ce22dfecSMartin Mares grow_tree();
1222a387042eSMartin Mares if (opt_tree)
1223888ddf0eSGera Kazakov show_forest(opt_filter ? &filter : NULL);
12246d0dc0fdSMartin Mares else
122598e39e09SMartin Mares show();
12261812a795SMartin Mares }
122717ec7e70SMartin Mares show_kernel_cleanup();
1228727ce158SMartin Mares pci_cleanup(pacc);
122998e39e09SMartin Mares
1230934e7e36SMartin Mares return (seen_errors ? 2 : 0);
123198e39e09SMartin Mares }
1232