]> mj.ucw.cz Git - pciutils.git/blobdiff - lspci.c
lib: fixup DOE status register bit
[pciutils.git] / lspci.c
diff --git a/lspci.c b/lspci.c
index aba2745a919262f25c9127d27fcc97c09230bbe4..9452cd31a2b0a830f876fd11e13239fd625f9106 100644 (file)
--- a/lspci.c
+++ b/lspci.c
@@ -3,7 +3,9 @@
  *
  *     Copyright (c) 1997--2020 Martin Mares <mj@ucw.cz>
  *
- *     Can be freely distributed and used under the terms of the GNU GPL.
+ *     Can be freely distributed and used under the terms of the GNU GPL v2+.
+ *
+ *     SPDX-License-Identifier: GPL-2.0-or-later
  */
 
 #include <stdio.h>
@@ -124,18 +126,18 @@ scan_device(struct pci_dev *p)
   d = xmalloc(sizeof(struct device));
   memset(d, 0, sizeof(*d));
   d->dev = p;
+  d->no_config_access = p->no_config_access;
   d->config_cached = d->config_bufsize = 64;
   d->config = xmalloc(64);
   d->present = xmalloc(64);
   memset(d->present, 1, 64);
-  if (!pci_read_block(p, 0, d->config, 64))
+  if (!d->no_config_access && !pci_read_block(p, 0, d->config, 64))
     {
-      fprintf(stderr, "lspci: Unable to read the standard configuration space header of device %04x:%02x:%02x.%d\n",
-             p->domain, p->bus, p->dev, p->func);
-      seen_errors++;
-      return NULL;
+      d->no_config_access = 1;
+      d->config_cached = d->config_bufsize = 0;
+      memset(d->present, 0, 64);
     }
-  if ((d->config[PCI_HEADER_TYPE] & 0x7f) == PCI_HEADER_TYPE_CARDBUS)
+  if (!d->no_config_access && (d->config[PCI_HEADER_TYPE] & 0x7f) == PCI_HEADER_TYPE_CARDBUS)
     {
       /* For cardbus bridges, we need to fetch 64 bytes more to get the
        * full standard header... */
@@ -143,7 +145,7 @@ scan_device(struct pci_dev *p)
        d->config_cached += 64;
     }
   pci_setup_cache(p, d->config, d->config_cached);
-  pci_fill_info(p, PCI_FILL_IDENT | PCI_FILL_CLASS);
+  pci_fill_info(p, PCI_FILL_IDENT | PCI_FILL_CLASS | PCI_FILL_CLASS_EXT | PCI_FILL_SUBSYS | (need_topology ? PCI_FILL_PARENT : 0));
   return d;
 }
 
@@ -285,31 +287,12 @@ show_slot_name(struct device *d)
   show_slot_path(d);
 }
 
