]> mj.ucw.cz Git - pciutils.git/commitdiff
lspci: add VirtIO SharedMemory capability support master
authorChangyuan Lyu <changyuan.lv@gmail.com>
Sat, 30 Dec 2023 01:37:28 +0000 (17:37 -0800)
committerMartin Mareš <mj@ucw.cz>
Mon, 15 Jul 2024 18:45:24 +0000 (20:45 +0200)
This patch adds the support for VirtIO share memory capability [1].
A shared memory region is defined in a `struct virtio_pci_cap64`
where the highest 32 bits of `offset` and `size` are appened to the
original `struct virtio_pci_cap`.

With this patch, a VirtIO PMEM device (ID 27) shows like the
following:

```
00:02.0 Class ffff: Device 1af4:105b (rev 01)
        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 0
        Region 0: Memory at 100001000 (64-bit, non-prefetchable) [size=4K]
        Region 2: Memory at 101000000 (64-bit, non-prefetchable) [size=16M]
        Capabilities: [40] Vendor Specific Information: VirtIO: CommonCfg
                BAR=0 offset=00000000 size=0000003c
        Capabilities: [50] Vendor Specific Information: VirtIO: ISR
                BAR=0 offset=0000003c size=00000001
        Capabilities: [60] Vendor Specific Information: VirtIO: Notify
                BAR=0 offset=00000040 size=00000002 multiplier=00000002
        Capabilities: [78] MSI-X: Enable+ Count=2 Masked-
                Vector table: BAR=0 offset=00000058
                PBA: BAR=0 offset=00000078
        Capabilities: [88] Vendor Specific Information: VirtIO: DeviceCfg
                BAR=0 offset=00000044 size=00000010
        Capabilities: [98] Vendor Specific Information: VirtIO: SharedMemory
                BAR=2 offset=0000000000000000 size=0000000001000000 id=0
        Kernel driver in use: virtio-pci
```

[1] Sec 4.1.4.7 https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-1240004

Signed-off-by: Changyuan Lyu <changyuan.lv@gmail.com>
lib/ecam.c
ls-caps-vendor.c
pcilib.man
tests/cap-vendor-virtio

