diff mbox series

[pciutils,2/2] pciutils: Add decode support for IDE Extended Capability

Message ID 20231230124239.310927-3-aik@amd.com (mailing list archive)
State Superseded
Delegated to: Bjorn Helgaas
Headers show
Series lspci: Adding TDISP, IDE | expand

Commit Message

Alexey Kardashevskiy Dec. 30, 2023, 12:42 p.m. UTC
IDE (Integrity & Data Encryption) Extended Capability defined in [1]
implements control of the PCI link encryption.

The example output is:

Capabilities: [830 v1] IDE
	IDECap: Lnk=1 Sel=1 FlowThru- PartHdr- Aggr- PCPC- IDE_KM+
	IDECtl: IntEn-
	LinkIDE#0 Ctl: En- NPR- PR- CPL- PCRC- HdrEnc=no Alg='AES-GCM 256 key size, 96b MAC' TC0 ID0
	LinkIDE#0 Sta: Status=secure RecvChkFail-
	SelectiveIDE#0 Ctl: En- NPR- PR- CPL- PCRC- HdrEnc=no Alg='AES-GCM 256 key size, 96b MAC' TC0 ID0
	SelectiveIDE#0 Sta: insecure RecvChkFail-
	SelectiveIDE#0 RID: Valid- Base=0 Limit=0 SegBase=0

[1] PCIe r6.0.1, sections 6.33, 7.9.26

Signed-off-by: Alexey Kardashevskiy <aik@amd.com>
---
 lib/header.h |  61 ++++++++
 ls-ecaps.c   | 162 ++++++++++++++++++++
 2 files changed, 223 insertions(+)

Comments

Alexey Kardashevskiy Jan. 11, 2024, 3:52 a.m. UTC | #1
On 30/12/23 23:42, Alexey Kardashevskiy wrote:
> IDE (Integrity & Data Encryption) Extended Capability defined in [1]
> implements control of the PCI link encryption.
> 
> The example output is:
> 
> Capabilities: [830 v1] IDE
> 	IDECap: Lnk=1 Sel=1 FlowThru- PartHdr- Aggr- PCPC- IDE_KM+
> 	IDECtl: IntEn-
> 	LinkIDE#0 Ctl: En- NPR- PR- CPL- PCRC- HdrEnc=no Alg='AES-GCM 256 key size, 96b MAC' TC0 ID0
> 	LinkIDE#0 Sta: Status=secure RecvChkFail-
> 	SelectiveIDE#0 Ctl: En- NPR- PR- CPL- PCRC- HdrEnc=no Alg='AES-GCM 256 key size, 96b MAC' TC0 ID0
> 	SelectiveIDE#0 Sta: insecure RecvChkFail-
> 	SelectiveIDE#0 RID: Valid- Base=0 Limit=0 SegBase=0


Ping? Suspiciously quiet :)

This is also missing:

--- a/setpci.c
+++ b/setpci.c
@@ -396,6 +396,7 @@ static const struct reg_name pci_reg_names[] = {
    { 0x20027,   0, 0, 0x0, "ECAP_LMR" },
    { 0x20028,   0, 0, 0x0, "ECAP_HIER_ID" },
    { 0x20029,   0, 0, 0x0, "ECAP_NPEM" },
+  { 0x20030,   0, 0, 0x0, "ECAP_IDE" },

Which reminded me - one thing I want to do with setpci is changing the 
"En-"s above to "En+". At the moment setpci.c seems only allowing 
offsets into a ecapability which is tricky to use as offsets of 
"LinkIDE#NN Ctl" and "SelectiveIDE#NN Ctl" are not fixed - these are 
variable length arrays.

So, I could
1) teach setpci do parsing (repeat what s-ecaps.c does) to allow 
register names, like "setpci CAP_IDE+LinkIDE#4Ctl", something like this.

2) dump offsets as ([24] in this example and use offsets with setpci 
which it can do now):

LinkIDE#0 Ctl [24]: En- NPR- PR- CPL- PCRC- HdrEnc=no Alg='AES-GCM 256 
key size, 96b MAC' TC0 ID0

3) leave lspci/setpci alone and do it elsewhere.

Any advice? Thanks,