-void
-get_subid(struct device *d, word *subvp, word *subdp)
-{
-  byte htype = get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f;
-
-  if (htype == PCI_HEADER_TYPE_NORMAL)
-    {
-      *subvp = get_conf_word(d, PCI_SUBSYSTEM_VENDOR_ID);
-      *subdp = get_conf_word(d, PCI_SUBSYSTEM_ID);
-    }
-  else if (htype == PCI_HEADER_TYPE_CARDBUS && d->config_cached >= 128)
-    {
-      *subvp = get_conf_word(d, PCI_CB_SUBSYSTEM_VENDOR_ID);
-      *subdp = get_conf_word(d, PCI_CB_SUBSYSTEM_ID);
-    }
-  else
-    *subvp = *subdp = 0xffff;
-}
-
 static void
 show_terse(struct device *d)
 {
   int c;
   struct pci_dev *p = d->dev;
-  char classbuf[128], devbuf[128];
+  char classbuf[256], devbuf[256];
 
   show_slot_name(d);
   printf(" %s: %s",
@@ -319,12 +302,12 @@ show_terse(struct device *d)
         pci_lookup_name(pacc, devbuf, sizeof(devbuf),
                         PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
                         p->vendor_id, p->device_id));
-  if (c = get_conf_byte(d, PCI_REVISION_ID))
-    printf(" (rev %02x)", c);
+  if ((p->known_fields & PCI_FILL_CLASS_EXT) && p->rev_id)
+    printf(" (rev %02x)", p->rev_id);
   if (verbose)
     {
       char *x;
-      c = get_conf_byte(d, PCI_CLASS_PROG);
+      c = (p->known_fields & PCI_FILL_CLASS_EXT) ? p->prog_if : 0;
       x = pci_lookup_name(pacc, devbuf, sizeof(devbuf),
                          PCI_LOOKUP_PROGIF | PCI_LOOKUP_NO_NUMBERS,
                          p->device_class, c);
@@ -340,19 +323,18 @@ show_terse(struct device *d)
 
   if (verbose || opt_kernel)
     {
-      word subsys_v, subsys_d;
       char ssnamebuf[256];
 
       pci_fill_info(p, PCI_FILL_LABEL);
 
       if (p->label)
         printf("\tDeviceName: %s", p->label);
-      get_subid(d, &subsys_v, &subsys_d);
-      if (subsys_v && subsys_v != 0xffff)
+      if ((p->known_fields & PCI_FILL_SUBSYS) &&
+         p->subsys_vendor_id && p->subsys_vendor_id != 0xffff)
        printf("\tSubsystem: %s\n",
                pci_lookup_name(pacc, ssnamebuf, sizeof(ssnamebuf),
                        PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
-                       p->vendor_id, p->device_id, subsys_v, subsys_d));
+                       p->vendor_id, p->device_id, p->subsys_vendor_id, p->subsys_id));
     }
 }
 
@@ -374,40 +356,60 @@ show_size(u64 x)
 }
 
 static void
-show_range(char *prefix, u64 base, u64 limit, int is_64bit)
+show_range(const char *prefix, u64 base, u64 limit, int bits, int disabled)
 {
   printf("%s:", prefix);
   if (base <= limit || verbose > 2)
-    {
-      if (is_64bit)
-        printf(" %016" PCI_U64_FMT_X "-%016" PCI_U64_FMT_X, base, limit);
-      else
-        printf(" %08x-%08x", (unsigned) base, (unsigned) limit);
-    }
-  if (base <= limit)
+    printf(" %0*" PCI_U64_FMT_X "-%0*" PCI_U64_FMT_X, (bits+3)/4, base, (bits+3)/4, limit);
+  if (!disabled && base <= limit)
     show_size(limit - base + 1);
   else
     printf(" [disabled]");
+  if (bits)
+    printf(" [%d-bit]", bits);
   putchar('\n');
 }
 
+static u32
+ioflg_to_pciflg(pciaddr_t ioflg)
+{
+  u32 flg;
+
+  if (ioflg & PCI_IORESOURCE_IO)
+    flg = PCI_BASE_ADDRESS_SPACE_IO;
+  else if (!(ioflg & PCI_IORESOURCE_MEM))
+    flg = 0;
+  else
+    {
+      flg = PCI_BASE_ADDRESS_SPACE_MEMORY;
+      if (ioflg & PCI_IORESOURCE_MEM_64)
+        flg |= PCI_BASE_ADDRESS_MEM_TYPE_64;
+      else
+        flg |= PCI_BASE_ADDRESS_MEM_TYPE_32;
+      if (ioflg & PCI_IORESOURCE_PREFETCH)
+        flg |= PCI_BASE_ADDRESS_MEM_PREFETCH;
+    }
+
+  return flg;
+}
+
 static void
