Commit f16469ee authored by Dan Williams's avatar Dan Williams
Browse files

PCI/IDE: Enumerate Selective Stream IDE capabilities



Link encryption is a new PCIe feature enumerated by "PCIe r7.0 section
7.9.26 IDE Extended Capability".

It is both a standalone port + endpoint capability, and a building block
for the security protocol defined by "PCIe r7.0 section 11 TEE Device
Interface Security Protocol (TDISP)". That protocol coordinates device
security setup between a platform TSM (TEE Security Manager) and a
device DSM (Device Security Manager). While the platform TSM can
allocate resources like Stream ID and manage keys, it still requires
system software to manage the IDE capability register block.

Add register definitions and basic enumeration in preparation for
Selective IDE Stream establishment. A follow on change selects the new
CONFIG_PCI_IDE symbol. Note that while the IDE specification defines
both a point-to-point "Link Stream" and a Root Port to endpoint
"Selective Stream", only "Selective Stream" is considered for Linux as
that is the predominant mode expected by Trusted Execution Environment
Security Managers (TSMs), and it is the security model that limits the
number of PCI components within the TCB in a PCIe topology with
switches.

Co-developed-by: default avatarAlexey Kardashevskiy <aik@amd.com>
Signed-off-by: default avatarAlexey Kardashevskiy <aik@amd.com>
Co-developed-by: default avatarXu Yilun <yilun.xu@linux.intel.com>
Signed-off-by: default avatarXu Yilun <yilun.xu@linux.intel.com>
Reviewed-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: default avatarAlexey Kardashevskiy <aik@amd.com>
Reviewed-by: default avatarAneesh Kumar K.V <aneesh.kumar@kernel.org>
Link: https://patch.msgid.link/20251031212902.2256310-3-dan.j.williams@intel.com


Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 603c646f
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -122,6 +122,9 @@ config XEN_PCIDEV_FRONTEND
config PCI_ATS
	bool

config PCI_IDE
	bool

config PCI_DOE
	bool "Enable PCI Data Object Exchange (DOE) support"
	help
+1 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ obj-$(CONFIG_PCI_P2PDMA) += p2pdma.o
obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o
obj-$(CONFIG_VGA_ARB)		+= vgaarb.o
obj-$(CONFIG_PCI_DOE)		+= doe.o
obj-$(CONFIG_PCI_IDE)		+= ide.o
obj-$(CONFIG_PCI_DYNAMIC_OF_NODES) += of_property.o
obj-$(CONFIG_PCI_NPEM)		+= npem.o
obj-$(CONFIG_PCIE_TPH)		+= tph.o

drivers/pci/ide.c

0 → 100644
+88 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2024-2025 Intel Corporation. All rights reserved. */

/* PCIe r7.0 section 6.33 Integrity & Data Encryption (IDE) */

#define dev_fmt(fmt) "PCI/IDE: " fmt
#include <linux/bitfield.h>
#include <linux/pci.h>
#include <linux/pci_regs.h>

#include "pci.h"

static int __sel_ide_offset(u16 ide_cap, u8 nr_link_ide, u8 stream_index,
			    u8 nr_ide_mem)
{
	u32 offset = ide_cap + PCI_IDE_LINK_STREAM_0 +
		     nr_link_ide * PCI_IDE_LINK_BLOCK_SIZE;

	/*
	 * Assume a constant number of address association resources per stream
	 * index
	 */
	return offset + stream_index * PCI_IDE_SEL_BLOCK_SIZE(nr_ide_mem);
}

void pci_ide_init(struct pci_dev *pdev)
{
	u16 nr_link_ide, nr_ide_mem, nr_streams;
	u16 ide_cap;
	u32 val;

	if (!pci_is_pcie(pdev))
		return;

	ide_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_IDE);
	if (!ide_cap)
		return;

	pci_read_config_dword(pdev, ide_cap + PCI_IDE_CAP, &val);
	if ((val & PCI_IDE_CAP_SELECTIVE) == 0)
		return;

	/*
	 * Require endpoint IDE capability to be paired with IDE Root Port IDE
	 * capability.
	 */
	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) {
		struct pci_dev *rp = pcie_find_root_port(pdev);

		if (!rp->ide_cap)
			return;
	}

	pdev->ide_cfg = FIELD_GET(PCI_IDE_CAP_SEL_CFG, val);
	pdev->ide_tee_limit = FIELD_GET(PCI_IDE_CAP_TEE_LIMITED, val);

	if (val & PCI_IDE_CAP_LINK)
		nr_link_ide = 1 + FIELD_GET(PCI_IDE_CAP_LINK_TC_NUM, val);
	else
		nr_link_ide = 0;

	nr_ide_mem = 0;
	nr_streams = 1 + FIELD_GET(PCI_IDE_CAP_SEL_NUM, val);
	for (u16 i = 0; i < nr_streams; i++) {
		int pos = __sel_ide_offset(ide_cap, nr_link_ide, i, nr_ide_mem);
		int nr_assoc;
		u32 val;

		pci_read_config_dword(pdev, pos + PCI_IDE_SEL_CAP, &val);

		/*
		 * Let's not entertain streams that do not have a constant
		 * number of address association blocks
		 */
		nr_assoc = FIELD_GET(PCI_IDE_SEL_CAP_ASSOC_NUM, val);
		if (i && (nr_assoc != nr_ide_mem)) {
			pci_info(pdev, "Unsupported Selective Stream %d capability, SKIP the rest\n", i);
			nr_streams = i;
			break;
		}

		nr_ide_mem = nr_assoc;
	}

	pdev->ide_cap = ide_cap;
	pdev->nr_link_ide = nr_link_ide;
	pdev->nr_ide_mem = nr_ide_mem;
}
+6 −0
Original line number Diff line number Diff line
@@ -613,6 +613,12 @@ static inline void pci_doe_sysfs_init(struct pci_dev *pdev) { }
static inline void pci_doe_sysfs_teardown(struct pci_dev *pdev) { }
#endif

#ifdef CONFIG_PCI_IDE
void pci_ide_init(struct pci_dev *dev);
#else
static inline void pci_ide_init(struct pci_dev *dev) { }
#endif

/**
 * pci_dev_set_io_state - Set the new error state if possible.
 *
+1 −0
Original line number Diff line number Diff line
@@ -2667,6 +2667,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
	pci_doe_init(dev);		/* Data Object Exchange */
	pci_tph_init(dev);		/* TLP Processing Hints */
	pci_rebar_init(dev);		/* Resizable BAR */
	pci_ide_init(dev);		/* Link Integrity and Data Encryption */

	pcie_report_downtraining(dev);
	pci_init_reset_methods(dev);
Loading