> 
> [1] PCIe r6.0.1, sections 6.33, 7.9.26
> 
> Signed-off-by: Alexey Kardashevskiy <aik@amd.com>
> ---
>   lib/header.h |  61 ++++++++
>   ls-ecaps.c   | 162 ++++++++++++++++++++
>   2 files changed, 223 insertions(+)
> 
> diff --git a/lib/header.h b/lib/header.h
> index 47ee8a6..5df2f57 100644
> --- a/lib/header.h
> +++ b/lib/header.h
> @@ -256,6 +256,7 @@
>   #define PCI_EXT_CAP_ID_NPEM	0x29	/* Native PCIe Enclosure Management */
>   #define PCI_EXT_CAP_ID_32GT	0x2a	/* Physical Layer 32.0 GT/s */
>   #define PCI_EXT_CAP_ID_DOE	0x2e	/* Data Object Exchange */
> +#define PCI_EXT_CAP_ID_IDE	0x30	/* IDE */
>   
>   /*** Definitions of capabilities ***/
>   
> @@ -1416,6 +1417,66 @@
>   #define  PCI_DOE_STS_ERROR		0x4	/* DOE Error */
>   #define  PCI_DOE_STS_OBJECT_READY	0x80000000 /* Data Object Ready */
>   
> +/* IDE Extended Capability */
> +#define PCI_IDE_CAP		0x4
> +#define  PCI_IDE_CAP_LINK_IDE_SUPP	0x1	/* Link IDE Stream Supported */
> +#define  PCI_IDE_CAP_SELECTIVE_IDE_SUPP 0x2	/* Selective IDE Streams Supported */
> +#define  PCI_IDE_CAP_FLOWTHROUGH_IDE_SUPP 0x4	/* Flow-Through IDE Stream Supported */
> +#define  PCI_IDE_CAP_PARTIAL_HEADER_ENC_SUPP 0x8 /* Partial Header Encryption Supported */
> +#define  PCI_IDE_CAP_AGGREGATION_SUPP	0x10	/* Aggregation Supported */
> +#define  PCI_IDE_CAP_PCRC_SUPP		0x20	/* PCRC Supported */
> +#define  PCI_IDE_CAP_IDE_KM_SUPP	0x40	/* IDE_KM Protocol Supported */
> +#define  PCI_IDE_CAP_ALG(x)	(((x) >> 8) & 0x1f) /* Supported Algorithms */
> +#define  PCI_IDE_CAP_ALG_AES_GCM_256	0	/* AES-GCM 256 key size, 96b MAC */
> +#define  PCI_IDE_CAP_LINK_TC_NUM(x)		(((x) >> 13) & 0x7) /* Number of TCs Supported for Link IDE */
> +#define  PCI_IDE_CAP_SELECTIVE_STREAMS_NUM(x)	(((x) >> 16) & 0xff) /* Number of Selective IDE Streams Supported */
> +#define PCI_IDE_CTL		0x8
> +#define  PCI_IDE_CTL_FLOWTHROUGH_IDE	0x4	/* Flow-Through IDE Stream Enabled */
> +#define PCI_IDE_LINK_STREAM		0xC
> +/* Link IDE Stream block, up to PCI_IDE_CAP_LINK_TC_NUM */
> +/* Link IDE Stream Control Register */
> +#define  PCI_IDE_LINK_CTL_EN		0x1	/* Link IDE Stream Enable */
> +#define  PCI_IDE_LINK_CTL_TX_AGGR_NPR(x)(((x) >> 2) & 0x3) /* Tx Aggregation Mode NPR */
> +#define  PCI_IDE_LINK_CTL_TX_AGGR_PR(x)	(((x) >> 4) & 0x3) /* Tx Aggregation Mode PR */
> +#define  PCI_IDE_LINK_CTL_TX_AGGR_CPL(x)(((x) >> 6) & 0x3) /* Tx Aggregation Mode CPL */
> +#define  PCI_IDE_LINK_CTL_PCRC_EN	0x100	/* PCRC Enable */
> +#define  PCI_IDE_LINK_CTL_PART_ENC(x)	(((x) >> 10) & 0xf)  /* Partial Header Encryption Mode */
> +#define  PCI_IDE_LINK_CTL_ALG(x)	(((x) >> 14) & 0x1f) /* Selected Algorithm */
> +#define  PCI_IDE_LINK_CTL_TC(x)		(((x) >> 19) & 0x7)  /* Traffic Class */
> +#define  PCI_IDE_LINK_CTL_ID(x)		(((x) >> 24) & 0xff) /* Stream ID */
> +/* Link IDE Stream Status Register */
> +#define  PCI_IDE_LINK_STS_STATUS(x)	((x) & 0xf) /* Link IDE Stream State */
> +#define  PCI_IDE_LINK_STS_RECVD_INTEGRITY_CHECK	0x80000000 /* Received Integrity Check Fail Message */
> +/* Selective IDE Stream block, up to PCI_IDE_CAP_SELECTIVE_STREAMS_NUM */
> +/* Selective IDE Stream Capability Register */
> +#define  PCI_IDE_SEL_CAP_BLOCKS_NUM(x)	((x) & 0xf) /* Number of Address Association Register Blocks */
> +/* Selective IDE Stream Control Register */
> +#define  PCI_IDE_SEL_CTL_EN		0x1	/* Selective IDE Stream Enable */
> +#define  PCI_IDE_SEL_CTL_TX_AGGR_NPR(x)	(((x) >> 2) & 0x3) /* Tx Aggregation Mode NPR */
> +#define  PCI_IDE_SEL_CTL_TX_AGGR_PR(x)	(((x) >> 4) & 0x3) /* Tx Aggregation Mode PR */
> +#define  PCI_IDE_SEL_CTL_TX_AGGR_CPL(x)	(((x) >> 6) & 0x3) /* Tx Aggregation Mode CPL */
> +#define  PCI_IDE_SEL_CTL_PCRC_EN	0x100	/* PCRC Enable */
> +#define  PCI_IDE_SEL_CTL_PART_ENC(x)	(((x) >> 10) & 0xf)  /* Partial Header Encryption Mode */
> +#define  PCI_IDE_SEL_CTL_ALG(x)		(((x) >> 14) & 0x1f) /* Selected Algorithm */
> +#define  PCI_IDE_SEL_CTL_TC(x)		(((x) >> 19) & 0x7)  /* Traffic Class */
> +#define  PCI_IDE_SEL_CTL_DEFAULT	0x400000 /* Default Stream */
> +#define  PCI_IDE_SEL_CTL_ID(x)		(((x) >> 24) & 0xff) /* Stream ID */
> +/* Selective IDE Stream Status Register */
> +#define  PCI_IDE_SEL_STS_STATUS(x)	((x) & 0xf) /* Selective IDE Stream State */
> +#define  PCI_IDE_SEL_STS_RECVD_INTEGRITY_CHECK	0x80000000 /* Received Integrity Check Fail Message */
> +/* IDE RID Association Register 1 */
> +#define  PCI_IDE_SEL_RID_1_LIMIT(x)	(((x) >> 8) & 0xffff) /* RID Limit */
> +/* IDE RID Association Register 2 */
> +#define  PCI_IDE_SEL_RID_2_VALID	0x1	/* Valid */
> +#define  PCI_IDE_SEL_RID_2_BASE(x)	(((x) >> 8) & 0xffff) /* RID Base */
> +#define  PCI_IDE_SEL_RID_2_SEG_BASE(x)	(((x) >> 24) & 0xff) /* Segmeng Base */
> +/* Selective IDE Address Association Register Block, up to PCI_IDE_SEL_CAP_BLOCKS_NUM */
> +#define  PCI_IDE_SEL_ADDR_1_VALID	0x1	/* Valid */
> +#define  PCI_IDE_SEL_ADDR_1_BASE_LOW(x)	(((x) >> 8) & 0xfff) /* Memory Base Lower */
> +#define  PCI_IDE_SEL_ADDR_1_LIMIT_LOW(x)(((x) >> 20) & 0xfff) /* Memory Limit Lower */
> +/* IDE Address Association Register 2 is "Memory Limit Upper" */
> +/* IDE Address Association Register 3 is "Memory Base Upper" */
> +
>   /*
>    * 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 2d7d827..9f6c3f8 100644
> --- a/ls-ecaps.c
> +++ b/ls-ecaps.c
> @@ -1468,6 +1468,165 @@ cap_doe(struct device *d, int where)
>   	 FLAG(l, PCI_DOE_STS_OBJECT_READY));
>   }
>   
> +static void
> +cap_ide(struct device *d, int where)
> +{
> +    const char *hdr_enc_mode[] = { "no", "17:2", "25:2", "33:2", "41:2" };
> +    const char *algo[] = { "AES-GCM 256 key size, 96b MAC" };
> +    const char *stream_state[] = { "insecure", "secure" };
> +    const char *aggr[] = { "-", "=2", "=4", "=8" };
> +    u32 l, l2, linknum = 0, selnum = 0, addrnum, off, i, j;
> +    char buf1[16], buf2[16];
> +
> +    printf("IDE\n");
> +
> +    if (verbose < 2)
> +        return;
> +
> +    if (!config_fetch(d, where + PCI_IDE_CAP, 8))
> +      {
> +        printf("\t\t<unreadable>\n");
> +        return;
> +      }
> +
> +    l = get_conf_long(d, where + PCI_IDE_CAP);
> +    if (l & PCI_IDE_CAP_LINK_IDE_SUPP)
> +        linknum = PCI_IDE_CAP_LINK_TC_NUM(l) + 1;
> +    if (l & PCI_IDE_CAP_SELECTIVE_IDE_SUPP)
> +        selnum = PCI_IDE_CAP_SELECTIVE_STREAMS_NUM(l) + 1;
> +
> +    printf("\t\tIDECap: Lnk=%d Sel=%d FlowThru%c PartHdr%c Aggr%c PCPC%c IDE_KM%c\n",
> +      linknum,
> +      selnum,
> +      FLAG(l, PCI_IDE_CAP_FLOWTHROUGH_IDE_SUPP),
> +      FLAG(l, PCI_IDE_CAP_PARTIAL_HEADER_ENC_SUPP),
> +      FLAG(l, PCI_IDE_CAP_AGGREGATION_SUPP),
> +      FLAG(l, PCI_IDE_CAP_PCRC_SUPP),
> +      FLAG(l, PCI_IDE_CAP_IDE_KM_SUPP));
> +
> +    l = get_conf_long(d, where + PCI_IDE_CTL);
> +    printf("\t\tIDECtl: IntEn%c\n",
> +      FLAG(l, PCI_IDE_CTL_FLOWTHROUGH_IDE));
> +
> +    // The rest of the capability is variable length arrays
> +    off = where + PCI_IDE_CAP + PCI_IDE_LINK_STREAM;
> +
> +    // Link IDE Register Block repeated 0 to 8 times
> +    if (linknum)
> +      {
> +        if (!config_fetch(d, off, 8 * linknum))
> +          {
> +            printf("\t\t<unreadable>\n");
> +            return;
> +          }
> +        for (i = 0; i < linknum; ++i)
> +          {
> +            // Link IDE Stream Control Register
> +            l = get_conf_long(d, off);
> +            off += 4;
> +            printf("\t\tLinkIDE#%d Ctl: En%c NPR%s PR%s CPL%s PCRC%c HdrEnc=%s Alg='%s' TC%d ID%d\n",
> +              i,
> +              FLAG(l, PCI_IDE_LINK_CTL_EN),
> +              aggr[PCI_IDE_LINK_CTL_TX_AGGR_NPR(l)],
> +              aggr[PCI_IDE_LINK_CTL_TX_AGGR_PR(l)],
> +              aggr[PCI_IDE_LINK_CTL_TX_AGGR_CPL(l)],
> +              FLAG(l, PCI_IDE_LINK_CTL_EN),
> +              TABLE(hdr_enc_mode, PCI_IDE_LINK_CTL_PART_ENC(l), buf1),
> +              TABLE(algo, PCI_IDE_LINK_CTL_ALG(l), buf2),
> +              PCI_IDE_LINK_CTL_TC(l),
> +              PCI_IDE_LINK_CTL_ID(l)
> +              );
> +
> +            /* Link IDE Stream Status Register */
> +            l = get_conf_long(d, off);
> +            off += 4;
> +            printf("\t\tLinkIDE#%d Sta: Status=%s RecvChkFail%c\n",
> +              i,
> +              TABLE(stream_state, PCI_IDE_LINK_STS_STATUS(l), buf1),
> +              FLAG(l, PCI_IDE_LINK_STS_RECVD_INTEGRITY_CHECK));
> +          }
> +      }
> +
> +    for (i = 0; i < linknum; ++i)
> +      {
> +        // Fetching Selective IDE Stream Capability/Control/Status/RID1/RID2
> +        if (!config_fetch(d, off, 20))
> +          {
> +            printf("\t\t<unreadable>\n");
> +            return;
> +          }
> +
> +        // Selective IDE Stream Capability Register
> +        l = get_conf_long(d, off);
> +        off += 4;
> +        addrnum = PCI_IDE_SEL_CAP_BLOCKS_NUM(l);
> +
> +        // Selective IDE Stream Control Register
> +        l = get_conf_long(d, off);
> +        off += 4;
> +
> +        printf("\t\tSelectiveIDE#%d Ctl: En%c NPR%s PR%s CPL%s PCRC%c HdrEnc=%s Alg='%s' TC%d ID%d%s\n",
> +          i,
> +          FLAG(l, PCI_IDE_SEL_CTL_EN),
> +          aggr[PCI_IDE_SEL_CTL_TX_AGGR_NPR(l)],
> +          aggr[PCI_IDE_SEL_CTL_TX_AGGR_PR(l)],
> +          aggr[PCI_IDE_SEL_CTL_TX_AGGR_CPL(l)],
> +          FLAG(l, PCI_IDE_SEL_CTL_PCRC_EN),
> +          TABLE(hdr_enc_mode, PCI_IDE_SEL_CTL_PART_ENC(l), buf1),
> +          TABLE(algo, PCI_IDE_SEL_CTL_ALG(l), buf2),
> +          PCI_IDE_SEL_CTL_TC(l),
> +          PCI_IDE_SEL_CTL_ID(l),
> +          (l & PCI_IDE_SEL_CTL_DEFAULT) ? " Default" : ""
> +          );
> +
> +        // Selective IDE Stream Status Register
> +        l = get_conf_long(d, off);
> +        off += 4;
> +
> +        printf("\t\tSelectiveIDE#%d Sta: %s RecvChkFail%c\n",
> +          i,
> +          TABLE(stream_state, PCI_IDE_SEL_STS_STATUS(l), buf1),
> +          FLAG(l, PCI_IDE_SEL_STS_RECVD_INTEGRITY_CHECK));
> +
> +        // IDE RID Association Registers
> +        l = get_conf_long(d, off);
> +        off += 4;
> +        l2 = get_conf_long(d, off);
> +        off += 4;
> +
> +        printf("\t\tSelectiveIDE#%d RID: Valid%c Base=%x Limit=%x SegBase=%x\n",
> +          i,
> +          FLAG(l2, PCI_IDE_SEL_RID_2_VALID),
> +          PCI_IDE_SEL_RID_2_BASE(l2),
> +          PCI_IDE_SEL_RID_1_LIMIT(l),
> +          PCI_IDE_SEL_RID_2_SEG_BASE(l2));
> +
> +        if (!config_fetch(d, off, addrnum * 12))
> +          {
> +            printf("\t\t<unreadable>\n");
> +            return;
> +          }
> +
> +        // IDE Address Association Registers
> +        for (j = 0; j < addrnum; ++j)
> +          {
> +            u64 limit, base;
> +
> +            l = get_conf_long(d, off);
> +            off += 4;
> +            limit = get_conf_long(d, off);
> +            off += 4;
> +            base = get_conf_long(d, off);
> +            off += 4;
> +            printf("\t\tSelectiveIDE#%d RID: Valid%c Base=%lx Limit=%lx\n",
> +              i,
> +              FLAG(l, PCI_IDE_SEL_ADDR_1_VALID),
> +              (base << 32) | PCI_IDE_SEL_ADDR_1_BASE_LOW(l),
> +              (limit << 32) | PCI_IDE_SEL_ADDR_1_LIMIT_LOW(l));
> +          }
> +      }
> +}
> +
>   void
>   show_ext_caps(struct device *d, int type)
>   {
> @@ -1621,6 +1780,9 @@ show_ext_caps(struct device *d, int type)
>   	  case PCI_EXT_CAP_ID_DOE:
>   	    cap_doe(d, where);
>   	    break;
> +	  case PCI_EXT_CAP_ID_IDE:
> +	    cap_ide(d, where);
> +	    break;
>   	  default:
>   	    printf("Extended Capability ID %#02x\n", id);
>   	    break;
Bjorn Helgaas Jan. 12, 2024, 9:19 p.m. UTC | #2
On Sat, Dec 30, 2023 at 11:42:39PM +1100, Alexey Kardashevskiy wrote:
> IDE (Integrity & Data Encryption) Extended Capability defined in [1]
> implements control of the PCI link encryption.
> 
> The example output is:
> 
> Capabilities: [830 v1] IDE

Possibly expand "IDE"?  Many other Capabilities are spelled out:

  Capabilities: [c0] Express Downstream Port (Slot+), MSI 00
  Capabilities: [100] Device Serial Number 5f-2f-9d-40-30-f1-0c-00
  Capabilities: [200] Advanced Error Reporting
  Capabilities: [300] Virtual Channel
  Capabilities: [400] Power Budgeting <?>
  Capabilities: [500] Vendor Specific Information: ID=1234 Rev=1 Len=0d8 <?>
  Capabilities: [700] Secondary PCI Express
Martin Mareš Jan. 26, 2024, 10:15 a.m. UTC | #3
Hello!

> > Capabilities: [830 v1] IDE
> 
> Possibly expand "IDE"? [...]

Yes, please.

Also, could you please provide some test data (a dump of config space
which contains this capability)? See also the dumps in the "tests"
directory.

				Have a nice fortnight
diff mbox series

Patch

diff --git a/lib/header.h b/lib/header.h
index 47ee8a6..5df2f57 100644
--- a/lib/header.h
+++ b/lib/header.h
@@ -256,6 +256,7 @@ 
 #define PCI_EXT_CAP_ID_NPEM	0x29	/* Native PCIe Enclosure Management */
 #define PCI_EXT_CAP_ID_32GT	0x2a	/* Physical Layer 32.0 GT/s */
 #define PCI_EXT_CAP_ID_DOE	0x2e	/* Data Object Exchange */
+#define PCI_EXT_CAP_ID_IDE	0x30	/* IDE */
 
 /*** Definitions of capabilities ***/
 
@@ -1416,6 +1417,66 @@ 
 #define  PCI_DOE_STS_ERROR		0x4	/* DOE Error */
 #define  PCI_DOE_STS_OBJECT_READY	0x80000000 /* Data Object Ready */
 
+/* IDE Extended Capability */
+#define PCI_IDE_CAP		0x4
+#define  PCI_IDE_CAP_LINK_IDE_SUPP	0x1	/* Link IDE Stream Supported */
+#define  PCI_IDE_CAP_SELECTIVE_IDE_SUPP 0x2	/* Selective IDE Streams Supported */
+#define  PCI_IDE_CAP_FLOWTHROUGH_IDE_SUPP 0x4	/* Flow-Through IDE Stream Supported */
+#define  PCI_IDE_CAP_PARTIAL_HEADER_ENC_SUPP 0x8 /* Partial Header Encryption Supported */
+#define  PCI_IDE_CAP_AGGREGATION_SUPP	0x10	/* Aggregation Supported */
+#define  PCI_IDE_CAP_PCRC_SUPP		0x20	/* PCRC Supported */
+#define  PCI_IDE_CAP_IDE_KM_SUPP	0x40	/* IDE_KM Protocol Supported */
+#define  PCI_IDE_CAP_ALG(x)	(((x) >> 8) & 0x1f) /* Supported Algorithms */
+#define  PCI_IDE_CAP_ALG_AES_GCM_256	0	/* AES-GCM 256 key size, 96b MAC */
+#define  PCI_IDE_CAP_LINK_TC_NUM(x)		(((x) >> 13) & 0x7) /* Number of TCs Supported for Link IDE */
+#define  PCI_IDE_CAP_SELECTIVE_STREAMS_NUM(x)	(((x) >> 16) & 0xff) /* Number of Selective IDE Streams Supported */
+#define PCI_IDE_CTL		0x8
+#define  PCI_IDE_CTL_FLOWTHROUGH_IDE	0x4	/* Flow-Through IDE Stream Enabled */
+#define PCI_IDE_LINK_STREAM		0xC
+/* Link IDE Stream block, up to PCI_IDE_CAP_LINK_TC_NUM */
+/* Link IDE Stream Control Register */
+#define  PCI_IDE_LINK_CTL_EN		0x1	/* Link IDE Stream Enable */
+#define  PCI_IDE_LINK_CTL_TX_AGGR_NPR(x)(((x) >> 2) & 0x3) /* Tx Aggregation Mode NPR */
+#define  PCI_IDE_LINK_CTL_TX_AGGR_PR(x)	(((x) >> 4) & 0x3) /* Tx Aggregation Mode PR */
+#define  PCI_IDE_LINK_CTL_TX_AGGR_CPL(x)(((x) >> 6) & 0x3) /* Tx Aggregation Mode CPL */
+#define  PCI_IDE_LINK_CTL_PCRC_EN	0x100	/* PCRC Enable */
+#define  PCI_IDE_LINK_CTL_PART_ENC(x)	(((x) >> 10) & 0xf)  /* Partial Header Encryption Mode */
+#define  PCI_IDE_LINK_CTL_ALG(x)	(((x) >> 14) & 0x1f) /* Selected Algorithm */
+#define  PCI_IDE_LINK_CTL_TC(x)		(((x) >> 19) & 0x7)  /* Traffic Class */
+#define  PCI_IDE_LINK_CTL_ID(x)		(((x) >> 24) & 0xff) /* Stream ID */
+/* Link IDE Stream Status Register */
+#define  PCI_IDE_LINK_STS_STATUS(x)	((x) & 0xf) /* Link IDE Stream State */
+#define  PCI_IDE_LINK_STS_RECVD_INTEGRITY_CHECK	0x80000000 /* Received Integrity Check Fail Message */
+/* Selective IDE Stream block, up to PCI_IDE_CAP_SELECTIVE_STREAMS_NUM */
+/* Selective IDE Stream Capability Register */
+#define  PCI_IDE_SEL_CAP_BLOCKS_NUM(x)	((x) & 0xf) /* Number of Address Association Register Blocks */
+/* Selective IDE Stream Control Register */
+#define  PCI_IDE_SEL_CTL_EN		0x1	/* Selective IDE Stream Enable */
+#define  PCI_IDE_SEL_CTL_TX_AGGR_NPR(x)	(((x) >> 2) & 0x3) /* Tx Aggregation Mode NPR */
+#define  PCI_IDE_SEL_CTL_TX_AGGR_PR(x)	(((x) >> 4) & 0x3) /* Tx Aggregation Mode PR */
+#define  PCI_IDE_SEL_CTL_TX_AGGR_CPL(x)	(((x) >> 6) & 0x3) /* Tx Aggregation Mode CPL */
+#define  PCI_IDE_SEL_CTL_PCRC_EN	0x100	/* PCRC Enable */
+#define  PCI_IDE_SEL_CTL_PART_ENC(x)	(((x) >> 10) & 0xf)  /* Partial Header Encryption Mode */
+#define  PCI_IDE_SEL_CTL_ALG(x)		(((x) >> 14) & 0x1f) /* Selected Algorithm */
+#define  PCI_IDE_SEL_CTL_TC(x)		(((x) >> 19) & 0x7)  /* Traffic Class */
+#define  PCI_IDE_SEL_CTL_DEFAULT	0x400000 /* Default Stream */
+#define  PCI_IDE_SEL_CTL_ID(x)		(((x) >> 24) & 0xff) /* Stream ID */
+/* Selective IDE Stream Status Register */
+#define  PCI_IDE_SEL_STS_STATUS(x)	((x) & 0xf) /* Selective IDE Stream State */
+#define  PCI_IDE_SEL_STS_RECVD_INTEGRITY_CHECK	0x80000000 /* Received Integrity Check Fail Message */
+/* IDE RID Association Register 1 */
+#define  PCI_IDE_SEL_RID_1_LIMIT(x)	(((x) >> 8) & 0xffff) /* RID Limit */
+/* IDE RID Association Register 2 */
+#define  PCI_IDE_SEL_RID_2_VALID	0x1	/* Valid */
+#define  PCI_IDE_SEL_RID_2_BASE(x)	(((x) >> 8) & 0xffff) /* RID Base */
+#define  PCI_IDE_SEL_RID_2_SEG_BASE(x)	(((x) >> 24) & 0xff) /* Segmeng Base */
+/* Selective IDE Address Association Register Block, up to PCI_IDE_SEL_CAP_BLOCKS_NUM */
+#define  PCI_IDE_SEL_ADDR_1_VALID	0x1	/* Valid */
+#define  PCI_IDE_SEL_ADDR_1_BASE_LOW(x)	(((x) >> 8) & 0xfff) /* Memory Base Lower */
+#define  PCI_IDE_SEL_ADDR_1_LIMIT_LOW(x)(((x) >> 20) & 0xfff) /* Memory Limit Lower */
+/* IDE Address Association Register 2 is "Memory Limit Upper" */
+/* IDE Address Association Register 3 is "Memory Base Upper" */
+
 /*
  * 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 2d7d827..9f6c3f8 100644
--- a/ls-ecaps.c
+++ b/ls-ecaps.c
@@ -1468,6 +1468,165 @@  cap_doe(struct device *d, int where)
 	 FLAG(l, PCI_DOE_STS_OBJECT_READY));
 }
 
+static void
+cap_ide(struct device *d, int where)
+{
+    const char *hdr_enc_mode[] = { "no", "17:2", "25:2", "33:2", "41:2" };
+    const char *algo[] = { "AES-GCM 256 key size, 96b MAC" };
+    const char *stream_state[] = { "insecure", "secure" };
+    const char *aggr[] = { "-", "=2", "=4", "=8" };
+    u32 l, l2, linknum = 0, selnum = 0, addrnum, off, i, j;
+    char buf1[16], buf2[16];
+
+    printf("IDE\n");
+
+    if (verbose < 2)
+        return;
+
+    if (!config_fetch(d, where + PCI_IDE_CAP, 8))
+      {
+        printf("\t\t<unreadable>\n");
+        return;
+      }
+
+    l = get_conf_long(d, where + PCI_IDE_CAP);
+    if (l & PCI_IDE_CAP_LINK_IDE_SUPP)
+        linknum = PCI_IDE_CAP_LINK_TC_NUM(l) + 1;
+    if (l & PCI_IDE_CAP_SELECTIVE_IDE_SUPP)
+        selnum = PCI_IDE_CAP_SELECTIVE_STREAMS_NUM(l) + 1;
+
+    printf("\t\tIDECap: Lnk=%d Sel=%d FlowThru%c PartHdr%c Aggr%c PCPC%c IDE_KM%c\n",
+      linknum,
+      selnum,
+      FLAG(l, PCI_IDE_CAP_FLOWTHROUGH_IDE_SUPP),
+      FLAG(l, PCI_IDE_CAP_PARTIAL_HEADER_ENC_SUPP),
+      FLAG(l, PCI_IDE_CAP_AGGREGATION_SUPP),
+      FLAG(l, PCI_IDE_CAP_PCRC_SUPP),
+      FLAG(l, PCI_IDE_CAP_IDE_KM_SUPP));
+
+    l = get_conf_long(d, where + PCI_IDE_CTL);
+    printf("\t\tIDECtl: IntEn%c\n",
+      FLAG(l, PCI_IDE_CTL_FLOWTHROUGH_IDE));
+
+    // The rest of the capability is variable length arrays
+    off = where + PCI_IDE_CAP + PCI_IDE_LINK_STREAM;
+
+    // Link IDE Register Block repeated 0 to 8 times
+    if (linknum)
+      {
+        if (!config_fetch(d, off, 8 * linknum))
+          {
+            printf("\t\t<unreadable>\n");
+            return;
+          }
+        for (i = 0; i < linknum; ++i)
+          {
+            // Link IDE Stream Control Register
+            l = get_conf_long(d, off);
+            off += 4;
+            printf("\t\tLinkIDE#%d Ctl: En%c NPR%s PR%s CPL%s PCRC%c HdrEnc=%s Alg='%s' TC%d ID%d\n",
+              i,
+              FLAG(l, PCI_IDE_LINK_CTL_EN),
+              aggr[PCI_IDE_LINK_CTL_TX_AGGR_NPR(l)],
+              aggr[PCI_IDE_LINK_CTL_TX_AGGR_PR(l)],
+              aggr[PCI_IDE_LINK_CTL_TX_AGGR_CPL(l)],
+              FLAG(l, PCI_IDE_LINK_CTL_EN),
+              TABLE(hdr_enc_mode, PCI_IDE_LINK_CTL_PART_ENC(l), buf1),
+              TABLE(algo, PCI_IDE_LINK_CTL_ALG(l), buf2),
+              PCI_IDE_LINK_CTL_TC(l),
+              PCI_IDE_LINK_CTL_ID(l)
+              );
+
+            /* Link IDE Stream Status Register */
+            l = get_conf_long(d, off);
+            off += 4;
+            printf("\t\tLinkIDE#%d Sta: Status=%s RecvChkFail%c\n",
+              i,
+              TABLE(stream_state, PCI_IDE_LINK_STS_STATUS(l), buf1),
+              FLAG(l, PCI_IDE_LINK_STS_RECVD_INTEGRITY_CHECK));
+          }
+      }
+
+    for (i = 0; i < linknum; ++i)
+      {
+        // Fetching Selective IDE Stream Capability/Control/Status/RID1/RID2
+        if (!config_fetch(d, off, 20))
+          {
+            printf("\t\t<unreadable>\n");
+            return;
+          }
+
+        // Selective IDE Stream Capability Register
+        l = get_conf_long(d, off);
+        off += 4;
+        addrnum = PCI_IDE_SEL_CAP_BLOCKS_NUM(l);
+
+        // Selective IDE Stream Control Register
+        l = get_conf_long(d, off);
+        off += 4;
+
+        printf("\t\tSelectiveIDE#%d Ctl: En%c NPR%s PR%s CPL%s PCRC%c HdrEnc=%s Alg='%s' TC%d ID%d%s\n",
+          i,
+          FLAG(l, PCI_IDE_SEL_CTL_EN),
+          aggr[PCI_IDE_SEL_CTL_TX_AGGR_NPR(l)],
+          aggr[PCI_IDE_SEL_CTL_TX_AGGR_PR(l)],
+          aggr[PCI_IDE_SEL_CTL_TX_AGGR_CPL(l)],
+          FLAG(l, PCI_IDE_SEL_CTL_PCRC_EN),
+          TABLE(hdr_enc_mode, PCI_IDE_SEL_CTL_PART_ENC(l), buf1),
+          TABLE(algo, PCI_IDE_SEL_CTL_ALG(l), buf2),
+          PCI_IDE_SEL_CTL_TC(l),
+          PCI_IDE_SEL_CTL_ID(l),
+          (l & PCI_IDE_SEL_CTL_DEFAULT) ? " Default" : ""
+          );
+
+        // Selective IDE Stream Status Register
+        l = get_conf_long(d, off);
+        off += 4;
+
+        printf("\t\tSelectiveIDE#%d Sta: %s RecvChkFail%c\n",
+          i,
+          TABLE(stream_state, PCI_IDE_SEL_STS_STATUS(l), buf1),
+          FLAG(l, PCI_IDE_SEL_STS_RECVD_INTEGRITY_CHECK));
+
+        // IDE RID Association Registers
+        l = get_conf_long(d, off);
+        off += 4;
+        l2 = get_conf_long(d, off);
+        off += 4;
+
+        printf("\t\tSelectiveIDE#%d RID: Valid%c Base=%x Limit=%x SegBase=%x\n",
+          i,
+          FLAG(l2, PCI_IDE_SEL_RID_2_VALID),
+          PCI_IDE_SEL_RID_2_BASE(l2),
+          PCI_IDE_SEL_RID_1_LIMIT(l),
+          PCI_IDE_SEL_RID_2_SEG_BASE(l2));
+
+        if (!config_fetch(d, off, addrnum * 12))
+          {
+            printf("\t\t<unreadable>\n");
+            return;
+          }
+
+        // IDE Address Association Registers
+        for (j = 0; j < addrnum; ++j)
+          {
+            u64 limit, base;
+
+            l = get_conf_long(d, off);
+            off += 4;
+            limit = get_conf_long(d, off);
+            off += 4;
+            base = get_conf_long(d, off);
+            off += 4;
+            printf("\t\tSelectiveIDE#%d RID: Valid%c Base=%lx Limit=%lx\n",
+              i,
+              FLAG(l, PCI_IDE_SEL_ADDR_1_VALID),
+              (base << 32) | PCI_IDE_SEL_ADDR_1_BASE_LOW(l),
+              (limit << 32) | PCI_IDE_SEL_ADDR_1_LIMIT_LOW(l));
+          }
+      }
+}
+
 void
 show_ext_caps(struct device *d, int type)
 {
@@ -1621,6 +1780,9 @@  show_ext_caps(struct device *d, int type)
 	  case PCI_EXT_CAP_ID_DOE:
 	    cap_doe(d, where);
 	    break;
+	  case PCI_EXT_CAP_ID_IDE:
+	    cap_ide(d, where);
+	    break;
 	  default:
 	    printf("Extended Capability ID %#02x\n", id);
 	    break;