-show_bases(struct device *d, int cnt)
+show_bases(struct device *d, int cnt, int without_config_data)
 {
   struct pci_dev *p = d->dev;
-  word cmd = get_conf_word(d, PCI_COMMAND);
+  word cmd = without_config_data ? (PCI_COMMAND_IO | PCI_COMMAND_MEMORY) : get_conf_word(d, PCI_COMMAND);
   int i;
-  int virtual = 0;
 
   for (i=0; i<cnt; i++)
     {
       pciaddr_t pos = p->base_addr[i];
       pciaddr_t len = (p->known_fields & PCI_FILL_SIZES) ? p->size[i] : 0;
       pciaddr_t ioflg = (p->known_fields & PCI_FILL_IO_FLAGS) ? p->flags[i] : 0;
-      u32 flg = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i);
-      u32 hw_lower;
+      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);
+      u32 hw_lower = 0;
       u32 hw_upper = 0;
       int broken = 0;
+      int virtual = 0;
 
       if (flg == 0xffffffff)
        flg = 0;
@@ -419,31 +421,26 @@ show_bases(struct device *d, int cnt)
       else
        putchar('\t');
 
-      /* Read address as seen by the hardware */
-      if (flg & PCI_BASE_ADDRESS_SPACE_IO)
-       hw_lower = flg & PCI_BASE_ADDRESS_IO_MASK;
-      else
+      /* Detect virtual regions, which are reported by the OS, but unassigned in the device */
+      if ((p->known_fields & PCI_FILL_IO_FLAGS) && !without_config_data)
        {
-         hw_lower = flg & PCI_BASE_ADDRESS_MEM_MASK;
-         if ((flg & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64)
+         /* Read address as seen by the hardware */
+         hw_lower = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i);
+         if ((hw_lower & PCI_BASE_ADDRESS_SPACE) == (ioflg_to_pciflg(ioflg) & PCI_BASE_ADDRESS_SPACE))
            {
-             if (i >= cnt - 1)
-               broken = 1;
-             else
-               {
-                 i++;
-                 hw_upper = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i);
+             if ((ioflg & PCI_IORESOURCE_TYPE_BITS) == PCI_IORESOURCE_MEM &&
+                 (hw_lower & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64)
+               {
+                 if (i >= cnt - 1)
+                   broken = 1;
+                 else
+                   hw_upper = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i + 1);
                }
+             if (pos && !hw_lower && !hw_upper && !(ioflg & PCI_IORESOURCE_PCI_EA_BEI))
+               virtual = 1;
            }
        }
 
