]> mj.ucw.cz Git - pciutils.git/blobdiff - lib/generic.c
CXL3.0: Add DVSEC CXLCtrl3 and missing CXLCtl2
[pciutils.git] / lib / generic.c
index 79e1eee1535fc7e2b37ffae5e07f22c4b347ad59..6211c90fbe607d76177925b58049fbae22237fec 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     The PCI Library -- Generic Direct Access Functions
  *
- *     Copyright (c) 1997--2000 Martin Mares <mj@ucw.cz>
+ *     Copyright (c) 1997--2022 Martin Mares <mj@ucw.cz>
  *
  *     Can be freely distributed and used under the terms of the GNU GPL.
  */
 #include "internal.h"
 
 void
-pci_generic_scan_bus(struct pci_access *a, byte *busmap, int bus)
+pci_generic_scan_bus(struct pci_access *a, byte *busmap, int domain, int bus)
 {
   int dev, multi, ht;
-  struct pci_dev *t = pci_alloc_dev(a);
+  struct pci_dev *t;
 
   a->debug("Scanning bus %02x for devices...\n", bus);
   if (busmap[bus])
@@ -23,12 +23,14 @@ pci_generic_scan_bus(struct pci_access *a, byte *busmap, int bus)
       return;
     }
   busmap[bus] = 1;
+  t = pci_alloc_dev(a);
+  t->domain = domain;
   t->bus = bus;
-  for(dev=0; dev<32; dev++)
+  for (dev=0; dev<32; dev++)
     {
       t->dev = dev;
       multi = 0;
-      for(t->func=0; !t->func || multi && t->func<8; t->func++)
+      for (t->func=0; !t->func || multi && t->func<8; t->func++)
        {
          u32 vd = pci_read_long(t, PCI_VENDOR_ID);
          struct pci_dev *d;
@@ -40,6 +42,7 @@ pci_generic_scan_bus(struct pci_access *a, byte *busmap, int bus)
            multi = ht & 0x80;
          ht &= 0x7f;
          d = pci_alloc_dev(a);
+         d->domain = t->domain;
          d->bus = t->bus;
          d->dev = t->dev;
          d->func = t->func;
@@ -54,41 +57,93 @@ pci_generic_scan_bus(struct pci_access *a, byte *busmap, int bus)
              break;
            case PCI_HEADER_TYPE_BRIDGE:
            case PCI_HEADER_TYPE_CARDBUS:
-             pci_generic_scan_bus(a, busmap, pci_read_byte(t, PCI_SECONDARY_BUS));
+             pci_generic_scan_bus(a, busmap, domain, pci_read_byte(t, PCI_SECONDARY_BUS));
              break;
            default:
-             a->debug("Device %02x:%02x.%d has unknown header type %02x.\n", d->bus, d->dev, d->func, ht);
+             a->debug("Device %04x:%02x:%02x.%d has unknown header type %02x.\n", d->domain, d->bus, d->dev, d->func, ht);
            }
        }
     }
+  pci_free_dev(t);
 }
 
 void
-pci_generic_scan(struct pci_access *a)
+pci_generic_scan_domain(struct pci_access *a, int domain)
 {
   byte busmap[256];
 
-  bzero(busmap, sizeof(busmap));
-  pci_generic_scan_bus(a, busmap, 0);
+  memset(busmap, 0, sizeof(busmap));
+  pci_generic_scan_bus(a, busmap, domain, 0);
 }
 