index f953e1072046e74a75484af70dad86cb062fef47..edb2494e2b9d4848281f266a9b5ad97df6f7a3c9 100644 (file)
@@ -464,7 +464,7 @@ find_mcfg(struct pci_access *a, const char *acpimcfg, const char *efisystab, int
 #ifdef PCI_OS_WINDOWS
       if (strcmp(acpimcfg, "GetSystemFirmwareTable()") == 0)
         {
-          a->debug("reading acpi mcfg via GetSystemFirmwareTable()...");
+          a->debug("reading ACPI mcfg via GetSystemFirmwareTable()...");
           mcfg = get_system_firmware_table_acpi_mcfg(a);
           if (mcfg)
             return mcfg;
@@ -481,7 +481,7 @@ find_mcfg(struct pci_access *a, const char *acpimcfg, const char *efisystab, int
         {
           path = mcfg_glob.gl_pathv[0];
 #endif
-          a->debug("reading acpi mcfg file: %s...", path);
+          a->debug("reading ACPI mcfg file: %s...", path);
           mcfg_file = fopen(path, "rb");
 #ifndef PCI_OS_WINDOWS
           globfree(&mcfg_glob);
@@ -504,6 +504,7 @@ find_mcfg(struct pci_access *a, const char *acpimcfg, const char *efisystab, int
                       fclose(mcfg_file);
                       return mcfg;
                     }
+                  pci_mfree(mcfg);
                 }
               fclose(mcfg_file);
             }
index 62ee586dcd6de978162cb8e5c7b813fe7fe4df96..a69ddd6915224703fcd910452ebf7003253ec4cd 100644 (file)
@@ -19,6 +19,10 @@ show_vendor_caps_virtio(struct device *d, int where, int cap)
   int length = BITS(cap, 0, 8);
   int type = BITS(cap, 8, 8);
   char *tname;
+  u32 offset;
+  u32 size;
+  u32 offset_hi;
+  u32 size_hi;
 
   if (length < 16)
     return 0;
@@ -39,6 +43,9 @@ show_vendor_caps_virtio(struct device *d, int where, int cap)
     case 4:
       tname = "DeviceCfg";
       break;
+    case 8:
+      tname = "SharedMemory";
+      break;
     default:
       tname = "<unknown>";
       break;
@@ -49,10 +56,20 @@ show_vendor_caps_virtio(struct device *d, int where, int cap)
   if (verbose < 2)
     return 1;
 
-  printf("\t\tBAR=%d offset=%08x size=%08x",
-        get_conf_byte(d, where +  4),
-        get_conf_long(d, where +  8),
-        get_conf_long(d, where + 12));
+  offset = get_conf_long(d, where + 8);
+  size = get_conf_long(d, where + 12);
+  if (type != 8)
+    printf("\t\tBAR=%d offset=%08x size=%08x",
+          get_conf_byte(d, where +  4), offset, size);
+  else {
+    offset_hi = get_conf_long(d, where + 16);
+    size_hi = get_conf_long(d, where + 20);
+    printf("\t\tBAR=%d offset=%016lx size=%016lx id=%d",
+          get_conf_byte(d, where +  4),
+          (u64) offset | (u64) offset_hi << 32,
+          (u64) size | (u64) size_hi << 32,
+          get_conf_byte(d, where + 5));
+  }
 
   if (type == 2 && length >= 20)
     printf(" multiplier=%08x", get_conf_long(d, where+16));
@@ -61,6 +78,157 @@ show_vendor_caps_virtio(struct device *d, int where, int cap)
   return 1;
 }
 
+static int
+show_vendor_caps_intel(struct device *d, int where, int cap)
+{
+  int length = BITS(cap, 0, 8);
+  int version = BITS(cap, 8, 4);
+  int type = BITS(cap, 12, 4);
+  u32 l;
+
+  if (type == 0)
+    {
+      printf("Intel Capabilities v%d\n", version);
+      /*
+       * Intel Capabilities is used at least on Intel Host Bridge / DRAM Controller
+       * and Intel Integrated Graphics Controller. Format of the CAPID0_<X>
+       * registers parsed below matches Cap Version 1 which is used since second
+       * generation of the Intel Core processors (Sandy Bridge). Parsing of other
+       * versions is not currently supported.
+       */
+      if (version != 1)
+        return 1;
+    }
+  else if (type == 1)
+    {
+      printf("Intel Feature Detection\n");
+      /*
+       * Intel Feature Detection Capabilities is used on Intel LPC Controller.
+       * Capabilities are accessed indirectly by writing indirect capability
+       * register to PCI config space. Because lspci cannot write to PCI config
+       * space, it is not possible to read or parse Intel Feature Vector Space.
+       */
+      return 1;
+    }
+  else
+    {
+      printf("Intel <unknown>\n");
+      return 1;
+    }
+
+  if (!config_fetch(d, where, length))
+    return 0;
+
+  /* CAPID0_A */
+  if (length >= 8)
+    {
+      l = get_conf_long(d, where + 4);
+      printf("\t\tCapA:");
+      printf(" Peg60Dis%c", FLAG(l, BIT(31)));
+      printf(" Peg12Dis%c", FLAG(l, BIT(30)));
+      printf(" Peg11Dis%c", FLAG(l, BIT(29)));
+      printf(" Peg10Dis%c", FLAG(l, BIT(28)));
+      printf(" PeLWUDis%c", FLAG(l, BIT(27)));
+      printf(" DmiWidth=x%u", (l & BIT(26)) ? 2 : 4);
+      printf("\n\t\t     ");
+      printf(" EccDis%c", FLAG(l, BIT(25)));
+      printf(" ForceEccEn%c", FLAG(l, BIT(24)));
+      printf(" VTdDis%c", FLAG(l, BIT(23)));
+      printf(" DmiG2Dis%c", FLAG(l, BIT(22)));
+      printf(" PegG2Dis%c", FLAG(l, BIT(21)));
+      printf(" DDRMaxSize=");
+      if (BITS(l, 19, 2) == 0)
+        printf("Unlimited");
+      else
+        printf("%gGB/chan", 512 * (1 << ((3-BITS(l, 19, 2))*2)) / 1024.0);
+      printf("\n\t\t     ");
+      printf(" 1NDis%c", FLAG(l, BIT(17)));
+      printf(" CDDis%c", FLAG(l, BIT(15)));
+      printf(" DDPCDis%c", FLAG(l, BIT(14)));
+      printf(" X2APICEn%c", FLAG(l, BIT(13)));
+      printf(" PDCDis%c", FLAG(l, BIT(12)));
+      printf(" IGDis%c", FLAG(l, BIT(11)));
+      printf(" CDID=%u", BITS(l, 8, 2));
+      printf(" CRID=%u", BITS(l, 4, 4));
+      printf("\n\t\t     ");
+      printf(" DDROCCAP%c", FLAG(l, BIT(3)));
+      printf(" OCEn%c", FLAG(l, BIT(2)));
+      printf(" DDRWrtVrefEn%c", FLAG(l, BIT(1)));
+      printf(" DDR3LEn%c", FLAG(l, BIT(0)));
+      printf("\n");
+    }
+
+  /* CAPID0_B */
+  if (length >= 12)
+    {
+      l = get_conf_long(d, where + 8);
+      printf("\t\tCapB:");
+      printf(" ImguDis%c", FLAG(l, BIT(31)));
+      printf(" OCbySSKUCap%c", FLAG(l, BIT(30)));
+      printf(" OCbySSKUEn%c", FLAG(l, BIT(29)));
+      printf(" SMTCap%c", FLAG(l, BIT(28)));
+      printf(" CacheSzCap 0x%x", BITS(l, 25, 3));
+      printf("\n\t\t     ");
+      printf(" SoftBinCap%c", FLAG(l, BIT(24)));
+      printf(" DDR3MaxFreqWithRef100=");
+      if (BITS(l, 21, 3) == 0)
+        printf("Disabled");
+      else if (BITS(l, 21, 3) == 7)
+        printf("Unlimited");
+      else
+        printf("%uMHz", (6+BITS(l, 21, 3)) * 200);
+      printf(" PegG3Dis%c", FLAG(l, BIT(20)));
+      printf("\n\t\t     ");
+      printf(" PkgTyp%c", FLAG(l, BIT(19)));
+      printf(" AddGfxEn%c", FLAG(l, BIT(18)));
+      printf(" AddGfxCap%c", FLAG(l, BIT(17)));
+      printf(" PegX16Dis%c", FLAG(l, BIT(16)));
+      printf(" DmiG3Dis%c", FLAG(l, BIT(15)));
+      printf(" GmmDis%c", FLAG(l, BIT(8)));
+      printf("\n\t\t     ");
+      printf(" DDR3MaxFreq=%uMHz", (11-BITS(l, 4, 2)) * 2666 / 10);
+      printf(" LPDDR3En%c", FLAG(l, BIT(2)));
+      printf("\n");
+    }
+
+  /* CAPID0_C */
+  if (length >= 16)
+    {
+      l = get_conf_long(d, where + 12);
+      printf("\t\tCapC:");
+      printf(" PegG4Dis%c", FLAG(l, BIT(28)));
+      printf(" DDR4MaxFreq=");
+      if (BITS(l, 23, 4) == 0)
+        printf("Unlimited");
+      else
+        printf("%uMHz", BITS(l, 0, 4) * 2666 / 10);
+      printf(" LPDDREn%c", FLAG(l, BIT(22)));
+      printf(" LPDDR4MaxFreq=");
+      if (BITS(l, 17, 4) == 0)
+        printf("Unlimited");
+      else
+        printf("%uMHz", BITS(l, 0, 4) * 2666 / 10);
+      printf(" LPDDR4En%c", FLAG(l, BIT(16)));
+      printf("\n\t\t     ");
+      printf(" QClkGvDis%c", FLAG(l, BIT(14)));
+      printf(" SgxDis%c", FLAG(l, BIT(9)));
+      printf(" BClkOC=%s", BITS(l, 7, 2) == 0 ? "Disabled" :
+                           BITS(l, 7, 2) == 1 ? "115MHz" :
+                           BITS(l, 7, 2) == 2 ? "130MHz" :
+                                                "Unlimited");
+      printf(" IddDis%c", FLAG(l, BIT(6)));
+      printf(" Pipe3Dis%c", FLAG(l, BIT(5)));
+      printf(" Gear1MaxFreq=");
+      if (BITS(l, 0, 4) == 0)
+        printf("Unlimited");
+      else
+        printf("%uMHz", BITS(l, 0, 4) * 2666 / 10);
+      printf("\n");
+    }
+
+  return 1;
+}
+
 static int
 do_show_vendor_caps(struct device *d, int where, int cap)
 {
@@ -71,6 +239,8 @@ do_show_vendor_caps(struct device *d, int where, int cap)
          d->dev->device_id <= 0x107f)
        return show_vendor_caps_virtio(d, where, cap);
       break;
+    case 0x8086: /* Intel */
+      return show_vendor_caps_intel(d, where, cap);
     }
   return 0;
 }