-      /* Detect virtual regions, which are reported by the OS, but unassigned in the device */
-      if (pos && !hw_lower && !hw_upper && !(ioflg & PCI_IORESOURCE_PCI_EA_BEI))
-       {
-         flg = pos;
-         virtual = 1;
-       }
-
       /* Print base address */
       if (flg & PCI_BASE_ADDRESS_SPACE_IO)
        {
@@ -500,14 +497,14 @@ show_rom(struct device *d, int reg)
   pciaddr_t rom = p->rom_base_addr;
   pciaddr_t len = (p->known_fields & PCI_FILL_SIZES) ? p->rom_size : 0;
   pciaddr_t ioflg = (p->known_fields & PCI_FILL_IO_FLAGS) ? p->rom_flags : 0;
-  u32 flg = get_conf_long(d, reg);
-  word cmd = get_conf_word(d, PCI_COMMAND);
+  u32 flg = reg >= 0 ? get_conf_long(d, reg) : ioflg_to_pciflg(ioflg);
+  word cmd = reg >= 0 ? get_conf_word(d, PCI_COMMAND) : PCI_COMMAND_MEMORY;
   int virtual = 0;
 
   if (!rom && !flg && !len)
     return;
 
-  if ((rom & PCI_ROM_ADDRESS_MASK) && !(flg & PCI_ROM_ADDRESS_MASK) && !(ioflg & PCI_IORESOURCE_PCI_EA_BEI))
+  if (reg >= 0 && (rom & PCI_ROM_ADDRESS_MASK) && !(flg & PCI_ROM_ADDRESS_MASK) && !(ioflg & PCI_IORESOURCE_PCI_EA_BEI))
     {
       flg = rom;
       virtual = 1;
@@ -539,7 +536,7 @@ show_rom(struct device *d, int reg)
 static void
 show_htype0(struct device *d)
 {
-  show_bases(d, 6);
+  show_bases(d, 6, 0);
   show_rom(d, PCI_ROM_ADDRESS);
   show_caps(d, PCI_CAPABILITY_LIST);
 }
@@ -547,6 +544,7 @@ show_htype0(struct device *d)
 static void
 show_htype1(struct device *d)
 {
+  struct pci_dev *p = d->dev;
   u32 io_base = get_conf_byte(d, PCI_IO_BASE);
   u32 io_limit = get_conf_byte(d, PCI_IO_LIMIT);
   u32 io_type = io_base & PCI_IO_RANGE_TYPE_MASK;
@@ -558,15 +556,27 @@ show_htype1(struct device *d)
   u32 pref_type = pref_base & PCI_PREF_RANGE_TYPE_MASK;
   word sec_stat = get_conf_word(d, PCI_SEC_STATUS);
   word brc = get_conf_word(d, PCI_BRIDGE_CONTROL);
+  int io_disabled = (p->known_fields & PCI_FILL_BRIDGE_BASES) && !p->bridge_size[0];
+  int mem_disabled = (p->known_fields & PCI_FILL_BRIDGE_BASES) && !p->bridge_size[1];
+  int pref_disabled = (p->known_fields & PCI_FILL_BRIDGE_BASES) && !p->bridge_size[2];
+  int io_bits, pref_bits;
 
-  show_bases(d, 2);
+  show_bases(d, 2, 0);
   printf("\tBus: primary=%02x, secondary=%02x, subordinate=%02x, sec-latency=%d\n",
         get_conf_byte(d, PCI_PRIMARY_BUS),
         get_conf_byte(d, PCI_SECONDARY_BUS),
         get_conf_byte(d, PCI_SUBORDINATE_BUS),
         get_conf_byte(d, PCI_SEC_LATENCY_TIMER));
 
-  if (io_type != (io_limit & PCI_IO_RANGE_TYPE_MASK) ||
+  if ((p->known_fields & PCI_FILL_BRIDGE_BASES) && !io_disabled)
+    {
+      io_base = p->bridge_base_addr[0] & PCI_IO_RANGE_MASK;
+      io_limit = io_base + p->bridge_size[0] - 1;
+      io_type = p->bridge_base_addr[0] & PCI_IO_RANGE_TYPE_MASK;
+      io_bits = (io_type == PCI_IO_RANGE_TYPE_32) ? 32 : 16;
+      show_range("\tI/O behind bridge", io_base, io_limit, io_bits, io_disabled);
+    }
+  else if (io_type != (io_limit & PCI_IO_RANGE_TYPE_MASK) ||
       (io_type != PCI_IO_RANGE_TYPE_16 && io_type != PCI_IO_RANGE_TYPE_32))
     printf("\t!!! Unknown I/O range types %x/%x\n", io_base, io_limit);
   else
@@ -578,20 +588,40 @@ show_htype1(struct device *d)
          io_base |= (get_conf_word(d, PCI_IO_BASE_UPPER16) << 16);
          io_limit |= (get_conf_word(d, PCI_IO_LIMIT_UPPER16) << 16);
        }
-      show_range("\tI/O behind bridge", io_base, io_limit+0xfff, 0);
+      /* I/O is unsupported if both base and limit are zeros and resource is disabled */
+      if (!(io_base == 0x0 && io_limit == 0x0 && io_disabled))
+        {
+          io_limit += 0xfff;
+          io_bits = (io_type == PCI_IO_RANGE_TYPE_32) ? 32 : 16;
+          show_range("\tI/O behind bridge", io_base, io_limit, io_bits, io_disabled);
+        }
     }
 
-  if (mem_type != (mem_limit & PCI_MEMORY_RANGE_TYPE_MASK) ||
+  if ((p->known_fields & PCI_FILL_BRIDGE_BASES) && !mem_disabled)
+    {
+      mem_base = p->bridge_base_addr[1] & PCI_MEMORY_RANGE_MASK;
+      mem_limit = mem_base + p->bridge_size[1] - 1;
+      show_range("\tMemory behind bridge", mem_base, mem_limit, 32, mem_disabled);
+    }
+  else if (mem_type != (mem_limit & PCI_MEMORY_RANGE_TYPE_MASK) ||
       mem_type)
     printf("\t!!! Unknown memory range types %x/%x\n", mem_base, mem_limit);
   else
     {
       mem_base = (mem_base & PCI_MEMORY_RANGE_MASK) << 16;
       mem_limit = (mem_limit & PCI_MEMORY_RANGE_MASK) << 16;
-      show_range("\tMemory behind bridge", mem_base, mem_limit + 0xfffff, 0);
+      show_range("\tMemory behind bridge", mem_base, mem_limit + 0xfffff, 32, mem_disabled);
     }
 
-  if (pref_type != (pref_limit & PCI_PREF_RANGE_TYPE_MASK) ||
+  if ((p->known_fields & PCI_FILL_BRIDGE_BASES) && !pref_disabled)
+    {
+      u64 pref_base_64 = p->bridge_base_addr[2] & PCI_MEMORY_RANGE_MASK;
+      u64 pref_limit_64 = pref_base_64 + p->bridge_size[2] - 1;
+      pref_type = p->bridge_base_addr[2] & PCI_MEMORY_RANGE_TYPE_MASK;
+      pref_bits = (pref_type == PCI_PREF_RANGE_TYPE_64) ? 64 : 32;
+      show_range("\tPrefetchable memory behind bridge", pref_base_64, pref_limit_64, pref_bits, pref_disabled);
+    }
+  else if (pref_type != (pref_limit & PCI_PREF_RANGE_TYPE_MASK) ||
       (pref_type != PCI_PREF_RANGE_TYPE_32 && pref_type != PCI_PREF_RANGE_TYPE_64))
     printf("\t!!! Unknown prefetchable memory range types %x/%x\n", pref_base, pref_limit);
   else
@@ -603,7 +633,13 @@ show_htype1(struct device *d)
          pref_base_64 |= (u64) get_conf_long(d, PCI_PREF_BASE_UPPER32) << 32;
          pref_limit_64 |= (u64) get_conf_long(d, PCI_PREF_LIMIT_UPPER32) << 32;
        }
-      show_range("\tPrefetchable memory behind bridge", pref_base_64, pref_limit_64 + 0xfffff, (pref_type == PCI_PREF_RANGE_TYPE_64));
+      /* Prefetchable memory is unsupported if both base and limit are zeros and resource is disabled */
+      if (!(pref_base_64 == 0x0 && pref_limit_64 == 0x0 && pref_disabled))
+        {
+          pref_limit_64 += 0xfffff;
+          pref_bits = (pref_type == PCI_PREF_RANGE_TYPE_64) ? 64 : 32;
+          show_range("\tPrefetchable memory behind bridge", pref_base_64, pref_limit_64, pref_bits, pref_disabled);
+        }
     }
 
   if (verbose > 1)
@@ -652,7 +688,7 @@ show_htype2(struct device *d)
   word exca;
   int verb = verbose > 2;
 
-  show_bases(d, 1);
+  show_bases(d, 1, 0);
   printf("\tBus: primary=%02x, secondary=%02x, subordinate=%02x, sec-latency=%d\n",
         get_conf_byte(d, PCI_CB_PRIMARY_BUS),
         get_conf_byte(d, PCI_CB_CARD_BUS),
@@ -711,49 +747,92 @@ show_htype2(struct device *d)
   show_caps(d, PCI_CB_CAPABILITY_LIST);
 }
 
+static void
+show_htype_unknown(struct device *d)
+{
+  struct pci_dev *p = d->dev;
+  u64 base, limit, flags;
+  const char *str;
+  int i, bits;
+
+  if (pacc->buscentric)
+    return;
+
+  show_bases(d, 6, 1);
+  for (i = 0; i < 4; i++)
+    {
+      if (!p->bridge_base_addr[i])
+        continue;
+      base = p->bridge_base_addr[i];
+      limit = base + p->bridge_size[i] - 1;
+      flags = p->bridge_flags[i];
+      if (flags & PCI_IORESOURCE_IO)
+        {
+          bits = (flags & PCI_IORESOURCE_IO_16BIT_ADDR) ? 16 : 32;
+          str = "\tI/O behind bridge";
+        }
+      else if (flags & PCI_IORESOURCE_MEM)
+        {
+          bits = (flags & PCI_IORESOURCE_MEM_64) ? 64 : 32;
+          if (flags & PCI_IORESOURCE_PREFETCH)
+            str = "\tPrefetchable memory behind bridge";
+          else
+            str = "\tMemory behind bridge";
+        }
+      else
+        {
+          bits = 0;
+          str = "\tUnknown resource behind bridge";
+        }
+      show_range(str, base, limit, bits, 0);
+    }
+  show_rom(d, -1);
+}
+
 static void
 show_verbose(struct device *d)
 {
   struct pci_dev *p = d->dev;
-  word status = get_conf_word(d, PCI_STATUS);
-  word cmd = get_conf_word(d, PCI_COMMAND);
+  int unknown_config_data = 0;
   word class = p->device_class;
-  byte bist = get_conf_byte(d, PCI_BIST);
-  byte htype = get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f;
-  byte latency = get_conf_byte(d, PCI_LATENCY_TIMER);
-  byte cache_line = get_conf_byte(d, PCI_CACHE_LINE_SIZE);
+  byte htype = d->no_config_access ? -1 : (get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f);
+  byte bist;
   byte max_lat, min_gnt;
-  byte int_pin = get_conf_byte(d, PCI_INTERRUPT_PIN);
-  unsigned int irq;
   char *dt_node, *iommu_group;
 
   show_terse(d);
 
   pci_fill_info(p, PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES |
-    PCI_FILL_PHYS_SLOT | PCI_FILL_NUMA_NODE | PCI_FILL_DT_NODE | PCI_FILL_IOMMU_GROUP);
-  irq = p->irq;
+    PCI_FILL_PHYS_SLOT | PCI_FILL_NUMA_NODE | PCI_FILL_DT_NODE | PCI_FILL_IOMMU_GROUP |
+    PCI_FILL_BRIDGE_BASES | PCI_FILL_CLASS_EXT | PCI_FILL_SUBSYS);
 
   switch (htype)
     {
     case PCI_HEADER_TYPE_NORMAL:
       if (class == PCI_CLASS_BRIDGE_PCI)
        printf("\t!!! Invalid class %04x for header type %02x\n", class, htype);
+      bist = get_conf_byte(d, PCI_BIST);
       max_lat = get_conf_byte(d, PCI_MAX_LAT);
       min_gnt = get_conf_byte(d, PCI_MIN_GNT);
       break;
     case PCI_HEADER_TYPE_BRIDGE:
       if ((class >> 8) != PCI_BASE_CLASS_BRIDGE)
        printf("\t!!! Invalid class %04x for header type %02x\n", class, htype);
+      bist = get_conf_byte(d, PCI_BIST);
       min_gnt = max_lat = 0;
       break;
     case PCI_HEADER_TYPE_CARDBUS:
       if ((class >> 8) != PCI_BASE_CLASS_BRIDGE)
        printf("\t!!! Invalid class %04x for header type %02x\n", class, htype);
+      bist = get_conf_byte(d, PCI_BIST);
       min_gnt = max_lat = 0;
       break;
     default:
+      if (!d->no_config_access)
       printf("\t!!! Unknown header type %02x\n", htype);
-      return;
+      bist = 0;
+      min_gnt = max_lat = 0;
+      unknown_config_data = 1;
     }
 
   if (p->phy_slot)
@@ -762,8 +841,10 @@ show_verbose(struct device *d)
   if (dt_node = pci_get_string_property(p, PCI_FILL_DT_NODE))
     printf("\tDevice tree node: %s\n", dt_node);
 
-  if (verbose > 1)
+  if (!unknown_config_data && verbose > 1)
     {
+      word cmd = get_conf_word(d, PCI_COMMAND);
+      word status = get_conf_word(d, PCI_STATUS);
       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",
             FLAG(cmd, PCI_COMMAND_IO),
             FLAG(cmd, PCI_COMMAND_MEMORY),
@@ -793,6 +874,8 @@ show_verbose(struct device *d)
             FLAG(status, PCI_STATUS_INTx));
       if (cmd & PCI_COMMAND_MASTER)
        {
+         byte latency = get_conf_byte(d, PCI_LATENCY_TIMER);
+         byte cache_line = get_conf_byte(d, PCI_CACHE_LINE_SIZE);
          printf("\tLatency: %d", latency);
          if (min_gnt || max_lat)
            {
@@ -809,16 +892,25 @@ show_verbose(struct device *d)
            printf(", Cache Line Size: %d bytes", cache_line * 4);
          putchar('\n');
        }
-      if (int_pin || irq)
+    }
+
+  if (verbose > 1)
+    {
+      byte int_pin = unknown_config_data ? 0 : get_conf_byte(d, PCI_INTERRUPT_PIN);
+      if (int_pin || p->irq)
        printf("\tInterrupt: pin %c routed to IRQ " PCIIRQ_FMT "\n",
-              (int_pin ? 'A' + int_pin - 1 : '?'), irq);
+              (int_pin ? 'A' + int_pin - 1 : '?'), p->irq);
       if (p->numa_node != -1)
        printf("\tNUMA node: %d\n", p->numa_node);
       if (iommu_group = pci_get_string_property(p, PCI_FILL_IOMMU_GROUP))
        printf("\tIOMMU group: %s\n", iommu_group);
     }
-  else
+
+  if (!unknown_config_data && verbose <= 1)
     {
+      word cmd = get_conf_word(d, PCI_COMMAND);
+      word status = get_conf_word(d, PCI_STATUS);
+      byte latency = get_conf_byte(d, PCI_LATENCY_TIMER);
       printf("\tFlags: ");
       if (cmd & PCI_COMMAND_MASTER)
        printf("bus master, ");
@@ -838,8 +930,8 @@ show_verbose(struct device *d)
             ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_FAST) ? "fast" : "??");
       if (cmd & PCI_COMMAND_MASTER)
        printf(", latency %d", latency);