-int
-pci_generic_fill_info(struct pci_dev *d, int flags)
+void
+pci_generic_scan(struct pci_access *a)
+{
+  pci_generic_scan_domain(a, 0);
+}
+
+static int
+get_hdr_type(struct pci_dev *d)
+{
+  if (d->hdrtype < 0)
+    d->hdrtype = pci_read_byte(d, PCI_HEADER_TYPE) & 0x7f;
+  return d->hdrtype;
+}
+
+void
+pci_generic_fill_info(struct pci_dev *d, unsigned int flags)
 {
   struct pci_access *a = d->access;
+  struct pci_cap *cap;
 
-  if (flags & PCI_FILL_IDENT)
+  if (want_fill(d, flags, PCI_FILL_IDENT))
     {
       d->vendor_id = pci_read_word(d, PCI_VENDOR_ID);
       d->device_id = pci_read_word(d, PCI_DEVICE_ID);
     }
-  if (flags & PCI_FILL_IRQ)
+
+  if (want_fill(d, flags, PCI_FILL_CLASS))
+    d->device_class = pci_read_word(d, PCI_CLASS_DEVICE);
+
+  if (want_fill(d, flags, PCI_FILL_CLASS_EXT))
+    {
+      d->prog_if = pci_read_byte(d, PCI_CLASS_PROG);
+      d->rev_id = pci_read_byte(d, PCI_REVISION_ID);
+    }
+
+  if (want_fill(d, flags, PCI_FILL_SUBSYS))
+    {
+      switch (get_hdr_type(d))
+        {
+        case PCI_HEADER_TYPE_NORMAL:
+          d->subsys_vendor_id = pci_read_word(d, PCI_SUBSYSTEM_VENDOR_ID);
+          d->subsys_id = pci_read_word(d, PCI_SUBSYSTEM_ID);
+          break;
+        case PCI_HEADER_TYPE_BRIDGE:
+          cap = pci_find_cap(d, PCI_CAP_ID_SSVID, PCI_CAP_NORMAL);
+          if (cap)
+            {
+              d->subsys_vendor_id = pci_read_word(d, cap->addr + PCI_SSVID_VENDOR);
+              d->subsys_id = pci_read_word(d, cap->addr + PCI_SSVID_DEVICE);
+            }
+          break;
+        case PCI_HEADER_TYPE_CARDBUS:
+          d->subsys_vendor_id = pci_read_word(d, PCI_CB_SUBSYSTEM_VENDOR_ID);
+          d->subsys_id = pci_read_word(d, PCI_CB_SUBSYSTEM_ID);
+          break;
+        default:
+          clear_fill(d, PCI_FILL_SUBSYS);
+        }
+    }
+
+  if (want_fill(d, flags, PCI_FILL_IRQ))
     d->irq = pci_read_byte(d, PCI_INTERRUPT_LINE);
-  if (flags & PCI_FILL_BASES)
+
+  if (want_fill(d, flags, PCI_FILL_BASES))
     {
       int cnt = 0, i;
-      bzero(d->base_addr, sizeof(d->base_addr));
-      switch (d->hdrtype)
+      memset(d->base_addr, 0, sizeof(d->base_addr));
+      switch (get_hdr_type(d))
        {
        case PCI_HEADER_TYPE_NORMAL:
          cnt = 6;
@@ -102,49 +157,41 @@ pci_generic_fill_info(struct pci_dev *d, int flags)
        }
       if (cnt)
        {
-         u16 cmd = pci_read_word(d, PCI_COMMAND);
-         for(i=0; i<cnt; i++)
+         for (i=0; i<cnt; i++)
            {
              u32 x = pci_read_long(d, PCI_BASE_ADDRESS_0 + i*4);
              if (!x || x == (u32) ~0)
                continue;
-             d->base_addr[i] = x;
-             if (x & PCI_BASE_ADDRESS_SPACE_IO)
-               {
-                 if (!a->buscentric && !(cmd & PCI_COMMAND_IO))
-                   d->base_addr[i] = 0;
-               }
-             else if (a->buscentric || (cmd & PCI_COMMAND_MEMORY))
+             if ((x & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
+               d->base_addr[i] = x;
+             else
                {
-                 if ((x & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64)
+                 if ((x & PCI_BASE_ADDRESS_MEM_TYPE_MASK) != PCI_BASE_ADDRESS_MEM_TYPE_64)
+                   d->base_addr[i] = x;
+                 else if (i >= cnt-1)
+                   a->warning("%04x:%02x:%02x.%d: Invalid 64-bit address seen for BAR %d.", d->domain, d->bus, d->dev, d->func, i);
+                 else
                    {
-                     if (i >= cnt-1)
-                       a->warning("%02x:%02x.%d: Invalid 64-bit address seen.", d->bus, d->dev, d->func);
-                     else
-                       {
-                         u32 y = pci_read_long(d, PCI_BASE_ADDRESS_0 + (++i)*4);
-#ifdef HAVE_64BIT_ADDRESS
-                         d->base_addr[i-1] |= ((pciaddr_t) y) << 32;
+                     u32 y = pci_read_long(d, PCI_BASE_ADDRESS_0 + (++i)*4);
+#ifdef PCI_HAVE_64BIT_ADDRESS
+                     d->base_addr[i-1] = x | (((pciaddr_t) y) << 32);
 #else
-                         if (y)
-                           {
-                             a->warning("%02x:%02x.%d 64-bit device address ignored.", d->bus, d->dev, d->func);
-                             d->base_addr[i-1] = 0;
-                           }
+                     if (y)
+                       a->warning("%04x:%02x:%02x.%d 64-bit device address ignored.", d->domain, d->bus, d->dev, d->func);
+                     else
+                       d->base_addr[i-1] = x;
 #endif
-                       }
                    }
                }
-             else
-               d->base_addr[i] = 0;
            }
        }
     }
-  if (flags & PCI_FILL_ROM_BASE)
+
+  if (want_fill(d, flags, PCI_FILL_ROM_BASE))
     {
       int reg = 0;
       d->rom_base_addr = 0;
-      switch (d->hdrtype)
+      switch (get_hdr_type(d))
        {
        case PCI_HEADER_TYPE_NORMAL:
          reg = PCI_ROM_ADDRESS;
@@ -155,12 +202,13 @@ pci_generic_fill_info(struct pci_dev *d, int flags)
        }
       if (reg)
        {
-         u32 a = pci_read_long(d, reg);
-         if (a & PCI_ROM_ADDRESS_ENABLE)
-           d->rom_base_addr = a;
+         u32 u = pci_read_long(d, reg);
+         if (u != 0xffffffff)
+           d->rom_base_addr = u;
        }
     }
-  return flags & ~PCI_FILL_SIZES;
+
+  pci_scan_caps(d, flags);
 }
 
 static int