xref: /pciutils/lspci.c (revision 49efa87f)
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