index 79a1b146e5956e7c07938eeaa415e70a53c86387..2fa5bb9b2ed9e2eb4d099a3f535c0b11209dd1a3 100644 (file)
@@ -179,7 +179,16 @@ Path to the procfs bus tree.
 Path to the sysfs device tree.
 .TP
 .B devmem.path
-Path to the /dev/mem device.
+Path to the /dev/mem device or path to the \\Device\\PhysicalMemory NT section
+or name of the platform specific physical address access method. Generally on
+POSIX systems it is path to memory device and on Windows systems it is path to
+memory NT section. Additionally on 32-bit Windows systems are recognized also
+platform methods: \fIvxdcall\fP, \fIw32skrnl\fP. On DOS/DJGPP systems are
+recognized only platform methods: \fIauto\fP, \fIdevmap\fP, \fIphysmap\fP.
+DJGPP's \fIdevmap\fP method uses DPMI 1.0 functions 0508H (Map Device in Memory
+Block) and 0509H (Map Conventional Memory in Memory Block). DJGPP's \fIphysmap\fP
+method uses DPMI 0.9 function 0800H (Physical Address Mapping). DJGPP's \fIauto\fP
+parameter automatically chooses one of the mentioned method supported by the system.
 .TP
 .B mmio-conf1.addrs
 Physical addresses of memory-mapped I/O ports for Intel configuration mechanism 1.