-      if (irq)
-       printf(", IRQ " PCIIRQ_FMT, irq);
+      if (p->irq)
+       printf(", IRQ " PCIIRQ_FMT, p->irq);
       if (p->numa_node != -1)
        printf(", NUMA node %d", p->numa_node);
       if (iommu_group = pci_get_string_property(p, PCI_FILL_IOMMU_GROUP))
@@ -866,6 +958,8 @@ show_verbose(struct device *d)
     case PCI_HEADER_TYPE_CARDBUS:
       show_htype2(d);
       break;
+    default:
+      show_htype_unknown(d);
     }
 }
 
@@ -876,6 +970,12 @@ show_hex_dump(struct device *d)
 {
   unsigned int i, cnt;
 
+  if (d->no_config_access)
+    {
+      printf("WARNING: Cannot show hex-dump of the config space\n");
+      return;
+    }
+
   cnt = d->config_cached;
   if (opt_hex >= 3 && config_fetch(d, cnt, 256-cnt))
     {
@@ -911,13 +1011,9 @@ static void
 show_machine(struct device *d)
 {
   struct pci_dev *p = d->dev;
-  int c;
-  word sv_id, sd_id;
-  char classbuf[128], vendbuf[128], devbuf[128], svbuf[128], sdbuf[128];
+  char classbuf[256], vendbuf[256], devbuf[256], svbuf[256], sdbuf[256];
   char *dt_node, *iommu_group;
 
-  get_subid(d, &sv_id, &sd_id);
-
   if (verbose)
     {
       pci_fill_info(p, PCI_FILL_PHYS_SLOT | PCI_FILL_NUMA_NODE | PCI_FILL_DT_NODE | PCI_FILL_IOMMU_GROUP);
@@ -930,19 +1026,20 @@ show_machine(struct device *d)
             pci_lookup_name(pacc, vendbuf, sizeof(vendbuf), PCI_LOOKUP_VENDOR, p->vendor_id, p->device_id));
       printf("Device:\t%s\n",
             pci_lookup_name(pacc, devbuf, sizeof(devbuf), PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id));
-      if (sv_id && sv_id != 0xffff)
+      if ((p->known_fields & PCI_FILL_SUBSYS) &&
+         p->subsys_vendor_id && p->subsys_vendor_id != 0xffff)
        {
          printf("SVendor:\t%s\n",
-                pci_lookup_name(pacc, svbuf, sizeof(svbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR, sv_id));
+                pci_lookup_name(pacc, svbuf, sizeof(svbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR, p->subsys_vendor_id));
          printf("SDevice:\t%s\n",
-                pci_lookup_name(pacc, sdbuf, sizeof(sdbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id, sv_id, sd_id));
+                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));
        }
       if (p->phy_slot)
        printf("PhySlot:\t%s\n", p->phy_slot);
-      if (c = get_conf_byte(d, PCI_REVISION_ID))
-       printf("Rev:\t%02x\n", c);
-      if (c = get_conf_byte(d, PCI_CLASS_PROG))
-       printf("ProgIf:\t%02x\n", c);
+      if ((p->known_fields & PCI_FILL_CLASS_EXT) && p->rev_id)
+       printf("Rev:\t%02x\n", p->rev_id);
+      if (p->known_fields & PCI_FILL_CLASS_EXT)
+       printf("ProgIf:\t%02x\n", p->prog_if);
       if (opt_kernel)
        show_kernel_machine(d);
       if (p->numa_node != -1)
@@ -958,14 +1055,15 @@ show_machine(struct device *d)
       print_shell_escaped(pci_lookup_name(pacc, classbuf, sizeof(classbuf), PCI_LOOKUP_CLASS, p->device_class));
       print_shell_escaped(pci_lookup_name(pacc, vendbuf, sizeof(vendbuf), PCI_LOOKUP_VENDOR, p->vendor_id, p->device_id));
       print_shell_escaped(pci_lookup_name(pacc, devbuf, sizeof(devbuf), PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id));
-      if (c = get_conf_byte(d, PCI_REVISION_ID))
-       printf(" -r%02x", c);
-      if (c = get_conf_byte(d, PCI_CLASS_PROG))
-       printf(" -p%02x", c);
-      if (sv_id && sv_id != 0xffff)
+      if ((p->known_fields & PCI_FILL_CLASS_EXT) && p->rev_id)
+       printf(" -r%02x", p->rev_id);
+      if (p->known_fields & PCI_FILL_CLASS_EXT)
+       printf(" -p%02x", p->prog_if);
+      if ((p->known_fields & PCI_FILL_SUBSYS) &&
+         p->subsys_vendor_id && p->subsys_vendor_id != 0xffff)
        {
-         print_shell_escaped(pci_lookup_name(pacc, svbuf, sizeof(svbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR, sv_id));
-         print_shell_escaped(pci_lookup_name(pacc, sdbuf, sizeof(sdbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id, sv_id, sd_id));
+         print_shell_escaped(pci_lookup_name(pacc, svbuf, sizeof(svbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR, p->subsys_vendor_id));
+         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));
        }
       else
        printf(" \"\" \"\"");