From 67da1792a85a4ad46c67ea57839195f483311164 Mon Sep 17 00:00:00 2001
From: Martin Mares <mj@ucw.cz>
Date: Wed, 18 May 2011 10:54:32 +0200
Subject: [PATCH] TPH and LTR capability reporting

Report information about transaction processing hints and latency
tolerance reporting capabilities, if present.

Patch by Jesse Barnes
---
 lib/header.h |   20 ++++++++++++++++
 ls-ecaps.c   |   71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 91 insertions(+), 0 deletions(-)

diff --git a/lib/header.h b/lib/header.h
index 5d285c2..d481f27 100644
--- a/lib/header.h
+++ b/lib/header.h
@@ -223,6 +223,8 @@
 #define PCI_EXT_CAP_ID_ARI	0x0e	/* Alternative Routing-ID Interpretation */
 #define PCI_EXT_CAP_ID_ATS	0x0f	/* Address Translation Service */
 #define PCI_EXT_CAP_ID_SRIOV	0x10	/* Single Root I/O Virtualization */
+#define PCI_EXT_CAP_ID_TPH	0x17	/* Transaction processing hints */
+#define PCI_EXT_CAP_ID_LTR	0x18	/* Latency Tolerance Reporting */
 
 /*** Definitions of capabilities ***/
 
@@ -1028,6 +1030,24 @@
 #define PCI_IOV_MSA_BIR(x)	((x) & 7) /* VF Migration State BIR */
 #define PCI_IOV_MSA_OFFSET(x)	((x) & 0xfffffff8) /* VF Migration State Offset */
 
+/* Transaction Processing Hints */
+#define PCI_TPH_CAPABILITIES	4
+#define   PCI_TPH_INTVEC_SUP	(1<<1)	/* Supports interrupt vector mode */
+#define   PCI_TPH_DEV_SUP      	(1<<2)	/* Device specific mode supported */
+#define   PCI_TPH_EXT_REQ_SUP	(1<<8)	/* Supports extended requests */
+#define   PCI_TPH_ST_LOC_MASK	(3<<9)	/* Steering table location bits */
+#define     PCI_TPH_ST_NONE	(0<<9)	/* No steering table */
+#define     PCI_TPH_ST_CAP	(1<<9)	/* Steering table in TPH cap */
+#define     PCI_TPH_ST_MSIX	(2<<9)	/* Steering table in MSI-X table */
+#define   PCI_TPH_ST_SIZE_SHIFT	(16)	/* Encoded as size - 1 */
+
+/* Latency Tolerance Reporting */
+#define PCI_LTR_MAX_SNOOP	4	/* 16 bit value */
+#define   PCI_LTR_VALUE_MASK	(0x3ff)
+#define   PCI_LTR_SCALE_SHIFT	(10)
+#define   PCI_LTR_SCALE_MASK	(7)
+#define PCI_LTR_MAX_NOSNOOP	6	/* 16 bit value */
+
 /*
  * The PCI interface treats multi-function devices as independent
  * devices.  The slot/function address of each device is encoded
diff --git a/ls-ecaps.c b/ls-ecaps.c
index ed10f72..cd342aa 100644
--- a/ls-ecaps.c
+++ b/ls-ecaps.c
@@ -12,6 +12,71 @@
 #include "lspci.h"
 
 static void
+cap_tph(struct device *d, int where)
+{
+  u32 tph_cap;
+  printf("Transaction Processing Hints\n");
+  if (verbose < 2)
+    return;
+
+  if (!config_fetch(d, where + PCI_TPH_CAPABILITIES, 4))
+    return;
+
+  tph_cap = get_conf_long(d, where + PCI_TPH_CAPABILITIES);
+
+  if (tph_cap & PCI_TPH_INTVEC_SUP)
+    printf("\t\tInterrupt vector mode supported\n");
+  if (tph_cap & PCI_TPH_DEV_SUP)
+    printf("\t\tDevice specific mode supported\n");
+  if (tph_cap & PCI_TPH_EXT_REQ_SUP)
+    printf("\t\tExtended requester support\n");
+
+  switch (tph_cap & PCI_TPH_ST_LOC_MASK) {
+  case PCI_TPH_ST_NONE:
+    printf("\t\tNo steering table available\n");
+    break;
+  case PCI_TPH_ST_CAP:
+    printf("\t\tSteering table in TPH capability structure\n");
+    break;
+  case PCI_TPH_ST_MSIX:
+    printf("\t\tSteering table in MSI-X table\n");
+    break;
+  default:
+    printf("\t\tReserved steering table location\n");
+    break;
+  }
+}
+
+static u32
+cap_ltr_scale(u8 scale)
+{
+  return 1 << (scale * 5);
+}
+
+static void
+cap_ltr(struct device *d, int where)
+{
+  u32 scale;
+  u16 snoop, nosnoop;
+  printf("Latency Tolerance Reporting\n");
+  if (verbose < 2)
+    return;
+
+  if (!config_fetch(d, where + PCI_LTR_MAX_SNOOP, 4))
+    return;
+
+  snoop = get_conf_word(d, where + PCI_LTR_MAX_SNOOP);
+  scale = cap_ltr_scale((snoop >> PCI_LTR_SCALE_SHIFT) & PCI_LTR_SCALE_MASK);
+  printf("\t\tMax snoop latency: %lldns\n",
+	 ((unsigned long long)snoop & PCI_LTR_VALUE_MASK) * scale);
+
+  nosnoop = get_conf_word(d, where + PCI_LTR_MAX_NOSNOOP);
+  scale = cap_ltr_scale((nosnoop >> PCI_LTR_SCALE_SHIFT) & PCI_LTR_SCALE_MASK);
+  printf("\t\tMax no snoop latency: %lldns\n",
+	 ((unsigned long long)nosnoop & PCI_LTR_VALUE_MASK) * scale);
+}
+
+static void
 cap_dsn(struct device *d, int where)
 {
   u32 t1, t2;
@@ -455,6 +520,12 @@ show_ext_caps(struct device *d)
 	  case PCI_EXT_CAP_ID_SRIOV:
 	    cap_sriov(d, where);
 	    break;
+	  case PCI_EXT_CAP_ID_TPH:
+	    cap_tph(d, where);
+	    break;
+	  case PCI_EXT_CAP_ID_LTR:
+	    cap_ltr(d, where);
+	    break;
 	  default:
 	    printf("#%02x\n", id);
 	    break;
-- 
1.7.6.5