index 2d04831b2bc7b064f13811a0fe121a140dec0262..adaebf88f8cfe4f07e5f1b8592dba7ab2eafb336 100644 (file)
@@ -39,3 +39,39 @@ d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 
+00:04.0 Mass storage controller: Red Hat, Inc. Virtio file system (rev 01)
+       Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
+       Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
+       Latency: 0
+       Region 0: Memory at a0008000 (32-bit, non-prefetchable) [size=16K]
+       Region 2: Memory at 200000000 (64-bit, prefetchable) [size=1G]
+       Capabilities: [40] MSI-X: Enable+ Count=3 Masked-
+               Vector table: BAR=0 offset=00000000
+               PBA: BAR=0 offset=00002000
+       Capabilities: [4c] Vendor Specific Information: VirtIO: CommonCfg
+               BAR=0 offset=00003000 size=0000003c
+       Capabilities: [5c] Vendor Specific Information: VirtIO: ISR
+               BAR=0 offset=0000303c size=00000004
+       Capabilities: [6c] Vendor Specific Information: VirtIO: Notify
+               BAR=0 offset=00003040 size=00000008 multiplier=00000004
+       Capabilities: [80] Vendor Specific Information: VirtIO: DeviceCfg
+               BAR=0 offset=00003048 size=0000002c
+       Capabilities: [90] Vendor Specific Information: VirtIO: SharedMemory
+               BAR=2 offset=0000000000000000 size=0000000040000000 id=0
+       Kernel driver in use: virtio-pci
+00: f4 1a 5a 10 06 04 10 00 01 00 80 01 00 00 00 00
+10: 00 80 00 a0 00 00 00 00 0c 00 00 00 02 00 00 00
+20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 5a 10
+30: 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00
+40: 11 4c 02 80 00 00 00 00 00 20 00 00 09 5c 10 01
+50: 00 00 00 00 00 30 00 00 3c 00 00 00 09 6c 10 03
+60: 00 00 00 00 3c 30 00 00 04 00 00 00 09 80 14 02
+70: 00 00 00 00 40 30 00 00 08 00 00 00 04 00 00 00
+80: 09 90 10 04 00 00 00 00 48 30 00 00 2c 00 00 00
+90: 09 00 18 08 02 00 00 00 00 00 00 00 00 00 00 40
+a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00