From patchwork Tue Mar 4 07:14:20 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 14000060 X-Patchwork-Delegate: bhelgaas@google.com Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.16]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1CD241F9ED2 for ; Tue, 4 Mar 2025 07:14:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.16 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741072464; cv=none; b=lxd1CRbCxTKJHWpaKPZaP8M01s6IpvS/qrWVSDMyWE2rIsA8yKL8FyQDGAFbM6q1A3/y9hMhMa8B28+II7Iqsbez94fI4/zTztRncxHS7pMrjG3cq9XwmDPUJ9m3rlALbcr1NwMELVRupkSWfkGJeDg9CSL4u68B1tJybgSwpEs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741072464; c=relaxed/simple; bh=xme4W+0Xq3BhO50hKfUzW++vn/SJzw/PiKew18YEhvM=; h=Subject:From:To:Cc:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=TUg+hPrmZbWuicNwMP8zDID66bhiaxr07Gu+OmGYTiSzrw4rJ7n6Eb1RU9RqU4hM1hONcgapx0SLKmqJww/9MUJvzjlvFFL94xe0MJNhkd1x5L/44Cbu0nxH5PD3oDA2ROcoWcA4M7gLKJucZYyxBQ4CLQvOxU1cseXCco2dxN4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=NTLagzl5; arc=none smtp.client-ip=192.198.163.16 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="NTLagzl5" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1741072462; x=1772608462; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=xme4W+0Xq3BhO50hKfUzW++vn/SJzw/PiKew18YEhvM=; b=NTLagzl5XIH5hhpBk9AFefm7ncFmzSEZcawe1hvou9R1q/+JGP3GCybx e8EiTVpxjAG544it190uuMnNd+Lp+KUmPjqfoXbHLGaxzgKQpQwuxFwFW 1RC9mJiD0VH2Gp/syVsR+jSROD87ExD7wv0Jz+RrMxfwfTxt2QDreqY9d ySa9ZKQhyEWJaAevtMqRXOTuS8OAnjxgz/Azz+DuLaS54RcF16eTn8AEm +lc0ENLjSImsYo2J4Feqo5dIx4onxAuBnUkESh8vij78CUc2u5Z0ekbL+ kM/NuSKScIvpTumtwzS+ZtdD/egGG6eV39NY0k6SQ8ghq60jxJCBq4zeo Q==; X-CSE-ConnectionGUID: 3gCrxy+4TsOssz6SIbE6Cg== X-CSE-MsgGUID: KaBajHuiQcipp7qfqJ/1Aw== X-IronPort-AV: E=McAfee;i="6700,10204,11362"; a="29565094" X-IronPort-AV: E=Sophos;i="6.13,331,1732608000"; d="scan'208";a="29565094" Received: from fmviesa005.fm.intel.com ([10.60.135.145]) by fmvoesa110.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Mar 2025 23:14:21 -0800 X-CSE-ConnectionGUID: bqrNz+ywQhiVzGpbiBB+fg== X-CSE-MsgGUID: JMYvvgnoQNmEuY8cwfGUZg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.13,331,1732608000"; d="scan'208";a="122905490" Received: from inaky-mobl1.amr.corp.intel.com (HELO dwillia2-xfh.jf.intel.com) ([10.125.109.47]) by fmviesa005-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Mar 2025 23:14:21 -0800 Subject: [PATCH v2 01/11] configfs-tsm: Namespace TSM report symbols From: Dan Williams To: linux-coco@lists.linux.dev Cc: Yilun Xu , Samuel Ortiz , Tom Lendacky , Sami Mujawar , Steven Price , Alexey Kardashevskiy , Suzuki K Poulose , gregkh@linuxfoundation.org, linux-pci@vger.kernel.org, aik@amd.com, lukas@wunner.de Date: Mon, 03 Mar 2025 23:14:20 -0800 Message-ID: <174107246021.1288555.7203769833791489618.stgit@dwillia2-xfh.jf.intel.com> In-Reply-To: <174107245357.1288555.10863541957822891561.stgit@dwillia2-xfh.jf.intel.com> References: <174107245357.1288555.10863541957822891561.stgit@dwillia2-xfh.jf.intel.com> User-Agent: StGit/0.18-3-g996c Precedence: bulk X-Mailing-List: linux-pci@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 In preparation for new + common TSM (TEE Security Manager) infrastructure, namespace the TSM report symbols in tsm.h with an _REPORT suffix to differentiate them from other incoming tsm work. Cc: Yilun Xu Cc: Samuel Ortiz Cc: Tom Lendacky Cc: Sami Mujawar Cc: Steven Price Reviewed-by: Alexey Kardashevskiy Reviewed-by: Suzuki K Poulose Signed-off-by: Dan Williams Reviewed-by: Steven Price Reviewed-by: Kuppuswamy Sathyanarayanan Reviewed-by: Kai Huang --- Documentation/ABI/testing/configfs-tsm-report | 0 MAINTAINERS | 2 + drivers/virt/coco/arm-cca-guest/arm-cca-guest.c | 8 +++--- drivers/virt/coco/sev-guest/sev-guest.c | 12 ++++----- drivers/virt/coco/tdx-guest/tdx-guest.c | 8 +++--- drivers/virt/coco/tsm.c | 32 ++++++++++++----------- include/linux/tsm.h | 22 ++++++++-------- 7 files changed, 42 insertions(+), 42 deletions(-) rename Documentation/ABI/testing/{configfs-tsm => configfs-tsm-report} (100%) diff --git a/Documentation/ABI/testing/configfs-tsm b/Documentation/ABI/testing/configfs-tsm-report similarity index 100% rename from Documentation/ABI/testing/configfs-tsm rename to Documentation/ABI/testing/configfs-tsm-report diff --git a/MAINTAINERS b/MAINTAINERS index 8e0736dc2ee0..38bcf530c2ae 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -24115,7 +24115,7 @@ TRUSTED SECURITY MODULE (TSM) ATTESTATION REPORTS M: Dan Williams L: linux-coco@lists.linux.dev S: Maintained -F: Documentation/ABI/testing/configfs-tsm +F: Documentation/ABI/testing/configfs-tsm-report F: drivers/virt/coco/tsm.c F: include/linux/tsm.h diff --git a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c b/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c index 87f162736b2e..0c9ea24a200c 100644 --- a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c +++ b/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c @@ -96,7 +96,7 @@ static int arm_cca_report_new(struct tsm_report *report, void *data) struct arm_cca_token_info info; void *buf; u8 *token __free(kvfree) = NULL; - struct tsm_desc *desc = &report->desc; + struct tsm_report_desc *desc = &report->desc; if (desc->inblob_len < 32 || desc->inblob_len > 64) return -EINVAL; @@ -181,7 +181,7 @@ static int arm_cca_report_new(struct tsm_report *report, void *data) return ret; } -static const struct tsm_ops arm_cca_tsm_ops = { +static const struct tsm_report_ops arm_cca_tsm_ops = { .name = KBUILD_MODNAME, .report_new = arm_cca_report_new, }; @@ -202,7 +202,7 @@ static int __init arm_cca_guest_init(void) if (!is_realm_world()) return -ENODEV; - ret = tsm_register(&arm_cca_tsm_ops, NULL); + ret = tsm_report_register(&arm_cca_tsm_ops, NULL); if (ret < 0) pr_err("Error %d registering with TSM\n", ret); @@ -216,7 +216,7 @@ module_init(arm_cca_guest_init); */ static void __exit arm_cca_guest_exit(void) { - tsm_unregister(&arm_cca_tsm_ops); + tsm_report_unregister(&arm_cca_tsm_ops); } module_exit(arm_cca_guest_exit); diff --git a/drivers/virt/coco/sev-guest/sev-guest.c b/drivers/virt/coco/sev-guest/sev-guest.c index 264b6523fe52..964ac8ed8fde 100644 --- a/drivers/virt/coco/sev-guest/sev-guest.c +++ b/drivers/virt/coco/sev-guest/sev-guest.c @@ -317,7 +317,7 @@ struct snp_msg_cert_entry { static int sev_svsm_report_new(struct tsm_report *report, void *data) { unsigned int rep_len, man_len, certs_len; - struct tsm_desc *desc = &report->desc; + struct tsm_report_desc *desc = &report->desc; struct svsm_attest_call ac = {}; unsigned int retry_count; void *rep, *man, *certs; @@ -452,7 +452,7 @@ static int sev_svsm_report_new(struct tsm_report *report, void *data) static int sev_report_new(struct tsm_report *report, void *data) { struct snp_msg_cert_entry *cert_table; - struct tsm_desc *desc = &report->desc; + struct tsm_report_desc *desc = &report->desc; struct snp_guest_dev *snp_dev = data; struct snp_msg_report_resp_hdr hdr; const u32 report_size = SZ_4K; @@ -581,7 +581,7 @@ static bool sev_report_bin_attr_visible(int n) return false; } -static struct tsm_ops sev_tsm_ops = { +static struct tsm_report_ops sev_tsm_report_ops = { .name = KBUILD_MODNAME, .report_new = sev_report_new, .report_attr_visible = sev_report_attr_visible, @@ -590,7 +590,7 @@ static struct tsm_ops sev_tsm_ops = { static void unregister_sev_tsm(void *data) { - tsm_unregister(&sev_tsm_ops); + tsm_report_unregister(&sev_tsm_report_ops); } static int __init sev_guest_probe(struct platform_device *pdev) @@ -627,9 +627,9 @@ static int __init sev_guest_probe(struct platform_device *pdev) misc->fops = &snp_guest_fops; /* Set the privlevel_floor attribute based on the vmpck_id */ - sev_tsm_ops.privlevel_floor = mdesc->vmpck_id; + sev_tsm_report_ops.privlevel_floor = mdesc->vmpck_id; - ret = tsm_register(&sev_tsm_ops, snp_dev); + ret = tsm_report_register(&sev_tsm_report_ops, snp_dev); if (ret) goto e_msg_init; diff --git a/drivers/virt/coco/tdx-guest/tdx-guest.c b/drivers/virt/coco/tdx-guest/tdx-guest.c index 224e7dde9cde..bd043838ab2e 100644 --- a/drivers/virt/coco/tdx-guest/tdx-guest.c +++ b/drivers/virt/coco/tdx-guest/tdx-guest.c @@ -161,7 +161,7 @@ static int tdx_report_new(struct tsm_report *report, void *data) { u8 *buf, *reportdata = NULL, *tdreport = NULL; struct tdx_quote_buf *quote_buf = quote_data; - struct tsm_desc *desc = &report->desc; + struct tsm_report_desc *desc = &report->desc; int ret; u64 err; @@ -297,7 +297,7 @@ static const struct x86_cpu_id tdx_guest_ids[] = { }; MODULE_DEVICE_TABLE(x86cpu, tdx_guest_ids); -static const struct tsm_ops tdx_tsm_ops = { +static const struct tsm_report_ops tdx_tsm_ops = { .name = KBUILD_MODNAME, .report_new = tdx_report_new, .report_attr_visible = tdx_report_attr_visible, @@ -322,7 +322,7 @@ static int __init tdx_guest_init(void) goto free_misc; } - ret = tsm_register(&tdx_tsm_ops, NULL); + ret = tsm_report_register(&tdx_tsm_ops, NULL); if (ret) goto free_quote; @@ -339,7 +339,7 @@ module_init(tdx_guest_init); static void __exit tdx_guest_exit(void) { - tsm_unregister(&tdx_tsm_ops); + tsm_report_unregister(&tdx_tsm_ops); free_quote_buf(quote_data); misc_deregister(&tdx_misc_dev); } diff --git a/drivers/virt/coco/tsm.c b/drivers/virt/coco/tsm.c index 9432d4e303f1..bcb515b50c68 100644 --- a/drivers/virt/coco/tsm.c +++ b/drivers/virt/coco/tsm.c @@ -13,7 +13,7 @@ #include static struct tsm_provider { - const struct tsm_ops *ops; + const struct tsm_report_ops *ops; void *data; } provider; static DECLARE_RWSEM(tsm_rwsem); @@ -98,7 +98,7 @@ static ssize_t tsm_report_privlevel_store(struct config_item *cfg, * SEV-SNP GHCB) and a minimum of a TSM selected floor value no less * than 0. */ - if (provider.ops->privlevel_floor > val || val > TSM_PRIVLEVEL_MAX) + if (provider.ops->privlevel_floor > val || val > TSM_REPORT_PRIVLEVEL_MAX) return -EINVAL; guard(rwsem_write)(&tsm_rwsem); @@ -202,7 +202,7 @@ static ssize_t tsm_report_inblob_write(struct config_item *cfg, memcpy(report->desc.inblob, buf, count); return count; } -CONFIGFS_BIN_ATTR_WO(tsm_report_, inblob, NULL, TSM_INBLOB_MAX); +CONFIGFS_BIN_ATTR_WO(tsm_report_, inblob, NULL, TSM_REPORT_INBLOB_MAX); static ssize_t tsm_report_generation_show(struct config_item *cfg, char *buf) { @@ -272,7 +272,7 @@ static ssize_t tsm_report_read(struct tsm_report *report, void *buf, size_t count, enum tsm_data_select select) { struct tsm_report_state *state = to_state(report); - const struct tsm_ops *ops; + const struct tsm_report_ops *ops; ssize_t rc; /* try to read from the existing report if present and valid... */ @@ -314,7 +314,7 @@ static ssize_t tsm_report_outblob_read(struct config_item *cfg, void *buf, return tsm_report_read(report, buf, count, TSM_REPORT); } -CONFIGFS_BIN_ATTR_RO(tsm_report_, outblob, NULL, TSM_OUTBLOB_MAX); +CONFIGFS_BIN_ATTR_RO(tsm_report_, outblob, NULL, TSM_REPORT_OUTBLOB_MAX); static ssize_t tsm_report_auxblob_read(struct config_item *cfg, void *buf, size_t count) @@ -323,7 +323,7 @@ static ssize_t tsm_report_auxblob_read(struct config_item *cfg, void *buf, return tsm_report_read(report, buf, count, TSM_CERTS); } -CONFIGFS_BIN_ATTR_RO(tsm_report_, auxblob, NULL, TSM_OUTBLOB_MAX); +CONFIGFS_BIN_ATTR_RO(tsm_report_, auxblob, NULL, TSM_REPORT_OUTBLOB_MAX); static ssize_t tsm_report_manifestblob_read(struct config_item *cfg, void *buf, size_t count) @@ -332,7 +332,7 @@ static ssize_t tsm_report_manifestblob_read(struct config_item *cfg, void *buf, return tsm_report_read(report, buf, count, TSM_MANIFEST); } -CONFIGFS_BIN_ATTR_RO(tsm_report_, manifestblob, NULL, TSM_OUTBLOB_MAX); +CONFIGFS_BIN_ATTR_RO(tsm_report_, manifestblob, NULL, TSM_REPORT_OUTBLOB_MAX); static struct configfs_attribute *tsm_report_attrs[] = { [TSM_REPORT_GENERATION] = &tsm_report_attr_generation, @@ -448,9 +448,9 @@ static struct configfs_subsystem tsm_configfs = { .su_mutex = __MUTEX_INITIALIZER(tsm_configfs.su_mutex), }; -int tsm_register(const struct tsm_ops *ops, void *priv) +int tsm_report_register(const struct tsm_report_ops *ops, void *priv) { - const struct tsm_ops *conflict; + const struct tsm_report_ops *conflict; guard(rwsem_write)(&tsm_rwsem); conflict = provider.ops; @@ -463,9 +463,9 @@ int tsm_register(const struct tsm_ops *ops, void *priv) provider.data = priv; return 0; } -EXPORT_SYMBOL_GPL(tsm_register); +EXPORT_SYMBOL_GPL(tsm_report_register); -int tsm_unregister(const struct tsm_ops *ops) +int tsm_report_unregister(const struct tsm_report_ops *ops) { guard(rwsem_write)(&tsm_rwsem); if (ops != provider.ops) @@ -474,11 +474,11 @@ int tsm_unregister(const struct tsm_ops *ops) provider.data = NULL; return 0; } -EXPORT_SYMBOL_GPL(tsm_unregister); +EXPORT_SYMBOL_GPL(tsm_report_unregister); static struct config_group *tsm_report_group; -static int __init tsm_init(void) +static int __init tsm_report_init(void) { struct config_group *root = &tsm_configfs.su_group; struct config_group *tsm; @@ -499,14 +499,14 @@ static int __init tsm_init(void) return 0; } -module_init(tsm_init); +module_init(tsm_report_init); -static void __exit tsm_exit(void) +static void __exit tsm_report_exit(void) { configfs_unregister_default_group(tsm_report_group); configfs_unregister_subsystem(&tsm_configfs); } -module_exit(tsm_exit); +module_exit(tsm_report_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Provide Trusted Security Module attestation reports via configfs"); diff --git a/include/linux/tsm.h b/include/linux/tsm.h index 11b0c525be30..431054810dca 100644 --- a/include/linux/tsm.h +++ b/include/linux/tsm.h @@ -6,17 +6,17 @@ #include #include -#define TSM_INBLOB_MAX 64 -#define TSM_OUTBLOB_MAX SZ_32K +#define TSM_REPORT_INBLOB_MAX 64 +#define TSM_REPORT_OUTBLOB_MAX SZ_32K /* * Privilege level is a nested permission concept to allow confidential * guests to partition address space, 4-levels are supported. */ -#define TSM_PRIVLEVEL_MAX 3 +#define TSM_REPORT_PRIVLEVEL_MAX 3 /** - * struct tsm_desc - option descriptor for generating tsm report blobs + * struct tsm_report_desc - option descriptor for generating tsm report blobs * @privlevel: optional privilege level to associate with @outblob * @inblob_len: sizeof @inblob * @inblob: arbitrary input data @@ -24,10 +24,10 @@ * @service_guid: optional service-provider service guid to attest * @service_manifest_version: optional service-provider service manifest version requested */ -struct tsm_desc { +struct tsm_report_desc { unsigned int privlevel; size_t inblob_len; - u8 inblob[TSM_INBLOB_MAX]; + u8 inblob[TSM_REPORT_INBLOB_MAX]; char *service_provider; guid_t service_guid; unsigned int service_manifest_version; @@ -44,7 +44,7 @@ struct tsm_desc { * @manifestblob: (optional) manifest data associated with the report */ struct tsm_report { - struct tsm_desc desc; + struct tsm_report_desc desc; size_t outblob_len; u8 *outblob; size_t auxblob_len; @@ -88,7 +88,7 @@ enum tsm_bin_attr_index { }; /** - * struct tsm_ops - attributes and operations for tsm instances + * struct tsm_report_ops - attributes and operations for tsm_report instances * @name: tsm id reflected in /sys/kernel/config/tsm/report/$report/provider * @privlevel_floor: convey base privlevel for nested scenarios * @report_new: Populate @report with the report blob and auxblob @@ -99,7 +99,7 @@ enum tsm_bin_attr_index { * Implementation specific ops, only one is expected to be registered at * a time i.e. only one of "sev-guest", "tdx-guest", etc. */ -struct tsm_ops { +struct tsm_report_ops { const char *name; unsigned int privlevel_floor; int (*report_new)(struct tsm_report *report, void *data); @@ -107,6 +107,6 @@ struct tsm_ops { bool (*report_bin_attr_visible)(int n); }; -int tsm_register(const struct tsm_ops *ops, void *priv); -int tsm_unregister(const struct tsm_ops *ops); +int tsm_report_register(const struct tsm_report_ops *ops, void *priv); +int tsm_report_unregister(const struct tsm_report_ops *ops); #endif /* __TSM_H */ From patchwork Tue Mar 4 07:14:26 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 14000061 X-Patchwork-Delegate: bhelgaas@google.com Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.16]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D238E1F666B for ; Tue, 4 Mar 2025 07:14:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.16 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741072469; cv=none; b=AtyxCadp+CtTzjt9Jplog+rXfSJyY5BYIf3uG+DUvVYuDYMgwBLsTrunQX+O9PfwccU98WAqakFAO0JJUgGZ+cs6NE+7/IsR92ZZbiYz3+svlwt3oNGXiS8pNYPxo5N7e9LdISqARUQjt9fw3ZBaERDLFkr8gXqLkwWvOQO/JXs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741072469; c=relaxed/simple; bh=cxrLZ2/18pEvKe1uAi2YT+TyrD5ziAEkEVKwG75MW/8=; h=Subject:From:To:Cc:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ILoadMwvl0yvfiunVuQT39yrv27NMkRZiHErUSI5m6bbgqHNYr7gRcEV1EVxyYyHHKA4MlFWkrIW6ZdfNt4x/k13TA4UWy5omyDGBz+zilbOyTS+l7LORegCMRisgsuQ7jgGOGBzueLzF1wOSUDKiWak4fLcN8ScztPCqtEnznc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=aJk2Xd8O; arc=none smtp.client-ip=192.198.163.16 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="aJk2Xd8O" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1741072468; x=1772608468; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=cxrLZ2/18pEvKe1uAi2YT+TyrD5ziAEkEVKwG75MW/8=; b=aJk2Xd8O3n7tOEsBHuBihf+EZ4jPd/oOVo/KiZryTfe114infW5r5SHb YQ9K9Ngp0HiJOGPUgZbaMkY6FN7rEe29ZOy9FeFHRPkUrPhWppeq1S0wj kWVXv2AlPN+ksmDMgtbDBecmvwA/LVUMKpjCCCuQWlMu3QQhcfNYSfQMu Lrh/VakaIdCtJIB18mfwVjkRxITYzXakZyFGxyZnKCicXLSk7lqoFW7T/ Mmfrizjh8rZOTyCZ9wowIZSfaNHDG0Mg+rwdrusjZ6yTSTV3riuT/Dw1v ZP+PJzZYQYvjzAUcipqyAkTDXa4wsBAxn8n9L2xSws1mvQVeKPBb6hKFt Q==; X-CSE-ConnectionGUID: ZuKs03mjQxOuuDvg1rTFrw== X-CSE-MsgGUID: hKX73qiwRaWwNZDRAxc0Lg== X-IronPort-AV: E=McAfee;i="6700,10204,11362"; a="29565102" X-IronPort-AV: E=Sophos;i="6.13,331,1732608000"; d="scan'208";a="29565102" Received: from fmviesa005.fm.intel.com ([10.60.135.145]) by fmvoesa110.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Mar 2025 23:14:28 -0800 X-CSE-ConnectionGUID: nq2w/vTAQC6JQEh18ET36Q== X-CSE-MsgGUID: XVwYco9IQ8u0+XaKQgAg3w== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.13,331,1732608000"; d="scan'208";a="122905505" Received: from inaky-mobl1.amr.corp.intel.com (HELO dwillia2-xfh.jf.intel.com) ([10.125.109.47]) by fmviesa005-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Mar 2025 23:14:27 -0800 Subject: [PATCH v2 02/11] coco/guest: Move shared guest CC infrastructure to drivers/virt/coco/guest/ From: Dan Williams To: linux-coco@lists.linux.dev Cc: Wu Hao , Yilun Xu , Samuel Ortiz , Tom Lendacky , Alexey Kardashevskiy , gregkh@linuxfoundation.org, linux-pci@vger.kernel.org, aik@amd.com, lukas@wunner.de Date: Mon, 03 Mar 2025 23:14:26 -0800 Message-ID: <174107246641.1288555.208426916259466774.stgit@dwillia2-xfh.jf.intel.com> In-Reply-To: <174107245357.1288555.10863541957822891561.stgit@dwillia2-xfh.jf.intel.com> References: <174107245357.1288555.10863541957822891561.stgit@dwillia2-xfh.jf.intel.com> User-Agent: StGit/0.18-3-g996c Precedence: bulk X-Mailing-List: linux-pci@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 In preparation for creating a new drivers/virt/coco/host/ directory to house shared host driver infrastructure for confidential computing, move configfs-tsm to a guest/ sub-directory. The tsm.ko module is renamed to tsm_reports.ko. The old tsm.ko module was only ever demand loaded by kernel internal dependencies, so it should not affect existing userspace module install scripts. The new drivers/virt/coco/guest/ is also a preparatory landing spot for new / optional TSM Report mechanics like a TCB stability enumeration / watchdog mechanism. To be added later. Cc: Wu Hao Cc: Yilun Xu Cc: Samuel Ortiz Cc: Tom Lendacky Reviewed-by: Alexey Kardashevskiy Signed-off-by: Dan Williams Reviewed-by: Kuppuswamy Sathyanarayanan --- MAINTAINERS | 2 +- drivers/virt/coco/Kconfig | 6 ++---- drivers/virt/coco/Makefile | 2 +- drivers/virt/coco/guest/Kconfig | 7 +++++++ drivers/virt/coco/guest/Makefile | 3 +++ drivers/virt/coco/guest/report.c | 0 6 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 drivers/virt/coco/guest/Kconfig create mode 100644 drivers/virt/coco/guest/Makefile rename drivers/virt/coco/{tsm.c => guest/report.c} (100%) diff --git a/MAINTAINERS b/MAINTAINERS index 38bcf530c2ae..6a1d705c8eac 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -24116,7 +24116,7 @@ M: Dan Williams L: linux-coco@lists.linux.dev S: Maintained F: Documentation/ABI/testing/configfs-tsm-report -F: drivers/virt/coco/tsm.c +F: drivers/virt/coco/guest/ F: include/linux/tsm.h TRUSTED SERVICES TEE DRIVER diff --git a/drivers/virt/coco/Kconfig b/drivers/virt/coco/Kconfig index ff869d883d95..819a97e8ba99 100644 --- a/drivers/virt/coco/Kconfig +++ b/drivers/virt/coco/Kconfig @@ -3,10 +3,6 @@ # Confidential computing related collateral # -config TSM_REPORTS - select CONFIGFS_FS - tristate - source "drivers/virt/coco/efi_secret/Kconfig" source "drivers/virt/coco/pkvm-guest/Kconfig" @@ -16,3 +12,5 @@ source "drivers/virt/coco/sev-guest/Kconfig" source "drivers/virt/coco/tdx-guest/Kconfig" source "drivers/virt/coco/arm-cca-guest/Kconfig" + +source "drivers/virt/coco/guest/Kconfig" diff --git a/drivers/virt/coco/Makefile b/drivers/virt/coco/Makefile index c3d07cfc087e..885c9ef4e9fc 100644 --- a/drivers/virt/coco/Makefile +++ b/drivers/virt/coco/Makefile @@ -2,9 +2,9 @@ # # Confidential computing related collateral # -obj-$(CONFIG_TSM_REPORTS) += tsm.o obj-$(CONFIG_EFI_SECRET) += efi_secret/ obj-$(CONFIG_ARM_PKVM_GUEST) += pkvm-guest/ obj-$(CONFIG_SEV_GUEST) += sev-guest/ obj-$(CONFIG_INTEL_TDX_GUEST) += tdx-guest/ obj-$(CONFIG_ARM_CCA_GUEST) += arm-cca-guest/ +obj-$(CONFIG_TSM_REPORTS) += guest/ diff --git a/drivers/virt/coco/guest/Kconfig b/drivers/virt/coco/guest/Kconfig new file mode 100644 index 000000000000..ed9bafbdd854 --- /dev/null +++ b/drivers/virt/coco/guest/Kconfig @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Confidential computing shared guest collateral +# +config TSM_REPORTS + select CONFIGFS_FS + tristate diff --git a/drivers/virt/coco/guest/Makefile b/drivers/virt/coco/guest/Makefile new file mode 100644 index 000000000000..b3b217af77cf --- /dev/null +++ b/drivers/virt/coco/guest/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_TSM_REPORTS) += tsm_report.o +tsm_report-y := report.o diff --git a/drivers/virt/coco/tsm.c b/drivers/virt/coco/guest/report.c similarity index 100% rename from drivers/virt/coco/tsm.c rename to drivers/virt/coco/guest/report.c From patchwork Tue Mar 4 07:14:32 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 14000062 X-Patchwork-Delegate: bhelgaas@google.com Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.16]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ED1591F76A8 for ; Tue, 4 Mar 2025 07:14:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.16 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741072475; cv=none; b=PpkNUXKLGTrjHYaOvi9/pFnYBtoXBgB1arO2hiRwwvCV4+T0KZTpWYF59jIkWh6O6YF0f56VVDqyhAZGQNKElAX9jmLRsH1YOmD/VjMabTgUq4PEEZ+Gi/9DrzYh0wGpKIjQ0W65ZshF8tgYhUc38m6DuL3X36r6nGhcKhN1K0k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741072475; c=relaxed/simple; bh=kfDkVb1jbfAeiIRJdWG1zXlrVJ11SCIAwyK+NzJ7M2k=; h=Subject:From:To:Cc:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=YSR8FQCdCuK0UfCjsRHj2Ci6lLxdmZRsqalka+kvAUA1HmQ90IKpz8bP0NiV10vUDFMi3gPhBONHVdTCqigmG+mvHIXqsLAcNk38k+OmGuS3Bd/v0v05Hx9WALyP0ffbIZOmj715ssmn2rVrbD/4bp8iKV/57u23N8u2oHA8FKE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=YAJ8hXvd; arc=none smtp.client-ip=192.198.163.16 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="YAJ8hXvd" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1741072474; x=1772608474; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=kfDkVb1jbfAeiIRJdWG1zXlrVJ11SCIAwyK+NzJ7M2k=; b=YAJ8hXvdogHgYqai0OHzUtDwDetPSUUDktWSZIQWe2PJv2t9P5xFo+vi AyoWW7O0XE9zfGkVMGcw1f9xXoJyPRxKTepnebuAfychkCORmjwHn5bdq 3h3oyfWPZYFelHoBv1RJsDdH6J/HSPhK/bs1OXJTJBsr37mEKVC1YgQ9J 424+oZidUR97sOhUF65VMfLQElr2BjwYqnXuPNh559dQHDIdKUXfV4WHv CnGSFVmoRAvt9XXh0LLXUhEiRgnih8cYfppXI8NquoHavGbcWpFXQA4uW S5/VFQ01EaGmT/ozjQs39Xlpd3xu9XBu8YDUAXWq3aUDuOj5hHFPHK3SJ g==; X-CSE-ConnectionGUID: hGSj2lJvR0CnJN6ORxNopQ== X-CSE-MsgGUID: t/04W5z9Q8+sSSYp+Boz1Q== X-IronPort-AV: E=McAfee;i="6700,10204,11362"; a="29565111" X-IronPort-AV: E=Sophos;i="6.13,331,1732608000"; d="scan'208";a="29565111" Received: from fmviesa005.fm.intel.com ([10.60.135.145]) by fmvoesa110.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Mar 2025 23:14:34 -0800 X-CSE-ConnectionGUID: 3ADw4w+wTS6jOgwGVzNKbg== X-CSE-MsgGUID: gzLAlM0yTvmCP7EKd/KVCw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.13,331,1732608000"; d="scan'208";a="122905510" Received: from inaky-mobl1.amr.corp.intel.com (HELO dwillia2-xfh.jf.intel.com) ([10.125.109.47]) by fmviesa005-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Mar 2025 23:14:33 -0800 Subject: [PATCH v2 03/11] coco/tsm: Introduce a core device for TEE Security Managers From: Dan Williams To: linux-coco@lists.linux.dev Cc: Xiaoyao Li , Isaku Yamahata , Alexey Kardashevskiy , Yilun Xu , Tom Lendacky , John Allen , gregkh@linuxfoundation.org, linux-pci@vger.kernel.org, aik@amd.com, lukas@wunner.de Date: Mon, 03 Mar 2025 23:14:32 -0800 Message-ID: <174107247268.1288555.9365605713564715054.stgit@dwillia2-xfh.jf.intel.com> In-Reply-To: <174107245357.1288555.10863541957822891561.stgit@dwillia2-xfh.jf.intel.com> References: <174107245357.1288555.10863541957822891561.stgit@dwillia2-xfh.jf.intel.com> User-Agent: StGit/0.18-3-g996c Precedence: bulk X-Mailing-List: linux-pci@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 A "TSM" is a platform component that provides an API for securely provisioning resources for a confidential guest (TVM) to consume. The name originates from the PCI specification for platform agent that carries out operations for PCIe TDISP (TEE Device Interface Security Protocol). Instances of this core device are parented by a device representing the platform security function like CONFIG_CRYPTO_DEV_CCP or CONFIG_INTEL_TDX_HOST. This device interface is a frontend to the aspects of a TSM and TEE I/O that are cross-architecture common. This includes mechanisms like enumerating available platform TEE I/O capabilities and provisioning connections between the platform TSM and device DSMs (Device Security Manager (TDISP)). For now this is just the scaffolding for registering a TSM device sysfs interface. Cc: Xiaoyao Li Cc: Isaku Yamahata Cc: Alexey Kardashevskiy Cc: Yilun Xu Cc: Tom Lendacky Cc: John Allen Signed-off-by: Dan Williams --- Documentation/ABI/testing/sysfs-class-tsm | 10 +++ MAINTAINERS | 3 + drivers/virt/coco/Kconfig | 2 + drivers/virt/coco/Makefile | 1 drivers/virt/coco/host/Kconfig | 6 ++ drivers/virt/coco/host/Makefile | 6 ++ drivers/virt/coco/host/tsm-core.c | 112 +++++++++++++++++++++++++++++ include/linux/tsm.h | 5 + 8 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/testing/sysfs-class-tsm create mode 100644 drivers/virt/coco/host/Kconfig create mode 100644 drivers/virt/coco/host/Makefile create mode 100644 drivers/virt/coco/host/tsm-core.c diff --git a/Documentation/ABI/testing/sysfs-class-tsm b/Documentation/ABI/testing/sysfs-class-tsm new file mode 100644 index 000000000000..7503f04a9eb9 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-tsm @@ -0,0 +1,10 @@ +What: /sys/class/tsm/tsm0 +Date: Dec, 2024 +Contact: linux-coco@lists.linux.dev +Description: + "tsm0" is a singleton device that represents the generic + attributes of a platform TEE Security Manager. It is a child of + the platform TSM device. /sys/class/tsm/tsm0/uevent + signals when the PCI layer is able to support establishment of + link encryption and other device-security features coordinated + through the platform tsm. diff --git a/MAINTAINERS b/MAINTAINERS index 6a1d705c8eac..352f982f435e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -24111,12 +24111,13 @@ W: https://github.com/srcres258/linux-doc T: git git://github.com/srcres258/linux-doc.git doc-zh-tw F: Documentation/translations/zh_TW/ -TRUSTED SECURITY MODULE (TSM) ATTESTATION REPORTS +TRUSTED (TEE) SECURITY MANAGER (TSM) M: Dan Williams L: linux-coco@lists.linux.dev S: Maintained F: Documentation/ABI/testing/configfs-tsm-report F: drivers/virt/coco/guest/ +F: drivers/virt/coco/host/ F: include/linux/tsm.h TRUSTED SERVICES TEE DRIVER diff --git a/drivers/virt/coco/Kconfig b/drivers/virt/coco/Kconfig index 819a97e8ba99..14e7cf145d85 100644 --- a/drivers/virt/coco/Kconfig +++ b/drivers/virt/coco/Kconfig @@ -14,3 +14,5 @@ source "drivers/virt/coco/tdx-guest/Kconfig" source "drivers/virt/coco/arm-cca-guest/Kconfig" source "drivers/virt/coco/guest/Kconfig" + +source "drivers/virt/coco/host/Kconfig" diff --git a/drivers/virt/coco/Makefile b/drivers/virt/coco/Makefile index 885c9ef4e9fc..73f1b7bc5b11 100644 --- a/drivers/virt/coco/Makefile +++ b/drivers/virt/coco/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_SEV_GUEST) += sev-guest/ obj-$(CONFIG_INTEL_TDX_GUEST) += tdx-guest/ obj-$(CONFIG_ARM_CCA_GUEST) += arm-cca-guest/ obj-$(CONFIG_TSM_REPORTS) += guest/ +obj-y += host/ diff --git a/drivers/virt/coco/host/Kconfig b/drivers/virt/coco/host/Kconfig new file mode 100644 index 000000000000..4fbc6ef34f12 --- /dev/null +++ b/drivers/virt/coco/host/Kconfig @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# TSM (TEE Security Manager) Common infrastructure and host drivers +# +config TSM + tristate diff --git a/drivers/virt/coco/host/Makefile b/drivers/virt/coco/host/Makefile new file mode 100644 index 000000000000..be0aba6007cd --- /dev/null +++ b/drivers/virt/coco/host/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# TSM (TEE Security Manager) Common infrastructure and host drivers + +obj-$(CONFIG_TSM) += tsm.o +tsm-y := tsm-core.o diff --git a/drivers/virt/coco/host/tsm-core.c b/drivers/virt/coco/host/tsm-core.c new file mode 100644 index 000000000000..4f64af1a8967 --- /dev/null +++ b/drivers/virt/coco/host/tsm-core.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2024 Intel Corporation. All rights reserved. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include + +static DECLARE_RWSEM(tsm_core_rwsem); +static struct class *tsm_class; +static struct tsm_core_dev { + struct device dev; +} *tsm_core; + +static struct tsm_core_dev * +alloc_tsm_core(struct device *parent, const struct attribute_group **groups) +{ + struct tsm_core_dev *core = kzalloc(sizeof(*core), GFP_KERNEL); + struct device *dev; + + if (!core) + return ERR_PTR(-ENOMEM); + dev = &core->dev; + dev->parent = parent; + dev->groups = groups; + dev->class = tsm_class; + device_initialize(dev); + return core; +} + +static void put_tsm_core(struct tsm_core_dev *core) +{ + put_device(&core->dev); +} + +DEFINE_FREE(put_tsm_core, struct tsm_core_dev *, + if (!IS_ERR_OR_NULL(_T)) put_tsm_core(_T)) +struct tsm_core_dev *tsm_register(struct device *parent, + const struct attribute_group **groups) +{ + struct device *dev; + int rc; + + guard(rwsem_write)(&tsm_core_rwsem); + if (tsm_core) { + dev_warn(parent, "failed to register: %s already registered\n", + dev_name(tsm_core->dev.parent)); + return ERR_PTR(-EBUSY); + } + + struct tsm_core_dev *core __free(put_tsm_core) = + alloc_tsm_core(parent, groups); + if (IS_ERR(core)) + return core; + + dev = &core->dev; + rc = dev_set_name(dev, "tsm0"); + if (rc) + return ERR_PTR(rc); + + rc = device_add(dev); + if (rc) + return ERR_PTR(rc); + + tsm_core = no_free_ptr(core); + + return tsm_core; +} +EXPORT_SYMBOL_GPL(tsm_register); + +void tsm_unregister(struct tsm_core_dev *core) +{ + guard(rwsem_write)(&tsm_core_rwsem); + if (!tsm_core || core != tsm_core) { + pr_warn("failed to unregister, not currently registered\n"); + return; + } + + device_unregister(&core->dev); + tsm_core = NULL; +} +EXPORT_SYMBOL_GPL(tsm_unregister); + +static void tsm_release(struct device *dev) +{ + struct tsm_core_dev *core = container_of(dev, typeof(*core), dev); + + kfree(core); +} + +static int __init tsm_init(void) +{ + tsm_class = class_create("tsm"); + if (IS_ERR(tsm_class)) + return PTR_ERR(tsm_class); + + tsm_class->dev_release = tsm_release; + return 0; +} +module_init(tsm_init) + +static void __exit tsm_exit(void) +{ + class_destroy(tsm_class); +} +module_exit(tsm_exit) + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("TEE Security Manager core"); diff --git a/include/linux/tsm.h b/include/linux/tsm.h index 431054810dca..9253b79b8582 100644 --- a/include/linux/tsm.h +++ b/include/linux/tsm.h @@ -5,6 +5,7 @@ #include #include #include +#include #define TSM_REPORT_INBLOB_MAX 64 #define TSM_REPORT_OUTBLOB_MAX SZ_32K @@ -109,4 +110,8 @@ struct tsm_report_ops { int tsm_report_register(const struct tsm_report_ops *ops, void *priv); int tsm_report_unregister(const struct tsm_report_ops *ops); +struct tsm_core_dev; +struct tsm_core_dev *tsm_register(struct device *parent, + const struct attribute_group **groups); +void tsm_unregister(struct tsm_core_dev *tsm_core); #endif /* __TSM_H */ From patchwork Tue Mar 4 07:14:38 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 14000063 X-Patchwork-Delegate: bhelgaas@google.com Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.16]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DB18E1FBEAA for ; Tue, 4 Mar 2025 07:14:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.16 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741072482; cv=none; b=NuR/p1kco1yqnj+Kd2gAlEBfmkE7xMbzmSABlTypKqD/0mOZ/PMJVlzTGXow+fpHfs+JWdmvstVdBzZPQoG5q9zvMFu8gPEGnZSxt0KTOLMUAVIkIcvyswBS6vEjtpAV2rmHqCMU92MUD4CNIT0o+xHO6ucA4dQU0RshTUbcJbk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741072482; c=relaxed/simple; bh=QUZ+DqTMQnd86Ghk5JsAJV1kglDdnLwcgm+U88sTEmY=; h=Subject:From:To:Cc:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Zpmg0CNCBwhbcFE86njXs/zFKgSQSqqEpegWNh/KaAtugiCfwufxGJLsQrjrmce5+gYYaAP/4gZEJSWZw9pB/d96NPw1rPaCc27yqGNc0bTZ0ZTi3SKNfs72jcoWltMlX8mtSEem07VY3ZcMBEcJTnqnNEzC38OwzvRASjgB2jY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=lqCp962U; arc=none smtp.client-ip=192.198.163.16 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="lqCp962U" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1741072480; x=1772608480; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=QUZ+DqTMQnd86Ghk5JsAJV1kglDdnLwcgm+U88sTEmY=; b=lqCp962UJWCVVW6+6jvSI0EvfSvaDvn81bDXEawr4gqvpBd6g1+ltdmE XVeK49ZUfXlhteywAEaz93aZyK8KkxSP8hM3yrLkkgmspP5R6pOg5EhrB ZwbmU3LjR6U30ihHulqfdBCWxsWnXgcBT4bty5DHiqUBEpQyMU2+pR8tf RFXV6WaskKxJAmso9iX4mTi7qfMtys35QCvCLA5qoHyb4s6z66HNnfi/i E0rUlk8vL7zLyFjaPsLKPATJAKtchY9rfykg5ghV8gsS9qA25/TbbAVjM SjRF3iABsvSHPZLLbbHytUBAKdZvRvYu0W6MX8WNgGZobe5EYPUiKPsK0 Q==; X-CSE-ConnectionGUID: XG3AiwXxQregApC+TRtVjg== X-CSE-MsgGUID: UnlgTdNFRBW0TMVkdXd9uw== X-IronPort-AV: E=McAfee;i="6700,10204,11362"; a="29565120" X-IronPort-AV: E=Sophos;i="6.13,331,1732608000"; d="scan'208";a="29565120" Received: from fmviesa005.fm.intel.com ([10.60.135.145]) by fmvoesa110.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Mar 2025 23:14:40 -0800 X-CSE-ConnectionGUID: m0wbIc4aSjC+k/HoGAZa9g== X-CSE-MsgGUID: A38oBjOLQsOQtW8ITEhuEQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.13,331,1732608000"; d="scan'208";a="122905519" Received: from inaky-mobl1.amr.corp.intel.com (HELO dwillia2-xfh.jf.intel.com) ([10.125.109.47]) by fmviesa005-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Mar 2025 23:14:39 -0800 Subject: [PATCH v2 04/11] PCI/IDE: Enumerate Selective Stream IDE capabilities From: Dan Williams To: linux-coco@lists.linux.dev Cc: Yilun Xu , Jonathan Cameron , "Aneesh Kumar K.V" , Alexey Kardashevskiy , gregkh@linuxfoundation.org, linux-pci@vger.kernel.org, aik@amd.com, lukas@wunner.de Date: Mon, 03 Mar 2025 23:14:38 -0800 Message-ID: <174107247873.1288555.8934248700370548272.stgit@dwillia2-xfh.jf.intel.com> In-Reply-To: <174107245357.1288555.10863541957822891561.stgit@dwillia2-xfh.jf.intel.com> References: <174107245357.1288555.10863541957822891561.stgit@dwillia2-xfh.jf.intel.com> User-Agent: StGit/0.18-3-g996c Precedence: bulk X-Mailing-List: linux-pci@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Link encryption is a new PCIe feature enumerated by "PCIe 6.2 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 6.2 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. Cc: Yilun Xu Cc: Jonathan Cameron Cc: Aneesh Kumar K.V Co-developed-by: Alexey Kardashevskiy Signed-off-by: Alexey Kardashevskiy Signed-off-by: Dan Williams --- drivers/pci/Kconfig | 14 ++++++ drivers/pci/Makefile | 1 drivers/pci/ide.c | 89 +++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci.h | 6 +++ drivers/pci/probe.c | 1 include/linux/pci.h | 7 +++ include/uapi/linux/pci_regs.h | 81 +++++++++++++++++++++++++++++++++++++ 7 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 drivers/pci/ide.c diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 2fbd379923fd..5fb6dd113b0d 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -121,6 +121,20 @@ config XEN_PCIDEV_FRONTEND config PCI_ATS bool +config PCI_IDE + bool + +config PCI_IDE_STREAM_MAX + int "Maximum number of Selective IDE Streams supported per host bridge" if EXPERT + depends on PCI_IDE + range 1 256 + default 64 + help + Set a kernel limit for the number of streams. The expectation + is that the platform limit is 4 to 8, so the kernel need not + track the maximum possibility of 256 streams per host bridge + in the typical case. + config PCI_DOE bool diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 67647f1880fb..6612256fd37d 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -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 diff --git a/drivers/pci/ide.c b/drivers/pci/ide.c new file mode 100644 index 000000000000..193380763812 --- /dev/null +++ b/drivers/pci/ide.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2024 Intel Corporation. All rights reserved. */ + +/* PCIe 6.2 section 6.33 Integrity & Data Encryption (IDE) */ + +#define dev_fmt(fmt) "PCI/IDE: " fmt +#include +#include +#include "pci.h" + +static int sel_ide_offset(int nr_link_ide, int stream_index, int nr_ide_mem) +{ + int offset; + + offset = PCI_IDE_LINK_STREAM_0 + nr_link_ide * PCI_IDE_LINK_BLOCK_SIZE; + + /* + * Assume a constant number of address association resources per + * stream index + */ + if (stream_index > 0) + offset += stream_index * PCI_IDE_SEL_BLOCK_SIZE(nr_ide_mem); + return offset; +} + +void pci_ide_init(struct pci_dev *pdev) +{ + u8 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; + } + + if (val & PCI_IDE_CAP_SEL_CFG) + pdev->ide_cfg = 1; + + if (val & PCI_IDE_CAP_TEE_LIMITED) + pdev->ide_tee_limit = 1; + + if (val & PCI_IDE_CAP_LINK) + nr_link_ide = 1 + FIELD_GET(PCI_IDE_CAP_LINK_TC_NUM_MASK, val); + + nr_ide_mem = 0; + nr_streams = min(1 + FIELD_GET(PCI_IDE_CAP_SEL_NUM_MASK, val), + CONFIG_PCI_IDE_STREAM_MAX); + for (int i = 0; i < nr_streams; i++) { + int offset = sel_ide_offset(nr_link_ide, i, nr_ide_mem); + int nr_assoc; + u32 val; + + pci_read_config_dword(pdev, ide_cap + offset, &val); + + /* + * Let's not entertain devices that do not have a + * constant number of address association blocks + */ + nr_assoc = FIELD_GET(PCI_IDE_SEL_CAP_ASSOC_NUM_MASK, val); + if (i && (nr_assoc != nr_ide_mem)) { + pci_info(pdev, "Unsupported Selective Stream %d capability\n", i); + return; + } + + nr_ide_mem = nr_assoc; + } + + pdev->ide_cap = ide_cap; + pdev->nr_link_ide = nr_link_ide; + pdev->nr_ide_mem = nr_ide_mem; +} diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 01e51db8d285..6927028ab695 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -456,6 +456,12 @@ static inline void pci_npem_create(struct pci_dev *dev) { } static inline void pci_npem_remove(struct pci_dev *dev) { } #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. * diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 246744d8d268..6114d199c1d5 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2565,6 +2565,7 @@ static void pci_init_capabilities(struct pci_dev *dev) pci_rcec_init(dev); /* Root Complex Event Collector */ pci_doe_init(dev); /* Data Object Exchange */ pci_tph_init(dev); /* TLP Processing Hints */ + pci_ide_init(dev); /* Link Integrity and Data Encryption */ pcie_report_downtraining(dev); pci_init_reset_methods(dev); diff --git a/include/linux/pci.h b/include/linux/pci.h index 47b31ad724fa..628f9f5fdac9 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -530,6 +530,13 @@ struct pci_dev { #endif #ifdef CONFIG_PCI_NPEM struct npem *npem; /* Native PCIe Enclosure Management */ +#endif +#ifdef CONFIG_PCI_IDE + u16 ide_cap; /* Link Integrity & Data Encryption */ + u8 nr_ide_mem; /* Address association resources for streams */ + u8 nr_link_ide; /* Link Stream count (Selective Stream offset) */ + unsigned int ide_cfg:1; /* Config cycles over IDE */ + unsigned int ide_tee_limit:1; /* Disallow T=0 traffic over IDE */ #endif u16 acs_cap; /* ACS Capability offset */ u8 supported_speeds; /* Supported Link Speeds Vector */ diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index 3445c4970e4d..000258cd93c8 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -749,7 +749,8 @@ #define PCI_EXT_CAP_ID_NPEM 0x29 /* Native PCIe Enclosure Management */ #define PCI_EXT_CAP_ID_PL_32GT 0x2A /* Physical Layer 32.0 GT/s */ #define PCI_EXT_CAP_ID_DOE 0x2E /* Data Object Exchange */ -#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_DOE +#define PCI_EXT_CAP_ID_IDE 0x30 /* Integrity and Data Encryption */ +#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_IDE #define PCI_EXT_CAP_DSN_SIZEOF 12 #define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40 @@ -1213,4 +1214,82 @@ #define PCI_DVSEC_CXL_PORT_CTL 0x0c #define PCI_DVSEC_CXL_PORT_CTL_UNMASK_SBR 0x00000001 +/* Integrity and Data Encryption Extended Capability */ +#define PCI_IDE_CAP 0x4 +#define PCI_IDE_CAP_LINK 0x1 /* Link IDE Stream Supported */ +#define PCI_IDE_CAP_SELECTIVE 0x2 /* Selective IDE Streams Supported */ +#define PCI_IDE_CAP_FLOWTHROUGH 0x4 /* Flow-Through IDE Stream Supported */ +#define PCI_IDE_CAP_PARTIAL_HEADER_ENC 0x8 /* Partial Header Encryption Supported */ +#define PCI_IDE_CAP_AGGREGATION 0x10 /* Aggregation Supported */ +#define PCI_IDE_CAP_PCRC 0x20 /* PCRC Supported */ +#define PCI_IDE_CAP_IDE_KM 0x40 /* IDE_KM Protocol Supported */ +#define PCI_IDE_CAP_SEL_CFG 0x80 /* Selective IDE for Config Cycles Support */ +#define PCI_IDE_CAP_ALG_MASK __GENMASK(12, 8) /* 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_MASK __GENMASK(15, 13) /* Link IDE TCs */ +#define PCI_IDE_CAP_SEL_NUM_MASK __GENMASK(23, 16)/* Supported Selective IDE Streams */ +#define PCI_IDE_CAP_TEE_LIMITED 0x1000000 /* TEE-Limited Stream Supported */ +#define PCI_IDE_CTL 0x8 +#define PCI_IDE_CTL_FLOWTHROUGH_IDE 0x4 /* Flow-Through IDE Stream Enabled */ + +#define PCI_IDE_LINK_STREAM_0 0xc /* First Link Stream Register Block */ +#define PCI_IDE_LINK_BLOCK_SIZE 8 +/* Link IDE Stream block, up to PCI_IDE_CAP_LINK_TC_NUM */ +#define PCI_IDE_LINK_CTL_0 0x0 /* First Link Control Register Offset in block */ +#define PCI_IDE_LINK_CTL_EN 0x1 /* Link IDE Stream Enable */ +#define PCI_IDE_LINK_CTL_TX_AGGR_NPR_MASK __GENMASK(3, 2) /* Tx Aggregation Mode NPR */ +#define PCI_IDE_LINK_CTL_TX_AGGR_PR_MASK __GENMASK(5, 4) /* Tx Aggregation Mode PR */ +#define PCI_IDE_LINK_CTL_TX_AGGR_CPL_MASK __GENMASK(7, 6) /* Tx Aggregation Mode CPL */ +#define PCI_IDE_LINK_CTL_PCRC_EN 0x100 /* PCRC Enable */ +#define PCI_IDE_LINK_CTL_PART_ENC_MASK __GENMASK(13, 10) /* Partial Header Encryption Mode */ +#define PCI_IDE_LINK_CTL_ALG_MASK __GENMASK(18, 14) /* Selection from PCI_IDE_CAP_ALG */ +#define PCI_IDE_LINK_CTL_TC_MASK __GENMASK(21, 19) /* Traffic Class */ +#define PCI_IDE_LINK_CTL_ID_MASK __GENMASK(31, 24) /* Stream ID */ +#define PCI_IDE_LINK_STS_0 0x4 /* First Link Status Register Offset in block */ +#define PCI_IDE_LINK_STS_STATE __GENMASK(3, 0) /* Link IDE Stream State */ +#define PCI_IDE_LINK_STS_RECVD_INTEGRITY_CHECK 0x80000000 /* Received Integrity Check Fail Msg */ + +/* Selective IDE Stream block, up to PCI_IDE_CAP_SELECTIVE_STREAMS_NUM */ +/* Selective IDE Stream Capability Register */ +#define PCI_IDE_SEL_CAP 0 +#define PCI_IDE_SEL_CAP_ASSOC_NUM_MASK __GENMASK(3, 0) +/* Selective IDE Stream Control Register */ +#define PCI_IDE_SEL_CTL 4 +#define PCI_IDE_SEL_CTL_EN 0x1 /* Selective IDE Stream Enable */ +#define PCI_IDE_SEL_CTL_TX_AGGR_NPR_MASK __GENMASK(3, 2) /* Tx Aggregation Mode NPR */ +#define PCI_IDE_SEL_CTL_TX_AGGR_PR_MASK __GENMASK(5, 4) /* Tx Aggregation Mode PR */ +#define PCI_IDE_SEL_CTL_TX_AGGR_CPL_MASK __GENMASK(7, 6) /* Tx Aggregation Mode CPL */ +#define PCI_IDE_SEL_CTL_PCRC_EN 0x100 /* PCRC Enable */ +#define PCI_IDE_SEL_CTL_CFG_EN 0x200 /* Selective IDE for Configuration Requests */ +#define PCI_IDE_SEL_CTL_PART_ENC_MASK __GENMASK(13, 10) /* Partial Header Encryption Mode */ +#define PCI_IDE_SEL_CTL_ALG_MASK __GENMASK(18, 14) /* Selection from PCI_IDE_CAP_ALG */ +#define PCI_IDE_SEL_CTL_TC_MASK __GENMASK(21, 19) /* Traffic Class */ +#define PCI_IDE_SEL_CTL_DEFAULT 0x400000 /* Default Stream */ +#define PCI_IDE_SEL_CTL_TEE_LIMITED 0x800000 /* TEE-Limited Stream */ +#define PCI_IDE_SEL_CTL_ID_MASK __GENMASK(31, 24) /* Stream ID */ +#define PCI_IDE_SEL_CTL_ID_MAX 255 +/* Selective IDE Stream Status Register */ +#define PCI_IDE_SEL_STS 8 +#define PCI_IDE_SEL_STS_STATE_MASK __GENMASK(3, 0) /* Selective IDE Stream State */ +#define PCI_IDE_SEL_STS_RECVD_INTEGRITY_CHECK 0x80000000 /* Received Integrity Check Fail Msg */ +/* IDE RID Association Register 1 */ +#define PCI_IDE_SEL_RID_1 0xc +#define PCI_IDE_SEL_RID_1_LIMIT_MASK __GENMASK(23, 8) +/* IDE RID Association Register 2 */ +#define PCI_IDE_SEL_RID_2 0x10 +#define PCI_IDE_SEL_RID_2_VALID 0x1 +#define PCI_IDE_SEL_RID_2_BASE_MASK __GENMASK(23, 8) +#define PCI_IDE_SEL_RID_2_SEG_MASK __GENMASK(31, 24) +/* Selective IDE Address Association Register Block, up to PCI_IDE_SEL_CAP_ASSOC_NUM */ +#define PCI_IDE_SEL_ADDR_BLOCK_SIZE 12 +#define PCI_IDE_SEL_ADDR_1(x) (20 + (x) * PCI_IDE_SEL_ADDR_BLOCK_SIZE) +#define PCI_IDE_SEL_ADDR_1_VALID 0x1 +#define PCI_IDE_SEL_ADDR_1_BASE_LOW_MASK __GENMASK(19, 8) +#define PCI_IDE_SEL_ADDR_1_LIMIT_LOW_MASK __GENMASK(31, 20) +/* IDE Address Association Register 2 is "Memory Limit Upper" */ +/* IDE Address Association Register 3 is "Memory Base Upper" */ +#define PCI_IDE_SEL_ADDR_2(x) (24 + (x) * PCI_IDE_SEL_ADDR_BLOCK_SIZE) +#define PCI_IDE_SEL_ADDR_3(x) (28 + (x) * PCI_IDE_SEL_ADDR_BLOCK_SIZE) +#define PCI_IDE_SEL_BLOCK_SIZE(nr_assoc) (20 + PCI_IDE_SEL_ADDR_BLOCK_SIZE * (nr_assoc)) + #endif /* LINUX_PCI_REGS_H */ From patchwork Tue Mar 4 07:14:44 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 14000064 X-Patchwork-Delegate: bhelgaas@google.com Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.16]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BA5FA1F76A8 for ; Tue, 4 Mar 2025 07:14:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.16 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741072488; cv=none; b=RFhR2ycBYFMf82m2muhu7IMficwPxvhVJb77yMzDg+FGcFVNrdDFw5Ngqsw/FB2DmIuw6pm4+45A/+RlZsl563InqgHmQlGwRUnyzqcToSChCJhSinm5lzpOyjC/qUVGk0j3gqXMR9xDcwfjLSN5MkqSQzMreUXabijnJAQpZJw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741072488; c=relaxed/simple; bh=lHorGtrGPgvWvAiW7aEKuvcs2Heqie+KAH3L4WVkZW4=; h=Subject:From:To:Cc:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=URprEb6MZ6YEBz9PY8iLElNvqS9HBpa9qvDRaKXKy/CNevM75en4WkNZtP+xQwC/svScDqDjMLXrBxIsiZbn2fzaPTkfMQoTYtQf1Vpe6yvZ6mTJAKYJSZ1WRn0vUin5H8ub86gW0woLeyX8U4GbwqvLndm5et3Fw6OcEnHdZRE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=CAFJxGPF; arc=none smtp.client-ip=192.198.163.16 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="CAFJxGPF" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1741072486; x=1772608486; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=lHorGtrGPgvWvAiW7aEKuvcs2Heqie+KAH3L4WVkZW4=; b=CAFJxGPFNvyu++7epW2VdCjLrV8I+IjzG/aYpTM1vTEVQAwupBU3Ampo xK0TN+tHqirlWGW/ddSwfG+2lGQA7+FG39xmP7UsR31vY00rhXe8Yx/bJ XR+LIJqxBpVdWnc8XXEN8cj/wn94kkMJB+zGS30RFPD5YQ+7Jrckp+LvW 55LBHmYktKMmWHlmSsGlhvJEJUsrYetfW9z9xxZyH+azzLy8I2yih3TIg apH9DhpfXG5jR9ehgGIbPCY865/jsW1THKABPRHj49DTNBDXIyhKu4dJW lJndiNH/AkjX08x/MNMEDxs51/1T+heBdFsYCjdeqZYcWbtVXob/UXMpN g==; X-CSE-ConnectionGUID: /Cnwj7UNSae3GCWx1H8OzQ== X-CSE-MsgGUID: J7g0QjZrStC9hXnNHjbV8g== X-IronPort-AV: E=McAfee;i="6700,10204,11362"; a="29565131" X-IronPort-AV: E=Sophos;i="6.13,331,1732608000"; d="scan'208";a="29565131" Received: from fmviesa005.fm.intel.com ([10.60.135.145]) by fmvoesa110.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Mar 2025 23:14:45 -0800 X-CSE-ConnectionGUID: v6rzj1WyT3+kw40KlMIr3A== X-CSE-MsgGUID: lg3r1DjHRY+EkRq+WO36jQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.13,331,1732608000"; d="scan'208";a="122905524" Received: from inaky-mobl1.amr.corp.intel.com (HELO dwillia2-xfh.jf.intel.com) ([10.125.109.47]) by fmviesa005-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Mar 2025 23:14:45 -0800 Subject: [PATCH v2 05/11] PCI/TSM: Authenticate devices via platform TSM From: Dan Williams To: linux-coco@lists.linux.dev Cc: Lukas Wunner , Samuel Ortiz , Alexey Kardashevskiy , Bjorn Helgaas , Xu Yilun , gregkh@linuxfoundation.org, linux-pci@vger.kernel.org, aik@amd.com, lukas@wunner.de Date: Mon, 03 Mar 2025 23:14:44 -0800 Message-ID: <174107248456.1288555.10068789075179290465.stgit@dwillia2-xfh.jf.intel.com> In-Reply-To: <174107245357.1288555.10863541957822891561.stgit@dwillia2-xfh.jf.intel.com> References: <174107245357.1288555.10863541957822891561.stgit@dwillia2-xfh.jf.intel.com> User-Agent: StGit/0.18-3-g996c Precedence: bulk X-Mailing-List: linux-pci@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The PCIe 6.1 specification, section 11, introduces the Trusted Execution Environment (TEE) Device Interface Security Protocol (TDISP). This protocol definition builds upon Component Measurement and Authentication (CMA), and link Integrity and Data Encryption (IDE). It adds support for assigning devices (PCI physical or virtual function) to a confidential VM such that the assigned device is enabled to access guest private memory protected by technologies like Intel TDX, AMD SEV-SNP, RISCV COVE, or ARM CCA. The "TSM" (TEE Security Manager) is a concept in the TDISP specification of an agent that mediates between a "DSM" (Device Security Manager) and system software in both a VMM and a confidential VM. A VMM uses TSM ABIs to setup link security and assign devices. A confidential VM uses TSM ABIs to transition an assigned device into the TDISP "RUN" state and validate its configuration. From a Linux perspective the TSM abstracts many of the details of TDISP, IDE, and CMA. Some of those details leak through at times, but for the most part TDISP is an internal implementation detail of the TSM. CONFIG_PCI_TSM adds an "authenticated" attribute and "tsm/" subdirectory to pci-sysfs. Consider that the TSM driver may itself be a PCI driver. Userspace can watch for the arrival of the "TSM" core device, /sys/class/tsm/tsm0/uevent, to know when the PCI core has initialized TSM services. The common verbs that the low-level TSM drivers implement are defined by 'struct pci_tsm_ops'. For now only 'connect' and 'disconnect' are defined for secure session and IDE establishment. The 'probe' and 'remove' operations setup per-device context objects starting with 'struct pci_tsm_pf0', the device Physical Function 0 that mediates communication to the device's Security Manager (DSM). The locking allows for multiple devices to be executing commands simultaneously, one outstanding command per-device and an rwsem synchronizes the implementation relative to TSM registration/unregistration events. Thanks to Wu Hao for his work on an early draft of this support. Cc: Lukas Wunner Cc: Samuel Ortiz Cc: Alexey Kardashevskiy Acked-by: Bjorn Helgaas Co-developed-by: Xu Yilun Signed-off-by: Xu Yilun Signed-off-by: Dan Williams --- Documentation/ABI/testing/sysfs-bus-pci | 45 ++++ MAINTAINERS | 2 drivers/pci/Kconfig | 23 ++ drivers/pci/Makefile | 1 drivers/pci/pci-sysfs.c | 4 drivers/pci/pci.h | 10 + drivers/pci/probe.c | 1 drivers/pci/remove.c | 3 drivers/pci/tsm.c | 377 +++++++++++++++++++++++++++++++ drivers/virt/coco/host/tsm-core.c | 19 +- include/linux/pci-tsm.h | 135 +++++++++++ include/linux/pci.h | 3 include/linux/tsm.h | 4 include/uapi/linux/pci_regs.h | 1 14 files changed, 625 insertions(+), 3 deletions(-) create mode 100644 drivers/pci/tsm.c create mode 100644 include/linux/pci-tsm.h diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index 5da6a14dc326..816a342695b3 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci @@ -583,3 +583,48 @@ Description: enclosure-specific indications "specific0" to "specific7", hence the corresponding led class devices are unavailable if the DSM interface is used. + +What: /sys/bus/pci/devices/.../tsm/ +Date: July 2024 +Contact: linux-coco@lists.linux.dev +Description: + This directory only appears if a physical device function + supports authentication (PCIe CMA-SPDM), interface security + (PCIe TDISP), and is accepted for secure operation by the + platform TSM driver. This attribute directory appears + dynamically after the platform TSM driver loads. So, only after + the /sys/class/tsm/tsm0 device arrives can tools assume that + devices without a tsm/ attribute directory will never have one, + before that, the security capabilities of the device relative to + the platform TSM are unknown. See + Documentation/ABI/testing/sysfs-class-tsm. + +What: /sys/bus/pci/devices/.../tsm/connect +Date: July 2024 +Contact: linux-coco@lists.linux.dev +Description: + (RW) Writing "1" to this file triggers the platform TSM (TEE + Security Manager) to establish a connection with the device. + This typically includes an SPDM (DMTF Security Protocols and + Data Models) session over PCIe DOE (Data Object Exchange) and + may also include PCIe IDE (Integrity and Data Encryption) + establishment. + +What: /sys/bus/pci/devices/.../authenticated +Date: July 2024 +Contact: linux-pci@vger.kernel.org +Description: + When the device's tsm/ directory is present device + authentication (PCIe CMA-SPDM) and link encryption (PCIe IDE) + are handled by the platform TSM (TEE Security Manager). When the + tsm/ directory is not present this attribute reflects only the + native CMA-SPDM authentication state with the kernel's + certificate store. + + If the attribute is not present, it indicates that + authentication is unsupported by the device, or the TSM has no + available authentication methods for the device. + + When present and the tsm/ attribute directory is present, the + authenticated attribute is an alias for the device 'connect' + state. See the 'tsm/connect' attribute for more details. diff --git a/MAINTAINERS b/MAINTAINERS index 352f982f435e..80a5951bfa04 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -24116,8 +24116,10 @@ M: Dan Williams L: linux-coco@lists.linux.dev S: Maintained F: Documentation/ABI/testing/configfs-tsm-report +F: drivers/pci/tsm.c F: drivers/virt/coco/guest/ F: drivers/virt/coco/host/ +F: include/linux/pci-tsm.h F: include/linux/tsm.h TRUSTED SERVICES TEE DRIVER diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 5fb6dd113b0d..f9e0e517aaed 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -135,6 +135,29 @@ config PCI_IDE_STREAM_MAX track the maximum possibility of 256 streams per host bridge in the typical case. +config PCI_TSM + bool "PCI TSM: Device security protocol support" + select PCI_IDE + select PCI_DOE + help + The TEE (Trusted Execution Environment) Device Interface + Security Protocol (TDISP) defines a "TSM" as a platform agent + that manages device authentication, link encryption, link + integrity protection, and assignment of PCI device functions + (virtual or physical) to confidential computing VMs that can + access (DMA) guest private memory. + + Enable a platform TSM driver to use this capability. + +config PCI_TSM_DEBUG + bool "PCI TSM: Debug" + depends on PCI_TSM + help + Enable runtime sanity checks and assertions for the pci_tsm + object model. For example, validate that a low-level TSM + driver use the expected initialization helpers for newly + created objects. + config PCI_DOE bool diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 6612256fd37d..2c545f877062 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -35,6 +35,7 @@ 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_TSM) += tsm.o obj-$(CONFIG_PCI_DYNAMIC_OF_NODES) += of_property.o obj-$(CONFIG_PCI_NPEM) += npem.o obj-$(CONFIG_PCIE_TPH) += tph.o diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index b46ce1a2c554..b595cbaed8c0 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -1804,6 +1804,10 @@ const struct attribute_group *pci_dev_attr_groups[] = { #endif #ifdef CONFIG_PCIEASPM &aspm_ctrl_attr_group, +#endif +#ifdef CONFIG_PCI_TSM + &pci_tsm_auth_attr_group, + &pci_tsm_pf0_attr_group, #endif NULL, }; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 6927028ab695..b38bdd91e742 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -462,6 +462,16 @@ void pci_ide_init(struct pci_dev *dev); static inline void pci_ide_init(struct pci_dev *dev) { } #endif +#ifdef CONFIG_PCI_TSM +void pci_tsm_init(struct pci_dev *pdev); +void pci_tsm_destroy(struct pci_dev *pdev); +extern const struct attribute_group pci_tsm_pf0_attr_group; +extern const struct attribute_group pci_tsm_auth_attr_group; +#else +static inline void pci_tsm_init(struct pci_dev *pdev) { } +static inline void pci_tsm_destroy(struct pci_dev *pdev) { } +#endif + /** * pci_dev_set_io_state - Set the new error state if possible. * diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 6114d199c1d5..1d1d7de642da 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2566,6 +2566,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_ide_init(dev); /* Link Integrity and Data Encryption */ + pci_tsm_init(dev); /* TEE Security Manager connection */ pcie_report_downtraining(dev); pci_init_reset_methods(dev); diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index efc37fcb73e2..fd4ccafed067 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -55,6 +55,9 @@ static void pci_destroy_dev(struct pci_dev *dev) pci_npem_remove(dev); + /* before device_del() to keep config cycle access */ + pci_tsm_destroy(dev); + device_del(&dev->dev); down_write(&pci_bus_sem); diff --git a/drivers/pci/tsm.c b/drivers/pci/tsm.c new file mode 100644 index 000000000000..e5ea9f306672 --- /dev/null +++ b/drivers/pci/tsm.c @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * TEE Security Manager for the TEE Device Interface Security Protocol + * (TDISP, PCIe r6.1 sec 11) + * + * Copyright(c) 2024 Intel Corporation. All rights reserved. + */ + +#define dev_fmt(fmt) "TSM: " fmt + +#include +#include +#include + +#include +#include +#include +#include "pci.h" + +/* + * Provide a read/write lock against the init / exit of pdev tsm + * capabilities and arrival/departure of a tsm instance + */ +static DECLARE_RWSEM(pci_tsm_rwsem); +static const struct pci_tsm_ops *tsm_ops; + +/* supplemental attributes to surface when pci_tsm_attr_group is active */ +static const struct attribute_group *pci_tsm_owner_attr_group; + +static struct pci_tsm_pf0 *to_pci_tsm_pf0(struct pci_tsm *pci_tsm) +{ + struct pci_dev *pdev = pci_tsm->pdev; + + if (!is_pci_tsm_pf0(pdev) || !pci_tsm_check_type(pci_tsm, PCI_TSM_PF0)) { + dev_WARN_ONCE(&pdev->dev, 1, "invalid context object\n"); + return NULL; + } + + return container_of(pci_tsm, struct pci_tsm_pf0, tsm); +} + +static struct mutex *tsm_ops_lock(struct pci_tsm_pf0 *tsm) +{ + lockdep_assert_held(&pci_tsm_rwsem); + + if (mutex_lock_interruptible(&tsm->lock) != 0) + return NULL; + return &tsm->lock; +} +DEFINE_FREE(tsm_ops_unlock, struct mutex *, if (_T) mutex_unlock(_T)) + +static int pci_tsm_disconnect(struct pci_dev *pdev) +{ + struct pci_tsm_pf0 *tsm = to_pci_tsm_pf0(pdev->tsm); + + struct mutex *lock __free(tsm_ops_unlock) = tsm_ops_lock(tsm); + if (!lock) + return -EINTR; + + if (tsm->state < PCI_TSM_INIT) + return -ENXIO; + if (tsm->state < PCI_TSM_CONNECT) + return 0; + + tsm_ops->disconnect(pdev); + tsm->state = PCI_TSM_INIT; + + return 0; +} + +static int pci_tsm_connect(struct pci_dev *pdev) +{ + struct pci_tsm_pf0 *tsm = to_pci_tsm_pf0(pdev->tsm); + int rc; + + struct mutex *lock __free(tsm_ops_unlock) = tsm_ops_lock(tsm); + if (!lock) + return -EINTR; + + if (tsm->state < PCI_TSM_INIT) + return -ENXIO; + if (tsm->state >= PCI_TSM_CONNECT) + return 0; + + rc = tsm_ops->connect(pdev); + if (rc) + return rc; + tsm->state = PCI_TSM_CONNECT; + return 0; +} + +/* registration read lock */ +static struct rw_semaphore *tsm_read_lock(void) +{ + if (down_read_interruptible(&pci_tsm_rwsem)) + return NULL; + return &pci_tsm_rwsem; +} +DEFINE_FREE(tsm_read_unlock, struct rw_semaphore *, if (_T) up_read(_T)) + +static ssize_t connect_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) +{ + int rc; + bool connect; + struct pci_dev *pdev = to_pci_dev(dev); + + rc = kstrtobool(buf, &connect); + if (rc) + return rc; + + struct rw_semaphore *lock __free(tsm_read_unlock) = tsm_read_lock(); + if (!lock) + return -EINTR; + + if (connect) + rc = pci_tsm_connect(pdev); + else + rc = pci_tsm_disconnect(pdev); + if (rc) + return rc; + return len; +} + +static ssize_t connect_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct pci_tsm_pf0 *tsm; + + struct rw_semaphore *lock __free(tsm_read_unlock) = tsm_read_lock(); + if (!lock) + return -EINTR; + + if (!pdev->tsm) + return -ENXIO; + + tsm = to_pci_tsm_pf0(pdev->tsm); + return sysfs_emit(buf, "%d\n", tsm->state >= PCI_TSM_CONNECT); +} +static DEVICE_ATTR_RW(connect); + +static bool pci_tsm_pf0_group_visible(struct kobject *kobj) +{ + struct device *dev = kobj_to_dev(kobj); + struct pci_dev *pdev = to_pci_dev(dev); + + if (pdev->tsm && is_pci_tsm_pf0(pdev)) + return true; + return false; +} +DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(pci_tsm_pf0); + +static struct attribute *pci_tsm_pf0_attrs[] = { + &dev_attr_connect.attr, + NULL +}; + +const struct attribute_group pci_tsm_pf0_attr_group = { + .name = "tsm", + .attrs = pci_tsm_pf0_attrs, + .is_visible = SYSFS_GROUP_VISIBLE(pci_tsm_pf0), +}; + +static ssize_t authenticated_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + /* + * When device authentication is TSM owned, 'authenticated' is + * identical to the connect state. + */ + return connect_show(dev, attr, buf); +} +static DEVICE_ATTR_RO(authenticated); + +static struct attribute *pci_tsm_auth_attrs[] = { + &dev_attr_authenticated.attr, + NULL +}; + +const struct attribute_group pci_tsm_auth_attr_group = { + .attrs = pci_tsm_auth_attrs, + .is_visible = SYSFS_GROUP_VISIBLE(pci_tsm_pf0), +}; + +/** + * pci_tsm_pf0_initialize() - common 'struct pci_tsm_pf0' initialization + * @pdev: Physical Function 0 PCI device + * @tsm: context to initialize + */ +int pci_tsm_pf0_initialize(struct pci_dev *pdev, struct pci_tsm_pf0 *tsm) +{ + mutex_init(&tsm->lock); + tsm->doe_mb = pci_find_doe_mailbox(pdev, PCI_VENDOR_ID_PCI_SIG, + PCI_DOE_PROTO_CMA); + if (!tsm->doe_mb) { + pci_warn(pdev, "TSM init failure, no CMA mailbox\n"); + return -ENODEV; + } + + tsm->state = PCI_TSM_INIT; + pci_tsm_set_type(&tsm->tsm, PCI_TSM_PF0); + tsm->tsm.pdev = pdev; + + return 0; +} +EXPORT_SYMBOL_GPL(pci_tsm_pf0_initialize); + +static void tsm_remove(struct pci_tsm *tsm) +{ + if (!tsm) + return; + tsm_ops->remove(tsm); +} +DEFINE_FREE(tsm_remove, struct pci_tsm *, if (_T) tsm_remove(_T)) + +static void pci_tsm_pf0_init(struct pci_dev *pdev) +{ + bool tee_cap; + + tee_cap = pdev->devcap & PCI_EXP_DEVCAP_TEE; + + if (!(pdev->ide_cap || tee_cap)) + return; + + lockdep_assert_held_write(&pci_tsm_rwsem); + if (!tsm_ops) + return; + + /* + * If a physical device has any security capabilities it may be + * a candidate to connect with the platform TSM + */ + struct pci_tsm *pci_tsm __free(tsm_remove) = tsm_ops->probe(pdev); + + pci_dbg(pdev, "Device security capabilities detected (%s%s ), TSM %s\n", + pdev->ide_cap ? " ide" : "", tee_cap ? " tee" : "", + pci_tsm ? "attach" : "skip"); + + if (!pci_tsm) + return; + + pdev->tsm = no_free_ptr(pci_tsm); + sysfs_update_group(&pdev->dev.kobj, &pci_tsm_auth_attr_group); + sysfs_update_group(&pdev->dev.kobj, &pci_tsm_pf0_attr_group); + if (pci_tsm_owner_attr_group) + sysfs_merge_group(&pdev->dev.kobj, pci_tsm_owner_attr_group); +} + +static void pci_tsm_virtfn_init(struct pci_dev *pdev) +{ + if (!pci_physfn(pdev)->tsm) + return; + + struct pci_tsm *pci_tsm __free(tsm_remove) = tsm_ops->probe(pdev); + if (!pci_tsm) + return; + + pdev->tsm = no_free_ptr(pci_tsm); +} + +static void pci_tsm_mfd_init(struct pci_dev *pdev) +{ + struct pci_dev *pf0_dev __free(pci_dev_put) = + pci_get_slot(pdev->bus, pdev->devfn - PCI_FUNC(pdev->devfn)); + + if (!pf0_dev) + return; + + if (!pf0_dev->tsm) + return; + + struct pci_tsm *pci_tsm __free(tsm_remove) = tsm_ops->probe(pdev); + if (!pci_tsm) + return; + + pdev->tsm = no_free_ptr(pci_tsm); +} + +static void __pci_tsm_init(struct pci_dev *pdev) +{ + if (is_pci_tsm_pf0(pdev)) + pci_tsm_pf0_init(pdev); + else if (pdev->is_virtfn) + pci_tsm_virtfn_init(pdev); + else + pci_tsm_mfd_init(pdev); +} + +void pci_tsm_init(struct pci_dev *pdev) +{ + guard(rwsem_write)(&pci_tsm_rwsem); + __pci_tsm_init(pdev); +} + +int pci_tsm_core_register(const struct pci_tsm_ops *ops, const struct attribute_group *grp) +{ + struct pci_dev *pdev = NULL; + + if (!ops) + return 0; + guard(rwsem_write)(&pci_tsm_rwsem); + if (tsm_ops) + return -EBUSY; + tsm_ops = ops; + pci_tsm_owner_attr_group = grp; + for_each_pci_dev(pdev) + __pci_tsm_init(pdev); + return 0; +} +EXPORT_SYMBOL_GPL(pci_tsm_core_register); + +static void pci_tsm_pf0_destroy(struct pci_dev *pdev) +{ + struct pci_tsm_pf0 *tsm = to_pci_tsm_pf0(pdev->tsm); + + if (tsm->state > PCI_TSM_INIT) + pci_tsm_disconnect(pdev); + pdev->tsm = NULL; + if (pci_tsm_owner_attr_group) + sysfs_unmerge_group(&pdev->dev.kobj, pci_tsm_owner_attr_group); + sysfs_update_group(&pdev->dev.kobj, &pci_tsm_pf0_attr_group); + sysfs_update_group(&pdev->dev.kobj, &pci_tsm_auth_attr_group); +} + +static void __pci_tsm_destroy(struct pci_dev *pdev) +{ + struct pci_tsm *pci_tsm = pdev->tsm; + + if (!pci_tsm) + return; + + lockdep_assert_held_write(&pci_tsm_rwsem); + + if (is_pci_tsm_pf0(pdev)) + pci_tsm_pf0_destroy(pdev); + tsm_ops->remove(pci_tsm); +} + +void pci_tsm_destroy(struct pci_dev *pdev) +{ + guard(rwsem_write)(&pci_tsm_rwsem); + __pci_tsm_destroy(pdev); +} + +void pci_tsm_core_unregister(const struct pci_tsm_ops *ops) +{ + struct pci_dev *pdev = NULL; + + if (!ops) + return; + guard(rwsem_write)(&pci_tsm_rwsem); + if (ops != tsm_ops) + return; + for_each_pci_dev(pdev) + __pci_tsm_destroy(pdev); + tsm_ops = NULL; +} +EXPORT_SYMBOL_GPL(pci_tsm_core_unregister); + +int pci_tsm_doe_transfer(struct pci_dev *pdev, enum pci_doe_proto type, + const void *req, size_t req_sz, void *resp, + size_t resp_sz) +{ + struct pci_tsm_pf0 *tsm; + + if (!pdev->tsm || !is_pci_tsm_pf0(pdev)) + return -ENXIO; + + tsm = to_pci_tsm_pf0(pdev->tsm); + if (!tsm->doe_mb) + return -ENXIO; + + return pci_doe(tsm->doe_mb, PCI_VENDOR_ID_PCI_SIG, type, req, req_sz, + resp, resp_sz); +} +EXPORT_SYMBOL_GPL(pci_tsm_doe_transfer); diff --git a/drivers/virt/coco/host/tsm-core.c b/drivers/virt/coco/host/tsm-core.c index 4f64af1a8967..51146f226a64 100644 --- a/drivers/virt/coco/host/tsm-core.c +++ b/drivers/virt/coco/host/tsm-core.c @@ -8,11 +8,13 @@ #include #include #include +#include static DECLARE_RWSEM(tsm_core_rwsem); static struct class *tsm_class; static struct tsm_core_dev { struct device dev; + const struct pci_tsm_ops *pci_ops; } *tsm_core; static struct tsm_core_dev * @@ -39,7 +41,8 @@ static void put_tsm_core(struct tsm_core_dev *core) DEFINE_FREE(put_tsm_core, struct tsm_core_dev *, if (!IS_ERR_OR_NULL(_T)) put_tsm_core(_T)) struct tsm_core_dev *tsm_register(struct device *parent, - const struct attribute_group **groups) + const struct attribute_group **groups, + const struct pci_tsm_ops *pci_ops) { struct device *dev; int rc; @@ -61,10 +64,20 @@ struct tsm_core_dev *tsm_register(struct device *parent, if (rc) return ERR_PTR(rc); + rc = pci_tsm_core_register(pci_ops, NULL); + if (rc) { + dev_err(parent, "PCI initialization failure: %pe\n", + ERR_PTR(rc)); + return ERR_PTR(rc); + } + rc = device_add(dev); - if (rc) + if (rc) { + pci_tsm_core_unregister(pci_ops); return ERR_PTR(rc); + } + core->pci_ops = pci_ops; tsm_core = no_free_ptr(core); return tsm_core; @@ -79,7 +92,9 @@ void tsm_unregister(struct tsm_core_dev *core) return; } + pci_tsm_core_unregister(core->pci_ops); device_unregister(&core->dev); + tsm_core = NULL; } EXPORT_SYMBOL_GPL(tsm_unregister); diff --git a/include/linux/pci-tsm.h b/include/linux/pci-tsm.h new file mode 100644 index 000000000000..17657b7ef66c --- /dev/null +++ b/include/linux/pci-tsm.h @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PCI_TSM_H +#define __PCI_TSM_H +#include +#include + +struct pci_dev; + +enum pci_tsm_state { + PCI_TSM_ERR = -1, + PCI_TSM_INIT, + PCI_TSM_CONNECT, +}; + +enum pci_tsm_type { + PCI_TSM_INVALID, + PCI_TSM_PF0, + PCI_TSM_VIRTFN, + PCI_TSM_MFD, +}; + +/** + * struct pci_tsm - Core TSM context for a given PCIe endpoint + * @pdev: indicates the type of pci_tsm object + * @type: debug validation of the pci_tsm object type inferred by @pdev + * + * This structure is wrapped by a low level TSM driver and returned by + * tsm_ops.probe(), it is freed by tsm_ops.remove(). Depending on + * whether @pdev is physical function 0, another physical function, or a + * virtual function determines the pci_tsm object type. E.g. see 'struct + * pci_tsm_pf0'. + */ +struct pci_tsm { + struct pci_dev *pdev; +#ifdef CONFIG_PCI_TSM_DEBUG + enum pci_tsm_type type; +#endif +}; + +#ifdef CONFIG_PCI_TSM_DEBUG +static inline void pci_tsm_set_type(struct pci_tsm *pci_tsm, enum pci_tsm_type type) +{ + pci_tsm->type = type; +} +static inline bool pci_tsm_check_type(struct pci_tsm *pci_tsm, enum pci_tsm_type type) +{ + return pci_tsm->type == type; +} +#else +static inline void pci_tsm_set_type(struct pci_tsm *pci_tsm, enum pci_tsm_type type) +{ +} + +static inline bool pci_tsm_check_type(struct pci_tsm *pci_tsm, enum pci_tsm_type type) +{ + return true; +} +#endif + +/** + * struct pci_tsm_pf0 - Physical Function 0 TDISP context + * @state: reflect device initialized, connected, or bound + * @lock: protect @state vs pci_tsm_ops invocation + * @doe_mb: PCIe Data Object Exchange mailbox + */ +struct pci_tsm_pf0 { + struct pci_tsm tsm; + enum pci_tsm_state state; + struct mutex lock; + struct pci_doe_mb *doe_mb; +}; + +static inline bool is_pci_tsm_pf0(struct pci_dev *pdev) +{ + if (!pci_is_pcie(pdev)) + return false; + + if (pdev->is_virtfn) + return false; + + if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT) + return false; + + return PCI_FUNC(pdev->devfn) == 0; +} + +/** + * struct pci_tsm_ops - Low-level TSM-exported interface to the PCI core + * @probe: probe/accept device for tsm operation, setup DSM context + * @remove: destroy DSM context + * @connect: establish / validate a secure connection (e.g. IDE) with the device + * @disconnect: teardown the secure connection + * + * @probe and @remove run in pci_tsm_rwsem held for write context. All + * other ops run under the @pdev->tsm->lock mutex and pci_tsm_rwsem held + * for read. + */ +struct pci_tsm_ops { + struct pci_tsm *(*probe)(struct pci_dev *pdev); + void (*remove)(struct pci_tsm *tsm); + int (*connect)(struct pci_dev *pdev); + void (*disconnect)(struct pci_dev *pdev); +}; + +enum pci_doe_proto { + PCI_DOE_PROTO_CMA = 1, + PCI_DOE_PROTO_SSESSION = 2, +}; + +#ifdef CONFIG_PCI_TSM +int pci_tsm_core_register(const struct pci_tsm_ops *ops, + const struct attribute_group *grp); +void pci_tsm_core_unregister(const struct pci_tsm_ops *ops); +int pci_tsm_doe_transfer(struct pci_dev *pdev, enum pci_doe_proto type, + const void *req, size_t req_sz, void *resp, + size_t resp_sz); +int pci_tsm_pf0_initialize(struct pci_dev *pdev, struct pci_tsm_pf0 *tsm); +#else +static inline int pci_tsm_core_register(const struct pci_tsm_ops *ops, + const struct attribute_group *grp) +{ + return 0; +} +static inline void pci_tsm_core_unregister(const struct pci_tsm_ops *ops) +{ +} +static inline int pci_tsm_doe_transfer(struct pci_dev *pdev, + enum pci_doe_proto type, const void *req, + size_t req_sz, void *resp, + size_t resp_sz) +{ + return -ENOENT; +} +#endif +#endif /*__PCI_TSM_H */ diff --git a/include/linux/pci.h b/include/linux/pci.h index 628f9f5fdac9..57cfa0e3f2bd 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -537,6 +537,9 @@ struct pci_dev { u8 nr_link_ide; /* Link Stream count (Selective Stream offset) */ unsigned int ide_cfg:1; /* Config cycles over IDE */ unsigned int ide_tee_limit:1; /* Disallow T=0 traffic over IDE */ +#endif +#ifdef CONFIG_PCI_TSM + struct pci_tsm *tsm; /* TSM operation state */ #endif u16 acs_cap; /* ACS Capability offset */ u8 supported_speeds; /* Supported Link Speeds Vector */ diff --git a/include/linux/tsm.h b/include/linux/tsm.h index 9253b79b8582..59d3848404e1 100644 --- a/include/linux/tsm.h +++ b/include/linux/tsm.h @@ -111,7 +111,9 @@ struct tsm_report_ops { int tsm_report_register(const struct tsm_report_ops *ops, void *priv); int tsm_report_unregister(const struct tsm_report_ops *ops); struct tsm_core_dev; +struct pci_tsm_ops; struct tsm_core_dev *tsm_register(struct device *parent, - const struct attribute_group **groups); + const struct attribute_group **groups, + const struct pci_tsm_ops *ops); void tsm_unregister(struct tsm_core_dev *tsm_core); #endif /* __TSM_H */ diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index 000258cd93c8..713588a29813 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -499,6 +499,7 @@ #define PCI_EXP_DEVCAP_PWR_VAL 0x03fc0000 /* Slot Power Limit Value */ #define PCI_EXP_DEVCAP_PWR_SCL 0x0c000000 /* Slot Power Limit Scale */ #define PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */ +#define PCI_EXP_DEVCAP_TEE 0x40000000 /* TEE I/O (TDISP) Support */ #define PCI_EXP_DEVCTL 0x08 /* Device Control */ #define PCI_EXP_DEVCTL_CERE 0x0001 /* Correctable Error Reporting En. */ #define PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting Enable */ From patchwork Tue Mar 4 07:14:50 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 14000065 X-Patchwork-Delegate: bhelgaas@google.com Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 810041F76B6 for ; Tue, 4 Mar 2025 07:14:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741072494; cv=none; b=cdhX2uWZibl2ChePlIGUYLcyzVQiCGeaUdTXhl0Pt/YUIRl8hHQl4NACyUY88PNmwsa4oOrh9FYBsNmznpzJcc49MaHW8EkPmKXAOFcJ/eeL3UBoibT8kJ6zgZ+QmmUL76ANByfe7UpJZ4bSEBMJ4BTaR099rIAUyiv50qiTYmk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741072494; c=relaxed/simple; bh=73hpUD012jPJVSpwLrms2dD/TuVyQpbvkwh7t5I21xQ=; h=Subject:From:To:Cc:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=BqIAQlvpKb77JoMsTVctBePVSCIYoGxI4KWaGsxwpzn6Qcs1HjzPRsxjB4Os19GVWMBwieG2Tu5sPOeiOprGN190YtN+JUwnm8TC8+ZFnD4fvMuEWb+N3KXN7om9k3E+ysEiZUdjN/q9PhTELSlRnFwYEq+cGJfRPL4vEG4uQTU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=YF5oiG9b; arc=none smtp.client-ip=198.175.65.11 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="YF5oiG9b" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1741072492; x=1772608492; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=73hpUD012jPJVSpwLrms2dD/TuVyQpbvkwh7t5I21xQ=; b=YF5oiG9bjrTsGPpousCU6trvOmFRDMEoDa5C+Bj8RH3nEELWxtNJ7RfN xWmlPjx7mhxxP1vDnL8p7MgzPF6I7Knzk0YUifeqdCfubm/a5URziULzn v8/oCpXJwcjUM5+BZKRuyoGwuc7Rh0VFK4VwQgKmf8juGcZ/yRf52XbMq RrCZKbsOGfM+hgEdZ9BQ6cMwzP3oOrRyAya5/LvD5ARriRm7CHoFm/U2g X/npUS/MNdwY80sYgte319AlgDvbsyeQAimSdVvm/58yCyGnbFpfJXHuu fpuBM/DTzwq8Hey3P/+kUikBDujY6qleigr6HACpabQv+0KEZZ+Z365vL Q==; X-CSE-ConnectionGUID: 6VSkrwXbTUSIzovfUnfWsg== X-CSE-MsgGUID: 5npnQnX8RaSLvwr6IWOQkg== X-IronPort-AV: E=McAfee;i="6700,10204,11362"; a="52181286" X-IronPort-AV: E=Sophos;i="6.13,331,1732608000"; d="scan'208";a="52181286" Received: from orviesa005.jf.intel.com ([10.64.159.145]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Mar 2025 23:14:51 -0800 X-CSE-ConnectionGUID: S2D8/YmYQQ2PczFOYQEwsA== X-CSE-MsgGUID: Yhh3KhAkQ6eKwbc7mpIbMQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,224,1728975600"; d="scan'208";a="123497855" Received: from inaky-mobl1.amr.corp.intel.com (HELO dwillia2-xfh.jf.intel.com) ([10.125.109.47]) by orviesa005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Mar 2025 23:14:51 -0800 Subject: [PATCH v2 06/11] samples/devsec: Introduce a PCI device-security bus + endpoint sample From: Dan Williams To: linux-coco@lists.linux.dev Cc: Bjorn Helgaas , Lukas Wunner , Samuel Ortiz , Alexey Kardashevskiy , Xu Yilun , gregkh@linuxfoundation.org, linux-pci@vger.kernel.org, aik@amd.com, lukas@wunner.de Date: Mon, 03 Mar 2025 23:14:50 -0800 Message-ID: <174107249038.1288555.12362100502109498455.stgit@dwillia2-xfh.jf.intel.com> In-Reply-To: <174107245357.1288555.10863541957822891561.stgit@dwillia2-xfh.jf.intel.com> References: <174107245357.1288555.10863541957822891561.stgit@dwillia2-xfh.jf.intel.com> User-Agent: StGit/0.18-3-g996c Precedence: bulk X-Mailing-List: linux-pci@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Establish just enough emulated PCI infrastructure to register a sample TSM (platform security manager) driver and have it discover an IDE + TEE (link encryption + device-interface security protocol (TDISP)) capable device. Use the existing a CONFIG_PCI_BRIDGE_EMUL to emulate an IDE capable root port, and open code the emulation of an endpoint device via simulated configuration cycle responses. The devsec_tsm driver responds to the PCI core TSM operations as if it successfully exercised the given interface security protocol message. The devsec_bus and devsec_tsm drivers can be loaded in either order to reflect cases like SEV-TIO where the TSM is PCI-device firmware, and cases like TDX Connect where the TSM is a software agent running on the host CPU. Follow-on patches add common code for TSM managed IDE establishment. For now, just successfully complete setup and teardown of the DSM (device security manager) context as a building block for management of TDI (trusted device interface) instances. # modprobe devsec_bus devsec_bus devsec_bus: PCI host bridge to bus 10000:00 pci_bus 10000:00: root bus resource [bus 00-01] pci_bus 10000:00: root bus resource [mem 0xf000000000-0xffffffffff 64bit] pci 10000:00:00.0: [8086:7075] type 01 class 0x060400 PCIe Root Port pci 10000:00:00.0: PCI bridge to [bus 00] pci 10000:00:00.0: bridge window [io 0x0000-0x0fff] pci 10000:00:00.0: bridge window [mem 0x00000000-0x000fffff] pci 10000:00:00.0: bridge window [mem 0x00000000-0x000fffff 64bit pref] pci 10000:00:00.0: bridge configuration invalid ([bus 00-00]), reconfiguring pci 10000:01:00.0: [8086:ffff] type 00 class 0x000000 PCIe Endpoint pci 10000:01:00.0: BAR 0 [mem 0xf000000000-0xf0001fffff 64bit pref] pci_doe_abort: pci 10000:01:00.0: DOE: [100] Issuing Abort pci_doe_cache_protocols: pci 10000:01:00.0: DOE: [100] Found protocol 0 vid: 1 prot: 1 pci 10000:01:00.0: disabling ASPM on pre-1.1 PCIe device. You can enable it with 'pcie_aspm=force' pci 10000:00:00.0: PCI bridge to [bus 01] pci_bus 10000:01: busn_res: [bus 01] end is updated to 01 # modprobe devsec_tsm devsec_tsm_pci_probe: pci 10000:01:00.0: devsec: tsm enabled __pci_tsm_init: pci 10000:01:00.0: TSM: Device security capabilities detected ( ide tee ), TSM attach Cc: Bjorn Helgaas Cc: Lukas Wunner Cc: Samuel Ortiz Cc: Alexey Kardashevskiy Cc: Xu Yilun Signed-off-by: Dan Williams --- MAINTAINERS | 1 samples/Kconfig | 16 + samples/Makefile | 1 samples/devsec/Makefile | 10 + samples/devsec/bus.c | 692 +++++++++++++++++++++++++++++++++++++++++++++++ samples/devsec/common.c | 26 ++ samples/devsec/devsec.h | 7 samples/devsec/tsm.c | 121 ++++++++ 8 files changed, 874 insertions(+) create mode 100644 samples/devsec/Makefile create mode 100644 samples/devsec/bus.c create mode 100644 samples/devsec/common.c create mode 100644 samples/devsec/devsec.h create mode 100644 samples/devsec/tsm.c diff --git a/MAINTAINERS b/MAINTAINERS index 80a5951bfa04..69d74790f2ff 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -24121,6 +24121,7 @@ F: drivers/virt/coco/guest/ F: drivers/virt/coco/host/ F: include/linux/pci-tsm.h F: include/linux/tsm.h +F: samples/devsec/ TRUSTED SERVICES TEE DRIVER M: Balint Dobszay diff --git a/samples/Kconfig b/samples/Kconfig index 820e00b2ed68..6bd64fc54ac1 100644 --- a/samples/Kconfig +++ b/samples/Kconfig @@ -304,6 +304,22 @@ source "samples/rust/Kconfig" source "samples/damon/Kconfig" +config SAMPLE_DEVSEC + tristate "Build a sample TEE Security Manager with an emulated PCI endpoint" + depends on PCI + depends on VIRT_DRIVERS + depends on X86 # TODO: PCI_DOMAINS_GENERIC support + select PCI_BRIDGE_EMUL + select PCI_TSM + select TSM + help + Build a sample platform TEE Security Manager (TSM) driver with a + corresponding emulated PCIe topology. The resulting sample modules, + devsec_bus and devsec_tsm, exercise device-security enumeration, PCI + subsystem use ABIs, device security flows. For example, exercise IDE + (link encryption) establishment and TDISP state transitions via a + Device Security Manager (DSM). + endif # SAMPLES config HAVE_SAMPLE_FTRACE_DIRECT diff --git a/samples/Makefile b/samples/Makefile index f24cd0d72dd0..e4d8820e878f 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -42,3 +42,4 @@ obj-$(CONFIG_SAMPLE_FPROBE) += fprobe/ obj-$(CONFIG_SAMPLES_RUST) += rust/ obj-$(CONFIG_SAMPLE_DAMON_WSSE) += damon/ obj-$(CONFIG_SAMPLE_DAMON_PRCL) += damon/ +obj-y += devsec/ diff --git a/samples/devsec/Makefile b/samples/devsec/Makefile new file mode 100644 index 000000000000..c8cb5c0cceb8 --- /dev/null +++ b/samples/devsec/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_SAMPLE_DEVSEC) += devsec_common.o +devsec_common-y := common.o + +obj-$(CONFIG_SAMPLE_DEVSEC) += devsec_bus.o +devsec_bus-y := bus.o + +obj-$(CONFIG_SAMPLE_DEVSEC) += devsec_tsm.o +devsec_tsm-y := tsm.o diff --git a/samples/devsec/bus.c b/samples/devsec/bus.c new file mode 100644 index 000000000000..69117db10897 --- /dev/null +++ b/samples/devsec/bus.c @@ -0,0 +1,692 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright(c) 2024 Intel Corporation. All rights reserved. + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../drivers/pci/pci-bridge-emul.h" +#include "devsec.h" + +#define NR_DEVSEC_BUSES 1 +#define NR_DEVSEC_ROOT_PORTS 1 +#define NR_PORT_STREAMS 1 +#define NR_ADDR_ASSOC 1 +#define NR_DEVSEC_DEVS 1 + +struct devsec { + struct pci_sysdata sysdata; + struct gen_pool *iomem_pool; + struct resource resource[2]; + struct pci_bus *bus; + struct device *dev; + struct devsec_port { + union { + struct devsec_ide { + u32 cap; + u32 ctl; + struct devsec_stream { + u32 cap; + u32 ctl; + u32 status; + u32 rid1; + u32 rid2; + struct devsec_addr_assoc { + u32 assoc1; + u32 assoc2; + u32 assoc3; + } assoc[NR_ADDR_ASSOC]; + } stream[NR_PORT_STREAMS]; + } ide __packed; + char ide_regs[sizeof(struct devsec_ide)]; + }; + struct pci_bridge_emul bridge; + } *devsec_ports[NR_DEVSEC_ROOT_PORTS]; + struct devsec_dev { + struct devsec *devsec; + struct range mmio_range; + u8 __cfg[SZ_4K]; + struct devsec_dev_doe { + int cap; + u32 req[SZ_4K / sizeof(u32)]; + u32 rsp[SZ_4K / sizeof(u32)]; + int write, read, read_ttl; + } doe; + u16 ide_pos; + union { + struct devsec_ide ide __packed; + char ide_regs[sizeof(struct devsec_ide)]; + }; + } *devsec_devs[NR_DEVSEC_DEVS]; +}; + +#define devsec_base(x) ((void __force __iomem *) &(x)->__cfg[0]) + +static struct devsec *bus_to_devsec(struct pci_bus *bus) +{ + return container_of(bus->sysdata, struct devsec, sysdata); +} + +static int devsec_dev_config_read(struct devsec *devsec, struct pci_bus *bus, + unsigned int devfn, int pos, int size, + u32 *val) +{ + struct devsec_dev *devsec_dev; + struct devsec_dev_doe *doe; + void __iomem *base; + + if (PCI_FUNC(devfn) != 0 || + PCI_SLOT(devfn) >= ARRAY_SIZE(devsec->devsec_devs)) + return PCIBIOS_DEVICE_NOT_FOUND; + + devsec_dev = devsec->devsec_devs[PCI_SLOT(devfn)]; + base = devsec_base(devsec_dev); + doe = &devsec_dev->doe; + + if (pos == doe->cap + PCI_DOE_READ) { + if (doe->read_ttl > 0) { + *val = doe->rsp[doe->read]; + dev_dbg(&bus->dev, "devfn: %#x doe read[%d]\n", devfn, + doe->read); + } else { + *val = 0; + dev_dbg(&bus->dev, "devfn: %#x doe no data\n", devfn); + } + return PCIBIOS_SUCCESSFUL; + } else if (pos == doe->cap + PCI_DOE_STATUS) { + if (doe->read_ttl > 0) { + *val = PCI_DOE_STATUS_DATA_OBJECT_READY; + dev_dbg(&bus->dev, "devfn: %#x object ready\n", devfn); + } else if (doe->read_ttl < 0) { + *val = PCI_DOE_STATUS_ERROR; + dev_dbg(&bus->dev, "devfn: %#x error\n", devfn); + } else { + *val = 0; + dev_dbg(&bus->dev, "devfn: %#x idle\n", devfn); + } + return PCIBIOS_SUCCESSFUL; + } else if (pos >= devsec_dev->ide_pos && + pos < devsec_dev->ide_pos + sizeof(struct devsec_ide)) { + *val = *(u32 *) &devsec_dev->ide_regs[pos - devsec_dev->ide_pos]; + return PCIBIOS_SUCCESSFUL; + } + + switch (size) { + case 1: + *val = readb(base + pos); + break; + case 2: + *val = readw(base + pos); + break; + case 4: + *val = readl(base + pos); + break; + default: + PCI_SET_ERROR_RESPONSE(val); + return PCIBIOS_BAD_REGISTER_NUMBER; + } + return PCIBIOS_SUCCESSFUL; +} + +static int devsec_port_config_read(struct devsec *devsec, unsigned int devfn, + int pos, int size, u32 *val) +{ + struct devsec_port *devsec_port; + + if (PCI_FUNC(devfn) != 0 || + PCI_SLOT(devfn) >= ARRAY_SIZE(devsec->devsec_ports)) + return PCIBIOS_DEVICE_NOT_FOUND; + + devsec_port = devsec->devsec_ports[PCI_SLOT(devfn)]; + return pci_bridge_emul_conf_read(&devsec_port->bridge, pos, size, val); +} + +static int devsec_pci_read(struct pci_bus *bus, unsigned int devfn, int pos, + int size, u32 *val) +{ + struct devsec *devsec = bus_to_devsec(bus); + + dev_vdbg(&bus->dev, "devfn: %#x pos: %#x size: %d\n", devfn, pos, size); + + if (bus == devsec->bus) + return devsec_port_config_read(devsec, devfn, pos, size, val); + else if (bus->parent == devsec->bus) + return devsec_dev_config_read(devsec, bus, devfn, pos, size, + val); + + return PCIBIOS_DEVICE_NOT_FOUND; +} + +#ifndef PCI_DOE_PROTOCOL_DISCOVERY +#define PCI_DOE_PROTOCOL_DISCOVERY 0 +#define PCI_DOE_FEATURE_CMA 1 +#endif + +/* just indicate support for CMA */ +static void doe_process(struct devsec_dev_doe *doe) +{ + u8 type; + u16 vid; + + vid = FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_VID, doe->req[0]); + type = FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_TYPE, doe->req[0]); + + if (vid != PCI_VENDOR_ID_PCI_SIG) { + doe->read_ttl = -1; + return; + } + + if (type != PCI_DOE_PROTOCOL_DISCOVERY) { + doe->read_ttl = -1; + return; + } + + doe->rsp[0] = doe->req[0]; + doe->rsp[1] = FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH, 3); + doe->read_ttl = 3; + doe->rsp[2] = FIELD_PREP(PCI_DOE_DATA_OBJECT_DISC_RSP_3_VID, + PCI_VENDOR_ID_PCI_SIG) | + FIELD_PREP(PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL, + PCI_DOE_FEATURE_CMA) | + FIELD_PREP(PCI_DOE_DATA_OBJECT_DISC_RSP_3_NEXT_INDEX, 0); +} + +static int devsec_dev_config_write(struct devsec *devsec, struct pci_bus *bus, + unsigned int devfn, int pos, int size, + u32 val) +{ + struct devsec_dev *devsec_dev; + struct devsec_dev_doe *doe; + void __iomem *base; + + dev_vdbg(&bus->dev, "devfn: %#x pos: %#x size: %d\n", devfn, pos, size); + + if (PCI_FUNC(devfn) != 0 || + PCI_SLOT(devfn) >= ARRAY_SIZE(devsec->devsec_devs)) + return PCIBIOS_DEVICE_NOT_FOUND; + + devsec_dev = devsec->devsec_devs[PCI_SLOT(devfn)]; + base = devsec_base(devsec_dev); + doe = &devsec_dev->doe; + + if (pos >= PCI_BASE_ADDRESS_0 && pos <= PCI_BASE_ADDRESS_5) { + if (size != 4) + return PCIBIOS_BAD_REGISTER_NUMBER; + /* only one 64-bit mmio bar emulated for now */ + if (pos == PCI_BASE_ADDRESS_0) + val &= ~lower_32_bits(range_len(&devsec_dev->mmio_range) - 1); + else if (pos == PCI_BASE_ADDRESS_1) + val &= ~upper_32_bits(range_len(&devsec_dev->mmio_range) - 1); + else + val = 0; + } else if (pos == PCI_ROM_ADDRESS) { + val = 0; + } else if (pos == doe->cap + PCI_DOE_CTRL) { + if (val & PCI_DOE_CTRL_GO) { + dev_dbg(&bus->dev, "devfn: %#x doe go\n", devfn); + doe_process(doe); + } + if (val & PCI_DOE_CTRL_ABORT) { + dev_dbg(&bus->dev, "devfn: %#x doe abort\n", devfn); + doe->write = 0; + doe->read = 0; + doe->read_ttl = 0; + } + return PCIBIOS_SUCCESSFUL; + } else if (pos == doe->cap + PCI_DOE_WRITE) { + if (doe->write < ARRAY_SIZE(doe->req)) + doe->req[doe->write++] = val; + dev_dbg(&bus->dev, "devfn: %#x doe write[%d]\n", devfn, + doe->write - 1); + return PCIBIOS_SUCCESSFUL; + } else if (pos == doe->cap + PCI_DOE_READ) { + if (doe->read_ttl > 0) { + doe->read_ttl--; + doe->read++; + dev_dbg(&bus->dev, "devfn: %#x doe ack[%d]\n", devfn, + doe->read - 1); + } + return PCIBIOS_SUCCESSFUL; + } + + switch (size) { + case 1: + writeb(val, base + pos); + break; + case 2: + writew(val, base + pos); + break; + case 4: + writel(val, base + pos); + break; + default: + return PCIBIOS_BAD_REGISTER_NUMBER; + } + return PCIBIOS_SUCCESSFUL; +} + +static int devsec_port_config_write(struct devsec *devsec, struct pci_bus *bus, + unsigned int devfn, int pos, int size, + u32 val) +{ + struct devsec_port *devsec_port; + + dev_vdbg(&bus->dev, "devfn: %#x pos: %#x size: %d\n", devfn, pos, size); + + if (PCI_FUNC(devfn) != 0 || + PCI_SLOT(devfn) >= ARRAY_SIZE(devsec->devsec_ports)) + return PCIBIOS_DEVICE_NOT_FOUND; + + devsec_port = devsec->devsec_ports[PCI_SLOT(devfn)]; + return pci_bridge_emul_conf_write(&devsec_port->bridge, pos, size, val); +} + +static int devsec_pci_write(struct pci_bus *bus, unsigned int devfn, int pos, + int size, u32 val) +{ + struct devsec *devsec = bus_to_devsec(bus); + + dev_vdbg(&bus->dev, "devfn: %#x pos: %#x size: %d\n", devfn, pos, size); + + if (bus == devsec->bus) + return devsec_port_config_write(devsec, bus, devfn, pos, size, + val); + else if (bus->parent == devsec->bus) + return devsec_dev_config_write(devsec, bus, devfn, pos, size, + val); + return PCIBIOS_DEVICE_NOT_FOUND; +} + +static struct pci_ops devsec_ops = { + .read = devsec_pci_read, + .write = devsec_pci_write, +}; + +/* borrowed from vmd_find_free_domain() */ +static int find_free_domain(void) +{ + int domain = 0xffff; + struct pci_bus *bus = NULL; + + while ((bus = pci_find_next_bus(bus)) != NULL) + domain = max_t(int, domain, pci_domain_nr(bus)); + return domain + 1; +} + +static void destroy_bus(void *data) +{ + struct devsec *devsec = data; + + pci_stop_root_bus(devsec->bus); + pci_remove_root_bus(devsec->bus); +} + +static u32 build_ext_cap_header(u32 id, u32 ver, u32 next) +{ + return FIELD_PREP(GENMASK(15, 0), id) | + FIELD_PREP(GENMASK(19, 16), ver) | + FIELD_PREP(GENMASK(31, 20), next); +} + +static void init_ide(struct devsec_ide *ide) +{ + ide->cap = PCI_IDE_CAP_SELECTIVE | PCI_IDE_CAP_IDE_KM | + PCI_IDE_CAP_TEE_LIMITED | + FIELD_PREP(PCI_IDE_CAP_SEL_NUM_MASK, NR_PORT_STREAMS - 1); + + for (int i = 0; i < NR_PORT_STREAMS; i++) + ide->stream[i].cap = + FIELD_PREP(PCI_IDE_SEL_CAP_ASSOC_NUM_MASK, NR_ADDR_ASSOC); +} + +static void init_dev_cfg(struct devsec_dev *devsec_dev) +{ + void __iomem *base = devsec_base(devsec_dev), *cap_base; + int pos, next; + + /* BAR space */ + writew(0x8086, base + PCI_VENDOR_ID); + writew(0xffff, base + PCI_DEVICE_ID); + writel(lower_32_bits(devsec_dev->mmio_range.start) | + PCI_BASE_ADDRESS_MEM_TYPE_64 | + PCI_BASE_ADDRESS_MEM_PREFETCH, + base + PCI_BASE_ADDRESS_0); + writel(upper_32_bits(devsec_dev->mmio_range.start), + base + PCI_BASE_ADDRESS_1); + + /* Capability init */ + writeb(PCI_HEADER_TYPE_NORMAL, base + PCI_HEADER_TYPE); + writew(PCI_STATUS_CAP_LIST, base + PCI_STATUS); + pos = 0x40; + writew(pos, base + PCI_CAPABILITY_LIST); + + /* PCI-E Capability */ + cap_base = base + pos; + writeb(PCI_CAP_ID_EXP, cap_base); + writew(PCI_EXP_TYPE_ENDPOINT, cap_base + PCI_EXP_FLAGS); + writew(PCI_EXP_LNKSTA_CLS_2_5GB | PCI_EXP_LNKSTA_NLW_X1, cap_base + PCI_EXP_LNKSTA); + writel(PCI_EXP_DEVCAP_FLR | PCI_EXP_DEVCAP_TEE, cap_base + PCI_EXP_DEVCAP); + + /* DOE Extended Capability */ + pos = PCI_CFG_SPACE_SIZE; + next = pos + PCI_DOE_CAP_SIZEOF; + cap_base = base + pos; + devsec_dev->doe.cap = pos; + writel(build_ext_cap_header(PCI_EXT_CAP_ID_DOE, 2, next), cap_base); + + /* IDE Extended Capability */ + pos = next; + cap_base = base + pos; + writel(build_ext_cap_header(PCI_EXT_CAP_ID_IDE, 1, 0), cap_base); + devsec_dev->ide_pos = pos + 4; + init_ide(&devsec_dev->ide); +} + +#define MMIO_SIZE SZ_2M + +static void destroy_devsec_dev(void *data) +{ + struct devsec_dev *devsec_dev = data; + struct devsec *devsec = devsec_dev->devsec; + + gen_pool_free(devsec->iomem_pool, devsec_dev->mmio_range.start, + range_len(&devsec_dev->mmio_range)); + kfree(devsec_dev); +} + +static struct devsec_dev *devsec_dev_alloc(struct devsec *devsec) +{ + struct devsec_dev *devsec_dev __free(kfree) = + kzalloc(sizeof(*devsec_dev), GFP_KERNEL); + struct genpool_data_align data = { + .align = MMIO_SIZE, + }; + u64 phys; + + if (!devsec_dev) + return ERR_PTR(-ENOMEM); + + phys = gen_pool_alloc_algo(devsec->iomem_pool, MMIO_SIZE, + gen_pool_first_fit_align, &data); + if (!phys) + return ERR_PTR(-ENOMEM); + + *devsec_dev = (struct devsec_dev) { + .mmio_range = { + .start = phys, + .end = phys + MMIO_SIZE - 1, + }, + .devsec = devsec, + }; + init_dev_cfg(devsec_dev); + + return_ptr(devsec_dev); +} + +static int alloc_devs(struct devsec *devsec) +{ + struct device *dev = devsec->dev; + + for (int i = 0; i < ARRAY_SIZE(devsec->devsec_devs); i++) { + struct devsec_dev *devsec_dev = devsec_dev_alloc(devsec); + int rc; + + if (IS_ERR(devsec_dev)) + return PTR_ERR(devsec_dev); + rc = devm_add_action_or_reset(dev, destroy_devsec_dev, + devsec_dev); + if (rc) + return rc; + devsec->devsec_devs[i] = devsec_dev; + } + + return 0; +} + +static pci_bridge_emul_read_status_t +devsec_bridge_read_base(struct pci_bridge_emul *bridge, int pos, u32 *val) +{ + return PCI_BRIDGE_EMUL_NOT_HANDLED; +} + +static pci_bridge_emul_read_status_t +devsec_bridge_read_pcie(struct pci_bridge_emul *bridge, int pos, u32 *val) +{ + return PCI_BRIDGE_EMUL_NOT_HANDLED; +} + +static pci_bridge_emul_read_status_t +devsec_bridge_read_ext(struct pci_bridge_emul *bridge, int pos, u32 *val) +{ + struct devsec_port *devsec_port = bridge->data; + + /* only one extended capability, IDE... */ + if (pos == 0) { + *val = build_ext_cap_header(PCI_EXT_CAP_ID_IDE, 1, 0); + return PCI_BRIDGE_EMUL_HANDLED; + } + + if (pos < 4) + return PCI_BRIDGE_EMUL_NOT_HANDLED; + + pos -= 4; + if (pos < sizeof(struct devsec_ide)) { + *val = *(u32 *)(&devsec_port->ide_regs[pos]); + return PCI_BRIDGE_EMUL_HANDLED; + } + + return PCI_BRIDGE_EMUL_NOT_HANDLED; +} + +static void devsec_bridge_write_base(struct pci_bridge_emul *bridge, int pos, + u32 old, u32 new, u32 mask) +{ +} + +static void devsec_bridge_write_pcie(struct pci_bridge_emul *bridge, int pos, + u32 old, u32 new, u32 mask) +{ +} + +static void devsec_bridge_write_ext(struct pci_bridge_emul *bridge, int pos, + u32 old, u32 new, u32 mask) +{ + struct devsec_port *devsec_port = bridge->data; + + if (pos < sizeof(struct devsec_ide)) + *(u32 *)(&devsec_port->ide_regs[pos]) = new; +} + +static const struct pci_bridge_emul_ops devsec_bridge_ops = { + .read_base = devsec_bridge_read_base, + .write_base = devsec_bridge_write_base, + .read_pcie = devsec_bridge_read_pcie, + .write_pcie = devsec_bridge_write_pcie, + .read_ext = devsec_bridge_read_ext, + .write_ext = devsec_bridge_write_ext, +}; + +static int init_port(struct devsec_port *devsec_port) +{ + struct pci_bridge_emul *bridge = &devsec_port->bridge; + + *bridge = (struct pci_bridge_emul) { + .conf = { + .vendor = cpu_to_le16(0x8086), + .device = cpu_to_le16(0x7075), + .class_revision = cpu_to_le32(0x1), + .pref_mem_base = cpu_to_le16(PCI_PREF_RANGE_TYPE_64), + .pref_mem_limit = cpu_to_le16(PCI_PREF_RANGE_TYPE_64), + }, + .pcie_conf = { + .devcap = cpu_to_le16(PCI_EXP_DEVCAP_FLR), + .lnksta = cpu_to_le16(PCI_EXP_LNKSTA_CLS_2_5GB), + }, + .subsystem_vendor_id = cpu_to_le16(0x8086), + .has_pcie = true, + .data = devsec_port, + .ops = &devsec_bridge_ops, + }; + + init_ide(&devsec_port->ide); + + return pci_bridge_emul_init(bridge, 0); +} + +static void destroy_port(void *data) +{ + struct devsec_port *devsec_port = data; + + pci_bridge_emul_cleanup(&devsec_port->bridge); + kfree(devsec_port); +} + +static struct devsec_port *devsec_port_alloc(void) +{ + int rc; + + struct devsec_port *devsec_port __free(kfree) = + kzalloc(sizeof(*devsec_port), GFP_KERNEL); + + if (!devsec_port) + return ERR_PTR(-ENOMEM); + + rc = init_port(devsec_port); + if (rc) + return ERR_PTR(rc); + + return_ptr(devsec_port); +} + +static int alloc_ports(struct devsec *devsec) +{ + struct device *dev = devsec->dev; + + for (int i = 0; i < ARRAY_SIZE(devsec->devsec_ports); i++) { + struct devsec_port *devsec_port = devsec_port_alloc(); + int rc; + + if (IS_ERR(devsec_port)) + return PTR_ERR(devsec_port); + rc = devm_add_action_or_reset(dev, destroy_port, devsec_port); + if (rc) + return rc; + devsec->devsec_ports[i] = devsec_port; + } + + return 0; +} + +static int __init devsec_bus_probe(struct platform_device *pdev) +{ + int rc; + LIST_HEAD(resources); + struct devsec *devsec; + struct pci_sysdata *sd; + u64 mmio_size = SZ_64G; + struct device *dev = &pdev->dev; + u64 mmio_start = iomem_resource.end + 1 - SZ_64G; + + devsec = devm_kzalloc(dev, sizeof(*devsec), GFP_KERNEL); + if (!devsec) + return -ENOMEM; + + devsec->dev = dev; + devsec->iomem_pool = devm_gen_pool_create(dev, ilog2(SZ_2M), + NUMA_NO_NODE, "devsec iomem"); + if (!devsec->iomem_pool) + return -ENOMEM; + + rc = gen_pool_add(devsec->iomem_pool, mmio_start, mmio_size, + NUMA_NO_NODE); + if (rc) + return rc; + + rc = alloc_ports(devsec); + if (rc) + return rc; + + rc = alloc_devs(devsec); + if (rc) + return rc; + + devsec->resource[0] = (struct resource) { + .name = "DEVSEC BUSES", + .start = 0, + .end = NR_DEVSEC_BUSES + NR_DEVSEC_ROOT_PORTS - 1, + .flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED, + }; + pci_add_resource(&resources, &devsec->resource[0]); + + devsec->resource[1] = (struct resource) { + .name = "DEVSEC MMIO", + .start = mmio_start, + .end = mmio_start + mmio_size - 1, + .flags = IORESOURCE_MEM | IORESOURCE_MEM_64, + }; + pci_add_resource(&resources, &devsec->resource[1]); + + sd = &devsec->sysdata; + devsec_sysdata = sd; + sd->domain = find_free_domain(); + if (sd->domain < 0) + return sd->domain; + + + devsec->bus = pci_create_root_bus(dev, 0, &devsec_ops, + &devsec->sysdata, &resources); + if (!devsec->bus) { + pci_free_resource_list(&resources); + return -ENOMEM; + } + + rc = devm_add_action_or_reset(dev, destroy_bus, devsec); + if (rc) + return rc; + + pci_scan_child_bus(devsec->bus); + + return 0; +} + +static struct platform_driver devsec_bus_driver = { + .driver = { + .name = "devsec_bus", + }, +}; + +static struct platform_device *devsec_bus; + +static int __init devsec_bus_init(void) +{ + struct platform_device_info devsec_bus_info = { + .name = "devsec_bus", + .id = -1, + }; + int rc; + + devsec_bus = platform_device_register_full(&devsec_bus_info); + if (IS_ERR(devsec_bus)) + return PTR_ERR(devsec_bus); + + rc = platform_driver_probe(&devsec_bus_driver, devsec_bus_probe); + if (rc) + platform_device_unregister(devsec_bus); + return 0; +} +module_init(devsec_bus_init); + +static void __exit devsec_bus_exit(void) +{ + platform_driver_unregister(&devsec_bus_driver); + platform_device_unregister(devsec_bus); +} +module_exit(devsec_bus_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Device Security Sample Infrastructure: TDISP Device Emulation"); diff --git a/samples/devsec/common.c b/samples/devsec/common.c new file mode 100644 index 000000000000..9b6f4022f241 --- /dev/null +++ b/samples/devsec/common.c @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright(c) 2024 Intel Corporation. All rights reserved. + +#include +#include + +/* + * devsec_bus and devsec_tsm need a common location for this data to + * avoid depending on each other. Enables load order testing + */ +struct pci_sysdata *devsec_sysdata; +EXPORT_SYMBOL_GPL(devsec_sysdata); + +static int __init common_init(void) +{ + return 0; +} +module_init(common_init); + +static void __exit common_exit(void) +{ +} +module_exit(common_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Device Security Sample Infrastructure: Shared data"); diff --git a/samples/devsec/devsec.h b/samples/devsec/devsec.h new file mode 100644 index 000000000000..794a9898ee2d --- /dev/null +++ b/samples/devsec/devsec.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +// Copyright(c) 2024 Intel Corporation. All rights reserved. + +#ifndef __DEVSEC_H__ +#define __DEVSEC_H__ +extern struct pci_sysdata *devsec_sysdata; +#endif /* __DEVSEC_H__ */ diff --git a/samples/devsec/tsm.c b/samples/devsec/tsm.c new file mode 100644 index 000000000000..7698df2b4e29 --- /dev/null +++ b/samples/devsec/tsm.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2024 Intel Corporation. All rights reserved. */ + +#define dev_fmt(fmt) "devsec: " fmt +#include +#include +#include +#include +#include +#include "devsec.h" + +struct devsec_tsm_pf0 { + struct pci_tsm_pf0 pci; +#define NR_TSM_STREAMS 4 +}; + +static struct devsec_tsm_pf0 *to_devsec_tsm(struct pci_tsm *tsm) +{ + return container_of(tsm, struct devsec_tsm_pf0, pci.tsm); +} + +static struct pci_tsm *devsec_tsm_pci_probe(struct pci_dev *pdev) +{ + int rc; + + if (pdev->sysdata != devsec_sysdata) + return NULL; + + if (!is_pci_tsm_pf0(pdev)) + return NULL; + + struct devsec_tsm_pf0 *devsec_tsm __free(kfree) = + kzalloc(sizeof(*devsec_tsm), GFP_KERNEL); + if (!devsec_tsm) + return NULL; + + rc = pci_tsm_pf0_initialize(pdev, &devsec_tsm->pci); + if (rc) + return NULL; + + pci_dbg(pdev, "tsm enabled\n"); + return &no_free_ptr(devsec_tsm)->pci.tsm; +} + +static void devsec_tsm_pci_remove(struct pci_tsm *tsm) +{ + struct devsec_tsm_pf0 *devsec_tsm = to_devsec_tsm(tsm); + + pci_dbg(tsm->pdev, "tsm disabled\n"); + kfree(devsec_tsm); +} + +static int devsec_tsm_connect(struct pci_dev *pdev) +{ + return -ENXIO; +} + +static void devsec_tsm_disconnect(struct pci_dev *pdev) +{ +} + +static const struct pci_tsm_ops devsec_pci_ops = { + .probe = devsec_tsm_pci_probe, + .remove = devsec_tsm_pci_remove, + .connect = devsec_tsm_connect, + .disconnect = devsec_tsm_disconnect, +}; + +static void devsec_tsm_remove(void *tsm_core) +{ + tsm_unregister(tsm_core); +} + +static int devsec_tsm_probe(struct platform_device *pdev) +{ + struct tsm_core_dev *tsm_core; + + tsm_core = tsm_register(&pdev->dev, NULL, &devsec_pci_ops); + if (IS_ERR(tsm_core)) + return PTR_ERR(tsm_core); + + return devm_add_action_or_reset(&pdev->dev, devsec_tsm_remove, + tsm_core); +} + +static struct platform_driver devsec_tsm_driver = { + .driver = { + .name = "devsec_tsm", + }, +}; + +static struct platform_device *devsec_tsm; + +static int __init devsec_tsm_init(void) +{ + struct platform_device_info devsec_tsm_info = { + .name = "devsec_tsm", + .id = -1, + }; + int rc; + + devsec_tsm = platform_device_register_full(&devsec_tsm_info); + if (IS_ERR(devsec_tsm)) + return PTR_ERR(devsec_tsm); + + rc = platform_driver_probe(&devsec_tsm_driver, devsec_tsm_probe); + if (rc) + platform_device_unregister(devsec_tsm); + return rc; +} +module_init(devsec_tsm_init); + +static void __exit devsec_tsm_exit(void) +{ + platform_driver_unregister(&devsec_tsm_driver); + platform_device_unregister(devsec_tsm); +} +module_exit(devsec_tsm_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Device Security Sample Infrastructure: Platform TSM Driver"); From patchwork Tue Mar 4 07:14:56 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 14000066 X-Patchwork-Delegate: bhelgaas@google.com Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EA8061FC0E2 for ; Tue, 4 Mar 2025 07:14:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741072498; cv=none; b=hWDA+CRb/aH6ledCaoodYpTfhTWq4FfOfOcJ3ktUiHIOE8WmtWquUgz0y4zQtWwmgtX/bso5MEi7/FDOx/5WZGFgXJMotvSyLySTr6JRbUTeTKAv8I1vMWXtnjTbDWH6uH8V0bxmBxmnhO+ENN6M9gzZnTOj1NvtehqIWMoiDjM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741072498; c=relaxed/simple; bh=K21ZMUeqHQJEqIpyEZ902m5uTUEnhJujNLhx99cgqu4=; h=Subject:From:To:Cc:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=oVjE5VOqNO4SOR3YXdtOhR5wi+bJUVy1QSVesPN0bxpf/sNe6hIAHS/zaFmdZ6spdoeTuQ8/lC6PsmbUOBwbMfmcrEiiyvhZ0yf79N+1jBHoF4jJYx1ltmAZJUHXSehkSVBwc30+3rQuLFwNM3OaGjk5LHVQh5biIDw2P4pQczA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=IwVuT3Cm; arc=none smtp.client-ip=198.175.65.11 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="IwVuT3Cm" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1741072497; x=1772608497; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=K21ZMUeqHQJEqIpyEZ902m5uTUEnhJujNLhx99cgqu4=; b=IwVuT3CmeGz7DASx/6QxjsEWvNaXN23jKwTD0ALhZabYJKt6Nv10WeDH vJXTGjoDqKvuWdZmGy0zY6LRZDF8PT/Pz6PUhcvVsy/lDSSbLia1V3gaY pGrPNMtw6jXgRxgiMM7V6nYadd+x+L8aZeNjOXINHQQp8NH25t2ML4371 q0NAlsh+NgBqooPorSoswwZQ6LdTOnKG+quyCVl5n57qYDBhicgwBbtFN fNFjGdVkYkyaKDlnLab5KCgUhcrU/0FaERpZi5DZpPPyAYJKMEqsIrmbw 08WwlLa0w6WNjFH5JtDXZFUeTMRTjStt5TcP5rssqS0H+A4TuRAvqcduY A==; X-CSE-ConnectionGUID: TxjNZZaAQ52+mfQlhgQANA== X-CSE-MsgGUID: eLq3m/gMRXOvl1bsVZ1Z5Q== X-IronPort-AV: E=McAfee;i="6700,10204,11362"; a="52181296" X-IronPort-AV: E=Sophos;i="6.13,331,1732608000"; d="scan'208";a="52181296" Received: from orviesa005.jf.intel.com ([10.64.159.145]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Mar 2025 23:14:57 -0800 X-CSE-ConnectionGUID: sJwTBZYNRfWoCPD9pim8Qg== X-CSE-MsgGUID: eknjPY+STvqOSTaThaAM8g== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,224,1728975600"; d="scan'208";a="123497867" Received: from inaky-mobl1.amr.corp.intel.com (HELO dwillia2-xfh.jf.intel.com) ([10.125.109.47]) by orviesa005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Mar 2025 23:14:57 -0800 Subject: [PATCH v2 07/11] PCI: Add PCIe Device 3 Extended Capability enumeration From: Dan Williams To: linux-coco@lists.linux.dev Cc: Lukas Wunner , Ilpo =?utf-8?b?SsOkcnZpbmVu?= , Bjorn Helgaas , Samuel Ortiz , Alexey Kardashevskiy , Xu Yilun , gregkh@linuxfoundation.org, linux-pci@vger.kernel.org, aik@amd.com, lukas@wunner.de Date: Mon, 03 Mar 2025 23:14:56 -0800 Message-ID: <174107249599.1288555.1378423423476361939.stgit@dwillia2-xfh.jf.intel.com> In-Reply-To: <174107245357.1288555.10863541957822891561.stgit@dwillia2-xfh.jf.intel.com> References: <174107245357.1288555.10863541957822891561.stgit@dwillia2-xfh.jf.intel.com> User-Agent: StGit/0.18-3-g996c Precedence: bulk X-Mailing-List: linux-pci@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 PCIe 6.2 Section 7.7.9 Device 3 Extended Capability Structure, enumerates new link capabilities and status added for Gen 6 devices. One of the link details enumerated in that register block is the "Segment Captured" status in the Device Status 3 register. That status is relevant for enabling IDE (Integrity & Data Encryption) whereby Selective IDE streams can be limited to a given Requester ID range within a given segment. If a device has captured its Segment value then it knows that PCIe Flit Mode is enabled via all links in the path that a configuration write traversed. IDE establishment requires that "Segment Base" in IDE RID Association Register 2 (PCIe 6.2 Section 7.9.26.5.4.2) be programmed if the RID association mechanism is in effect. When / if IDE + Flit Mode capable devices arrive, the PCI core needs to setup the segment base when using the RID association facility, but no known deployments today depend on this. Cc: Lukas Wunner Cc: Ilpo Järvinen Cc: Bjorn Helgaas Cc: Samuel Ortiz Cc: Alexey Kardashevskiy Cc: Xu Yilun Signed-off-by: Dan Williams --- drivers/pci/probe.c | 12 ++++++++++++ include/linux/pci.h | 1 + include/uapi/linux/pci_regs.h | 7 +++++++ 3 files changed, 20 insertions(+) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 1d1d7de642da..e1c915629864 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2251,6 +2251,17 @@ int pci_configure_extended_tags(struct pci_dev *dev, void *ign) return 0; } +static void pci_dev3_init(struct pci_dev *pdev) +{ + u16 cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DEV3); + u32 val = 0; + + if (!cap) + return; + pci_read_config_dword(pdev, cap + PCI_DEV3_STA, &val); + pdev->fm_enabled = !!(val & PCI_DEV3_STA_SEGMENT); +} + /** * pcie_relaxed_ordering_enabled - Probe for PCIe relaxed ordering enable * @dev: PCI device to query @@ -2565,6 +2576,7 @@ static void pci_init_capabilities(struct pci_dev *dev) pci_rcec_init(dev); /* Root Complex Event Collector */ pci_doe_init(dev); /* Data Object Exchange */ pci_tph_init(dev); /* TLP Processing Hints */ + pci_dev3_init(dev); /* Device 3 capabilities */ pci_ide_init(dev); /* Link Integrity and Data Encryption */ pci_tsm_init(dev); /* TEE Security Manager connection */ diff --git a/include/linux/pci.h b/include/linux/pci.h index 57cfa0e3f2bd..b5ea9869c2b1 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -443,6 +443,7 @@ struct pci_dev { unsigned int pasid_enabled:1; /* Process Address Space ID */ unsigned int pri_enabled:1; /* Page Request Interface */ unsigned int tph_enabled:1; /* TLP Processing Hints */ + unsigned int fm_enabled:1; /* Flit Mode (segment captured) */ unsigned int is_managed:1; /* Managed via devres */ unsigned int is_msi_managed:1; /* MSI release via devres installed */ unsigned int needs_freset:1; /* Requires fundamental reset */ diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index 713588a29813..d17579592027 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -750,6 +750,7 @@ #define PCI_EXT_CAP_ID_NPEM 0x29 /* Native PCIe Enclosure Management */ #define PCI_EXT_CAP_ID_PL_32GT 0x2A /* Physical Layer 32.0 GT/s */ #define PCI_EXT_CAP_ID_DOE 0x2E /* Data Object Exchange */ +#define PCI_EXT_CAP_ID_DEV3 0x2F /* Device 3 Capability/Control/Status */ #define PCI_EXT_CAP_ID_IDE 0x30 /* Integrity and Data Encryption */ #define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_IDE @@ -1210,6 +1211,12 @@ #define PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL 0x00ff0000 #define PCI_DOE_DATA_OBJECT_DISC_RSP_3_NEXT_INDEX 0xff000000 +/* Device 3 Extended Capability */ +#define PCI_DEV3_CAP 0x4 /* Device 3 Capabilities Register */ +#define PCI_DEV3_CTL 0x8 /* Device 3 Control Register */ +#define PCI_DEV3_STA 0xc /* Device 3 Status Register */ +#define PCI_DEV3_STA_SEGMENT 0x8 /* Segment Captured (end-to-end flit-mode detected) */ + /* Compute Express Link (CXL r3.1, sec 8.1.5) */ #define PCI_DVSEC_CXL_PORT 3 #define PCI_DVSEC_CXL_PORT_CTL 0x0c From patchwork Tue Mar 4 07:15:01 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 14000067 X-Patchwork-Delegate: bhelgaas@google.com Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2FC011FC108 for ; Tue, 4 Mar 2025 07:15:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741072504; cv=none; b=TGrJwAPqmeyRKcS9nahUxRE+c3FZY0aCsYeE6zwkm5I40VidNrXrmqlBXFT2tezTI3/EOoW2SEH9q4PatCXlhkM5R0V9e71Ha91pUOyKBA2dqx2gJiqokZUMyBawABtvxapnI8m0YBzlyhDjmwdR4pbkBHH8EIVnLUMYqc34tmE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741072504; c=relaxed/simple; bh=wfo5YtxAOoefKL0h0XL0lXmyyRPplks6LoiTo9wyUU4=; h=Subject:From:To:Cc:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=DTG5GzTZ6VZOURFn7OAA8KzBPUUbXbuuJD+MMAuXiwxIqhunyioG0e6qUVMn6TZUvQy2ItobwtH2+GN5p8ej3ZRtUm1+sp7ZwMWXHdXIwwsYzVa9Ofr3vezqTr4vnNotk8bnTlhvjj/Nh1wBjLE+hHWz5rj2EjZ8hb/VSWEfD3k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=larLKxNc; arc=none smtp.client-ip=198.175.65.11 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="larLKxNc" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1741072502; x=1772608502; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=wfo5YtxAOoefKL0h0XL0lXmyyRPplks6LoiTo9wyUU4=; b=larLKxNc1ts8wR5HUHU/8KtfHHpI5pzudVFgNmbH3XoPz34GB8WunZkk Ic1KSmylCpk8xHzNEkm5zv11pKr20SH/miVHcQU/3TEYUHO8922b5wDqA /1RQBE0cGWxKXT9gNVk090c1jmlrNInVWitgfUtszogoMgOwMA3j0vYJq 96NkSgfz7K9S7PvPpSc6T78ytrUuOH3Ry9s7OWn9K/3xgCV4spNuAw7Nq MbaqYIIfJcTU1OZjnvpx/SCPeCqxg9D3ApxME2sxbbopqkE6C8RcJ54Ap nvamJtBM3kxBm79IvrK/PTpI2R3RkUWdBhTp2MryU8jur1hio5f+uQp6P g==; X-CSE-ConnectionGUID: 6T0h0jPCT4K9Oxy+yspP0Q== X-CSE-MsgGUID: ei8e9r5BQoeJ/ROKRfuwmg== X-IronPort-AV: E=McAfee;i="6700,10204,11362"; a="52181314" X-IronPort-AV: E=Sophos;i="6.13,331,1732608000"; d="scan'208";a="52181314" Received: from orviesa005.jf.intel.com ([10.64.159.145]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Mar 2025 23:15:02 -0800 X-CSE-ConnectionGUID: OO1yF9JZRlySBn01uzVZtw== X-CSE-MsgGUID: TOWKmBIuSuOepeANDpLYSw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,224,1728975600"; d="scan'208";a="123497877" Received: from inaky-mobl1.amr.corp.intel.com (HELO dwillia2-xfh.jf.intel.com) ([10.125.109.47]) by orviesa005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Mar 2025 23:15:02 -0800 Subject: [PATCH v2 08/11] PCI/IDE: Add IDE establishment helpers From: Dan Williams To: linux-coco@lists.linux.dev Cc: Bjorn Helgaas , Lukas Wunner , Samuel Ortiz , Alexey Kardashevskiy , Xu Yilun , gregkh@linuxfoundation.org, linux-pci@vger.kernel.org, aik@amd.com, lukas@wunner.de Date: Mon, 03 Mar 2025 23:15:01 -0800 Message-ID: <174107250147.1288555.16948528371146013276.stgit@dwillia2-xfh.jf.intel.com> In-Reply-To: <174107245357.1288555.10863541957822891561.stgit@dwillia2-xfh.jf.intel.com> References: <174107245357.1288555.10863541957822891561.stgit@dwillia2-xfh.jf.intel.com> User-Agent: StGit/0.18-3-g996c Precedence: bulk X-Mailing-List: linux-pci@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 There are two components to establishing an encrypted link, provisioning the stream in Partner Port config-space, and programming the keys into the link layer via IDE_KM (IDE Key Management). This new library, drivers/pci/ide.c, enables the former. IDE_KM, via a TSM low-level driver, is saved for later. With the platform TSM implementations of SEV-TIO and TDX Connect in mind this library abstracts small differences in those implementations. For example, TDX Connect handles Root Port register setup while SEV-TIO expects System Software to update the Root Port registers. This is the rationale for fine-grained 'setup' + 'enable' verbs. The other design detail for TSM-coordinated IDE establishment is that the TSM may manage allocation of Stream IDs, this is why the Stream ID value is passed in to pci_ide_stream_setup(). The flow is: pci_ide_stream_alloc() Allocate a Selective IDE Stream Register Block in each Partner Port (Endpoint + Root Port), and reserve a host bridge / platform stream slot. Gather Partner Port specific stream settings like Requester ID. pci_ide_stream_register() Publish the stream in sysfs after allocating a Stream ID. In the TSM case the TSM allocates the Stream ID for the Partner Port pair. pci_ide_stream_setup() Program the stream settings to a Partner Port. Caller is responsible for optionally calling this for the Root Port as well if the TSM implementation requires it. pci_ide_stream_enable() Run the stream after IDE_KM. In support of system administrators auditing where platform, Root Port, and Endpoint IDE stream resources are being spent, the allocated stream is reflected as a symlink from the host bridge to the endpoint with the name: stream%d.%d.%d:%s Where the tuple of integers reflects the allocated platform, Root Port, and Endpoint stream index (Selective IDE Stream Register Block) values, and the %s is the endpoint device name. Thanks to Wu Hao for a draft implementation of this infrastructure. Cc: Bjorn Helgaas Cc: Lukas Wunner Cc: Samuel Ortiz Co-developed-by: Alexey Kardashevskiy Signed-off-by: Alexey Kardashevskiy Co-developed-by: Xu Yilun Signed-off-by: Xu Yilun Signed-off-by: Dan Williams --- .../ABI/testing/sysfs-devices-pci-host-bridge | 32 ++ drivers/pci/ide.c | 352 ++++++++++++++++++++ include/linux/pci-ide.h | 60 +++ include/linux/pci.h | 6 4 files changed, 450 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-devices-pci-host-bridge create mode 100644 include/linux/pci-ide.h diff --git a/Documentation/ABI/testing/sysfs-devices-pci-host-bridge b/Documentation/ABI/testing/sysfs-devices-pci-host-bridge new file mode 100644 index 000000000000..51dc9eed9353 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices-pci-host-bridge @@ -0,0 +1,32 @@ +What: /sys/devices/pciDDDD:BB + /sys/devices/.../pciDDDD:BB +Date: December, 2024 +Contact: linux-pci@vger.kernel.org +Description: + A PCI host bridge device parents a PCI bus device topology. PCI + controllers may also parent host bridges. The DDDD:BB format + conveys the PCI domain number and root bus number of the + host bridge. + +What: pciDDDD:BB/firmware_node +Date: December, 2024 +Contact: linux-pci@vger.kernel.org +Description: + (RO) Symlink to the platform firmware device object "companion" + of the host bridge. For example, an ACPI device with an _HID of + PNP0A08 (/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00). + +What: pciDDDD:BB/streamH.R.E:DDDD:BB:DD:F +Date: December, 2024 +Contact: linux-pci@vger.kernel.org +Description: + (RO) When a platform has established a secure connection, PCIe + IDE, between two Partner Ports, this symlink appears. The + primary function is to account the stream slot / resources + consumed in each of the (H)ost bridge, (R)oot Port and + (E)ndpoint that will be freed when invoking the tsm/disconnect + flow. The link points to the endpoint PCI device at domain:DDDD + bus:BB device:DD function:F. Where R and E represent the + assigned Selective IDE Stream Register Block in the Root Port + and Endpoint, and H represents a platform specific pool of + stream resources shared by the Root Ports in a host bridge. diff --git a/drivers/pci/ide.c b/drivers/pci/ide.c index 193380763812..b2091f6260e6 100644 --- a/drivers/pci/ide.c +++ b/drivers/pci/ide.c @@ -5,6 +5,8 @@ #define dev_fmt(fmt) "PCI/IDE: " fmt #include +#include +#include #include #include "pci.h" @@ -85,5 +87,355 @@ void pci_ide_init(struct pci_dev *pdev) pdev->ide_cap = ide_cap; pdev->nr_link_ide = nr_link_ide; + pdev->nr_sel_ide = nr_streams; pdev->nr_ide_mem = nr_ide_mem; } + +struct stream_index { + unsigned long *map; + u8 max, stream_index; +}; + +static void free_stream_index(struct stream_index *stream) +{ + clear_bit_unlock(stream->stream_index, stream->map); +} + +DEFINE_FREE(free_stream, struct stream_index *, if (_T) free_stream_index(_T)) +static struct stream_index *alloc_stream_index(unsigned long *map, u8 max, + struct stream_index *stream) +{ + do { + u8 stream_index = find_first_zero_bit(map, max); + + if (stream_index == max) + return NULL; + if (!test_and_set_bit_lock(stream_index, map)) { + *stream = (struct stream_index) { + .map = map, + .max = max, + .stream_index = stream_index, + }; + return stream; + } + /* collided with another stream acquisition */ + } while (1); +} + +/** + * pci_ide_stream_alloc() - Reserve stream indices and probe for settings + * @pdev: IDE capable PCIe Endpoint Physical Function + * + * Retrieve the Requester ID range of @pdev for programming its Root + * Port IDE RID Association registers, and conversely retrieve the + * Requester ID of the Root Port for programming @pdev's IDE RID + * Association registers. + * + * Allocate a Selective IDE Stream Register Block instance per port. + * + * Allocate a platform stream resource from the associated host bridge. + * Retrieve stream association parameters for Requester ID range and + * address range restrictions for the stream. + */ +struct pci_ide *pci_ide_stream_alloc(struct pci_dev *pdev) +{ + /* EP, RP, + HB Stream allocation */ + struct stream_index __stream[PCI_IDE_PARTNER_MAX + 1]; + struct pci_host_bridge *hb; + struct pci_dev *rp; + int num_vf, rid_end; + + if (!pci_is_pcie(pdev)) + return NULL; + + if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT) + return NULL; + + if (!pdev->ide_cap) + return NULL; + + struct pci_ide *ide __free(kfree) = kzalloc(sizeof(*ide), GFP_KERNEL); + if (!ide) + return NULL; + + hb = pci_find_host_bridge(pdev->bus); + struct stream_index *hb_stream __free(free_stream) = alloc_stream_index( + hb->ide_stream_map, hb->nr_ide_streams, &__stream[PCI_IDE_HB]); + if (!hb_stream) + return NULL; + + rp = pcie_find_root_port(pdev); + struct stream_index *rp_stream __free(free_stream) = alloc_stream_index( + rp->ide_stream_map, rp->nr_sel_ide, &__stream[PCI_IDE_RP]); + if (!rp_stream) + return NULL; + + struct stream_index *ep_stream __free(free_stream) = alloc_stream_index( + pdev->ide_stream_map, pdev->nr_sel_ide, &__stream[PCI_IDE_EP]); + if (!ep_stream) + return NULL; + + /* for SR-IOV case, cover all VFs */ + num_vf = pci_num_vf(pdev); + if (num_vf) + rid_end = PCI_DEVID(pci_iov_virtfn_bus(pdev, num_vf), + pci_iov_virtfn_devfn(pdev, num_vf)); + else + rid_end = pci_dev_id(pdev); + + *ide = (struct pci_ide) { + .pdev = pdev, + .partner = { + [PCI_IDE_EP] = { + .rid_start = pci_dev_id(rp), + .rid_end = pci_dev_id(rp), + .stream_index = no_free_ptr(ep_stream)->stream_index, + }, + [PCI_IDE_RP] = { + .rid_start = pci_dev_id(pdev), + .rid_end = rid_end, + .stream_index = no_free_ptr(rp_stream)->stream_index, + }, + }, + .host_bridge_stream = no_free_ptr(hb_stream)->stream_index, + .stream_id = -1, + }; + + return_ptr(ide); +} +EXPORT_SYMBOL_GPL(pci_ide_stream_alloc); + +/** + * pci_ide_stream_free() - unwind pci_ide_stream_alloc() + * @ide: idle IDE settings descriptor + * + * Free all of the stream index (register block) allocations acquired by + * pci_ide_stream_alloc(). The stream represented by @ide is assumed to + * be unregistered and not instantiated in any device. + */ +void pci_ide_stream_free(struct pci_ide *ide) +{ + struct pci_dev *pdev = ide->pdev; + struct pci_dev *rp = pcie_find_root_port(pdev); + struct pci_host_bridge *hb = pci_find_host_bridge(pdev->bus); + + clear_bit_unlock(ide->partner[PCI_IDE_EP].stream_index, + pdev->ide_stream_map); + clear_bit_unlock(ide->partner[PCI_IDE_RP].stream_index, + rp->ide_stream_map); + clear_bit_unlock(ide->host_bridge_stream, hb->ide_stream_map); + kfree(ide); +} +EXPORT_SYMBOL_GPL(pci_ide_stream_free); + +/** + * pci_ide_stream_register() - Prepare to activate an IDE Stream + * @ide: IDE settings descriptor + * + * After a Stream ID has been acquired for @ide, record the presence of + * the stream in sysfs. The expectation is that @ide is immutable while + * registered. + */ +int pci_ide_stream_register(struct pci_ide *ide) +{ + struct pci_dev *pdev = ide->pdev; + struct pci_host_bridge *hb = pci_find_host_bridge(pdev->bus); + u8 ep_stream, rp_stream; + int rc; + + if (ide->stream_id < 0 || ide->stream_id > U8_MAX) { + pci_err(pdev, "Setup fail: Invalid Stream ID: %d\n", ide->stream_id); + return -ENXIO; + } + + ep_stream = ide->partner[PCI_IDE_EP].stream_index; + rp_stream = ide->partner[PCI_IDE_RP].stream_index; + const char *name __free(kfree) = kasprintf( + GFP_KERNEL, "stream%d.%d.%d:%s", ide->host_bridge_stream, + rp_stream, ep_stream, dev_name(&pdev->dev)); + if (!name) + return -ENOMEM; + + rc = sysfs_create_link(&hb->dev.kobj, &pdev->dev.kobj, name); + if (rc) + return rc; + + ide->name = no_free_ptr(name); + + return 0; +} +EXPORT_SYMBOL_GPL(pci_ide_stream_register); + +/** + * pci_ide_stream_unregister() - unwind pci_ide_stream_register() + * @ide: idle IDE settings descriptor + * + * In preparation for freeing @ide, remove sysfs enumeration for the + * stream. + */ +void pci_ide_stream_unregister(struct pci_ide *ide) +{ + struct pci_dev *pdev = ide->pdev; + struct pci_host_bridge *hb = pci_find_host_bridge(pdev->bus); + + sysfs_remove_link(&hb->dev.kobj, ide->name); + kfree(ide->name); +} +EXPORT_SYMBOL_GPL(pci_ide_stream_unregister); + +#define SEL_ADDR1_LOWER_MASK GENMASK(31, 20) +#define SEL_ADDR_UPPER_MASK GENMASK_ULL(63, 32) +#define PREP_PCI_IDE_SEL_ADDR1(base, limit) \ + (FIELD_PREP(PCI_IDE_SEL_ADDR_1_VALID, 1) | \ + FIELD_PREP(PCI_IDE_SEL_ADDR_1_BASE_LOW_MASK, \ + FIELD_GET(SEL_ADDR1_LOWER_MASK, (base))) | \ + FIELD_PREP(PCI_IDE_SEL_ADDR_1_LIMIT_LOW_MASK, \ + FIELD_GET(SEL_ADDR1_LOWER_MASK, (limit)))) + +#define PREP_PCI_IDE_SEL_RID_2(base, domain) \ + (FIELD_PREP(PCI_IDE_SEL_RID_2_VALID, 1) | \ + FIELD_PREP(PCI_IDE_SEL_RID_2_BASE_MASK, (base)) | \ + FIELD_PREP(PCI_IDE_SEL_RID_2_SEG_MASK, (domain))) + +static int ide_domain(struct pci_dev *pdev) +{ + if (pdev->fm_enabled) + return pci_domain_nr(pdev->bus); + return 0; +} + +static struct pci_ide_partner *to_settings(struct pci_dev *pdev, struct pci_ide *ide) +{ + if (!pci_is_pcie(pdev)) { + pci_warn_once(pdev, "not a PCIe device\n"); + return NULL; + } + + switch (pci_pcie_type(pdev)) { + case PCI_EXP_TYPE_ENDPOINT: + if (pdev != ide->pdev) { + pci_warn_once(pdev, "setup expected Endpoint: %s\n", pci_name(ide->pdev)); + return NULL; + } + return &ide->partner[PCI_IDE_EP]; + case PCI_EXP_TYPE_ROOT_PORT: + struct pci_dev *rp = pcie_find_root_port(ide->pdev); + + if (pdev != pcie_find_root_port(ide->pdev)) { + pci_warn_once(pdev, "setup expected Root Port: %s\n", + pci_name(rp)); + return NULL; + } + return &ide->partner[PCI_IDE_RP]; + default: + pci_warn_once(pdev, "invalid device type\n"); + return NULL; + } +} + +/** + * pci_ide_stream_setup() - program settings to Selective IDE Stream registers + * @pdev: PCIe device object for either a Root Port or Endpoint Partner Port + * @ide: registered IDE settings descriptor + * + * When @pdev is a PCI_EXP_TYPE_ENDPOINT then the PCI_IDE_EP partner + * settings are written to @pdev's Selective IDE Stream register block, + * and when @pdev is a PCI_EXP_TYPE_ROOT_PORT, the PCI_IDE_RP settings + * are selected. + */ +void pci_ide_stream_setup(struct pci_dev *pdev, struct pci_ide *ide) +{ + struct pci_ide_partner *settings = to_settings(pdev, ide); + int pos; + u32 val; + + if (!settings) + return; + + pos = sel_ide_offset(pdev->nr_link_ide, settings->stream_index, + pdev->nr_ide_mem); + + val = FIELD_PREP(PCI_IDE_SEL_RID_1_LIMIT_MASK, settings->rid_end); + pci_write_config_dword(pdev, pos + PCI_IDE_SEL_RID_1, val); + + val = PREP_PCI_IDE_SEL_RID_2(settings->rid_start, ide_domain(pdev)); + pci_write_config_dword(pdev, pos + PCI_IDE_SEL_RID_2, val); +} +EXPORT_SYMBOL_GPL(pci_ide_stream_setup); + +/** + * pci_ide_stream_teardown() - disable the stream and clear all settings + * @pdev: PCIe device object for either a Root Port or Endpoint Partner Port + * @ide: registered IDE settings descriptor + * + * For stream destruction, zero all registers that may have been written + * by pci_ide_stream_setup(). Consider pci_ide_stream_disable() to leave + * settings in place while temporarily disabling the stream. + */ +void pci_ide_stream_teardown(struct pci_dev *pdev, struct pci_ide *ide) +{ + struct pci_ide_partner *settings = to_settings(pdev, ide); + int pos; + + if (!settings) + return; + + pos = sel_ide_offset(pdev->nr_link_ide, settings->stream_index, + pdev->nr_ide_mem); + + pci_write_config_dword(pdev, pos + PCI_IDE_SEL_CTL, 0); + pci_write_config_dword(pdev, pos + PCI_IDE_SEL_RID_2, 0); + pci_write_config_dword(pdev, pos + PCI_IDE_SEL_RID_1, 0); +} +EXPORT_SYMBOL_GPL(pci_ide_stream_teardown); + +/** + * pci_ide_stream_enable() - after setup, enable the stream + * @pdev: PCIe device object for either a Root Port or Endpoint Partner Port + * @ide: registered and setup IDE settings descriptor + * + * Activate the stream by writing to the Selective IDE Stream Control Register. + */ +void pci_ide_stream_enable(struct pci_dev *pdev, struct pci_ide *ide) +{ + struct pci_ide_partner *settings = to_settings(pdev, ide); + int pos; + u32 val; + + if (!settings) + return; + + pos = sel_ide_offset(pdev->nr_link_ide, settings->stream_index, + pdev->nr_ide_mem); + + val = FIELD_PREP(PCI_IDE_SEL_CTL_ID_MASK, ide->stream_id) | + FIELD_PREP(PCI_IDE_SEL_CTL_DEFAULT, 1) | + FIELD_PREP(PCI_IDE_SEL_CTL_CFG_EN, pdev->ide_cfg) | + FIELD_PREP(PCI_IDE_SEL_CTL_TEE_LIMITED, pdev->ide_tee_limit) | + FIELD_PREP(PCI_IDE_SEL_CTL_EN, 1); + pci_write_config_dword(pdev, pos + PCI_IDE_SEL_CTL, val); +} +EXPORT_SYMBOL_GPL(pci_ide_stream_enable); + +/** + * pci_ide_stream_disable() - disable the given stream + * @pdev: PCIe device object for either a Root Port or Endpoint Partner Port + * @ide: registered and setup IDE settings descriptor + * + * Clear the Selective IDE Stream Control Register, but leave all other + * registers untouched. + */ +void pci_ide_stream_disable(struct pci_dev *pdev, struct pci_ide *ide) +{ + struct pci_ide_partner *settings = to_settings(pdev, ide); + int pos; + + if (!settings) + return; + + pos = sel_ide_offset(pdev->nr_link_ide, settings->stream_index, + pdev->nr_ide_mem); + + pci_write_config_dword(pdev, pos + PCI_IDE_SEL_CTL, 0); +} +EXPORT_SYMBOL_GPL(pci_ide_stream_disable); diff --git a/include/linux/pci-ide.h b/include/linux/pci-ide.h new file mode 100644 index 000000000000..7a3f72915ee2 --- /dev/null +++ b/include/linux/pci-ide.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2024 Intel Corporation. All rights reserved. */ + +/* PCIe 6.2 section 6.33 Integrity & Data Encryption (IDE) */ + +#ifndef __PCI_IDE_H__ +#define __PCI_IDE_H__ + +#include + +enum pci_ide_partner_select { + PCI_IDE_EP, + PCI_IDE_RP, + PCI_IDE_PARTNER_MAX, + /* pci_ide_stream_alloc() uses this for stream index allocation */ + PCI_IDE_HB = PCI_IDE_PARTNER_MAX, +}; + +/** + * struct pci_ide_partner - Per port IDE Stream settings + * @rid_start: Partner Port Requester ID range start + * @rid_start: Partner Port Requester ID range end + * @stream_index: Selective IDE Stream Register Block selection + */ +struct pci_ide_partner { + u16 rid_start; + u16 rid_end; + u8 stream_index; +}; + +/** + * struct pci_ide - PCIe Selective IDE Stream descriptor + * @pdev: PCIe Endpoint for the stream + * @partner: settings for both partner ports in a stream + * @host_bridge_stream: track platform Stream index + * @stream_id: unique id (within Partner Port pairing) for the stream + * @name: name of the stream in sysfs + * + * Negative @stream_id values indicate "uninitialized" on the + * expectation that with TSM established IDE the TSM owns the stream_id + * allocation. + */ +struct pci_ide { + struct pci_dev *pdev; + struct pci_ide_partner partner[PCI_IDE_PARTNER_MAX]; + u8 host_bridge_stream; + int stream_id; + const char *name; +}; + +struct pci_ide *pci_ide_stream_alloc(struct pci_dev *pdev); +void pci_ide_stream_free(struct pci_ide *ide); +DEFINE_FREE(pci_ide_stream_free, struct pci_ide *, if (_T) pci_ide_stream_free(_T)) +int pci_ide_stream_register(struct pci_ide *ide); +void pci_ide_stream_unregister(struct pci_ide *ide); +void pci_ide_stream_setup(struct pci_dev *pdev, struct pci_ide *ide); +void pci_ide_stream_teardown(struct pci_dev *pdev, struct pci_ide *ide); +void pci_ide_stream_enable(struct pci_dev *pdev, struct pci_ide *ide); +void pci_ide_stream_disable(struct pci_dev *pdev, struct pci_ide *ide); +#endif /* __PCI_IDE_H__ */ diff --git a/include/linux/pci.h b/include/linux/pci.h index b5ea9869c2b1..0f9d6aece346 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -536,6 +536,8 @@ struct pci_dev { u16 ide_cap; /* Link Integrity & Data Encryption */ u8 nr_ide_mem; /* Address association resources for streams */ u8 nr_link_ide; /* Link Stream count (Selective Stream offset) */ + u8 nr_sel_ide; /* Selective Stream count (register block allocator) */ + DECLARE_BITMAP(ide_stream_map, CONFIG_PCI_IDE_STREAM_MAX); unsigned int ide_cfg:1; /* Config cycles over IDE */ unsigned int ide_tee_limit:1; /* Disallow T=0 traffic over IDE */ #endif @@ -603,6 +605,10 @@ struct pci_host_bridge { int domain_nr; struct list_head windows; /* resource_entry */ struct list_head dma_ranges; /* dma ranges resource list */ +#ifdef CONFIG_PCI_IDE + u8 nr_ide_streams; /* Track available vs in-use streams */ + DECLARE_BITMAP(ide_stream_map, CONFIG_PCI_IDE_STREAM_MAX); +#endif u8 (*swizzle_irq)(struct pci_dev *, u8 *); /* Platform IRQ swizzler */ int (*map_irq)(const struct pci_dev *, u8, u8); void (*release_fn)(struct pci_host_bridge *); From patchwork Tue Mar 4 07:15:07 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 14000068 X-Patchwork-Delegate: bhelgaas@google.com Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B98BE1FC0FC for ; Tue, 4 Mar 2025 07:15:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741072510; cv=none; b=oU8uW2rFUwZyn/yBp8xGTgwm0eC0Fq+zGJVOu9OSmPHGSDNKUMmEuMb3ds3rt1ExC+VW1Eg2gEMIyEGDmmdwPdOdzdFMdMHQaXqeg9a5/LGgk6/ITLlw0ITjd30kwWPPwb9iK+vQ9RqQlFmuzfuOqmzPkm23RGXbtBryNpifCmw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741072510; c=relaxed/simple; bh=AF0NZZENOUtnVb3FwXdmLDRQtK0N2zbBdKaxmxdgQMQ=; h=Subject:From:To:Cc:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Uh/s/WaLuLOjYsaqeyjhL0LqDCuvQ3r63vI3ra9tBkctWvj1+lheCKEB7DaK40A79PqWflcDShFIX1aL4e/c/ghLZftMXv1g1IUX88uLDwlEkOLH15BCJ8snBQad9i4aaTxAwxijgRSVWR2cURNow8wAkWb5xPctxpExWC979ug= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=J8/u6zZH; arc=none smtp.client-ip=198.175.65.11 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="J8/u6zZH" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1741072508; x=1772608508; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=AF0NZZENOUtnVb3FwXdmLDRQtK0N2zbBdKaxmxdgQMQ=; b=J8/u6zZH6lydKo+pNaWferbqIKOCbHiIYvImhB1kdi99bCnlov6Kcf7O hmCvHt6PeiMLTkuKrDX5Xe7zOD60o5QYRw8RbZDWEchVI4hbN98PDCwmv M34tjGgiZzUNrkI7WNdAhTBUwka+Nc6xqwhjt5b1DoeyON7cZsKs7BtO1 2QxEF8Kl0XQY8donQvL4f4L+TSkNAG09B2kiVG0exTD+rk1mtKGzMD1/q Z+NKqqU8C/LjWESYdNXtRc3Rl+qJmyjd6KrETaOtsEY3Yosi8iIgVJpto tUNntGi3LPFNMKLDQDl3cS0ZO0/jNEzt9ENldk7LlyI+Ul0VSe/Diblpy g==; X-CSE-ConnectionGUID: VZDKQ2hvQMmQOsZPv/xSCA== X-CSE-MsgGUID: PDyu3xeSSwmSRkpI2RYvDw== X-IronPort-AV: E=McAfee;i="6700,10204,11362"; a="52181333" X-IronPort-AV: E=Sophos;i="6.13,331,1732608000"; d="scan'208";a="52181333" Received: from orviesa005.jf.intel.com ([10.64.159.145]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Mar 2025 23:15:08 -0800 X-CSE-ConnectionGUID: 1WjI0byBSYm9ITe+ZINQ+g== X-CSE-MsgGUID: MP+rY8TBTDultKR4KETq+g== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,224,1728975600"; d="scan'208";a="123497898" Received: from inaky-mobl1.amr.corp.intel.com (HELO dwillia2-xfh.jf.intel.com) ([10.125.109.47]) by orviesa005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Mar 2025 23:15:08 -0800 Subject: [PATCH v2 09/11] PCI/IDE: Report available IDE streams From: Dan Williams To: linux-coco@lists.linux.dev Cc: Bjorn Helgaas , Lukas Wunner , Samuel Ortiz , Alexey Kardashevskiy , Xu Yilun , gregkh@linuxfoundation.org, linux-pci@vger.kernel.org, aik@amd.com, lukas@wunner.de Date: Mon, 03 Mar 2025 23:15:07 -0800 Message-ID: <174107250696.1288555.15924775074966673629.stgit@dwillia2-xfh.jf.intel.com> In-Reply-To: <174107245357.1288555.10863541957822891561.stgit@dwillia2-xfh.jf.intel.com> References: <174107245357.1288555.10863541957822891561.stgit@dwillia2-xfh.jf.intel.com> User-Agent: StGit/0.18-3-g996c Precedence: bulk X-Mailing-List: linux-pci@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The limited number of link-encryption (IDE) streams that a given set of host bridges supports is a platform specific detail. Provide pci_ide_init_nr_streams() as a generic facility for either platform TSM drivers, or PCI core native IDE, to report the number available streams. After invoking pci_ide_init_nr_streams() an "available_secure_streams" attribute appears in PCI host bridge sysfs to convey that count. Cc: Bjorn Helgaas Cc: Lukas Wunner Cc: Samuel Ortiz Cc: Alexey Kardashevskiy Cc: Xu Yilun Signed-off-by: Dan Williams --- .../ABI/testing/sysfs-devices-pci-host-bridge | 12 ++++ drivers/pci/ide.c | 58 ++++++++++++++++++++ drivers/pci/pci.h | 3 + drivers/pci/probe.c | 12 ++++ include/linux/pci.h | 8 +++ 5 files changed, 92 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-devices-pci-host-bridge b/Documentation/ABI/testing/sysfs-devices-pci-host-bridge index 51dc9eed9353..4624469e56d4 100644 --- a/Documentation/ABI/testing/sysfs-devices-pci-host-bridge +++ b/Documentation/ABI/testing/sysfs-devices-pci-host-bridge @@ -20,6 +20,7 @@ What: pciDDDD:BB/streamH.R.E:DDDD:BB:DD:F Date: December, 2024 Contact: linux-pci@vger.kernel.org Description: +<<<<<<< current (RO) When a platform has established a secure connection, PCIe IDE, between two Partner Ports, this symlink appears. The primary function is to account the stream slot / resources @@ -30,3 +31,14 @@ Description: assigned Selective IDE Stream Register Block in the Root Port and Endpoint, and H represents a platform specific pool of stream resources shared by the Root Ports in a host bridge. + +What: pciDDDD:BB/available_secure_streams +Date: December, 2024 +Contact: linux-pci@vger.kernel.org +Description: + (RO) When a host bridge has Root Ports that support PCIe IDE + (link encryption and integrity protection) there may be a + limited number of streams that can be used for establishing new + secure links. This attribute decrements upon secure link setup, + and increments upon secure link teardown. The in-use stream + count is determined by counting stream symlinks. diff --git a/drivers/pci/ide.c b/drivers/pci/ide.c index b2091f6260e6..0c72985e6a65 100644 --- a/drivers/pci/ide.c +++ b/drivers/pci/ide.c @@ -439,3 +439,61 @@ void pci_ide_stream_disable(struct pci_dev *pdev, struct pci_ide *ide) pci_write_config_dword(pdev, pos + PCI_IDE_SEL_CTL, 0); } EXPORT_SYMBOL_GPL(pci_ide_stream_disable); + +static ssize_t available_secure_streams_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct pci_host_bridge *hb = to_pci_host_bridge(dev); + int avail; + + if (hb->nr_ide_streams < 0) + return -ENXIO; + + avail = hb->nr_ide_streams - + bitmap_weight(hb->ide_stream_map, hb->nr_ide_streams); + return sysfs_emit(buf, "%d\n", avail); +} +static DEVICE_ATTR_RO(available_secure_streams); + +static struct attribute *pci_ide_attrs[] = { + &dev_attr_available_secure_streams.attr, + NULL, +}; + +static umode_t pci_ide_attr_visible(struct kobject *kobj, struct attribute *a, int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct pci_host_bridge *hb = to_pci_host_bridge(dev); + + if (a == &dev_attr_available_secure_streams.attr) + if (hb->nr_ide_streams < 0) + return 0; + + return a->mode; +} + +struct attribute_group pci_ide_attr_group = { + .attrs = pci_ide_attrs, + .is_visible = pci_ide_attr_visible, +}; + +/** + * pci_init_nr_ide_streams() - size the pool of IDE Stream resources + * @hb: host bridge boundary for the stream pool + * @nr: number of streams + * + * Enable IDE Stream establishment by setting the number of stream + * resources available at the host bridge. Platform init code must set + * this before the first pci_ide_stream_alloc() call. + * + * The "PCI_IDE" symbol namespace is required because this is typically + * a detail that is settled in early PCI init, i.e. only an expert or + * test module should consume this export. + */ +void pci_ide_init_nr_streams(struct pci_host_bridge *hb, int nr) +{ + hb->nr_ide_streams = nr; + sysfs_update_group(&hb->dev.kobj, &pci_ide_attr_group); +} +EXPORT_SYMBOL_NS_GPL(pci_ide_init_nr_streams, "PCI_IDE"); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index b38bdd91e742..6c050eb9a91b 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -458,8 +458,11 @@ static inline void pci_npem_remove(struct pci_dev *dev) { } #ifdef CONFIG_PCI_IDE void pci_ide_init(struct pci_dev *dev); +extern struct attribute_group pci_ide_attr_group; +#define PCI_IDE_ATTR_GROUP (&pci_ide_attr_group) #else static inline void pci_ide_init(struct pci_dev *dev) { } +#define PCI_IDE_ATTR_GROUP NULL #endif #ifdef CONFIG_PCI_TSM diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index e1c915629864..a383cc32c84b 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -633,6 +633,16 @@ static void pci_release_host_bridge_dev(struct device *dev) kfree(bridge); } +static const struct attribute_group *pci_host_bridge_groups[] = { + PCI_IDE_ATTR_GROUP, + NULL, +}; + +static const struct device_type pci_host_bridge_type = { + .groups = pci_host_bridge_groups, + .release = pci_release_host_bridge_dev, +}; + static void pci_init_host_bridge(struct pci_host_bridge *bridge) { INIT_LIST_HEAD(&bridge->windows); @@ -652,6 +662,7 @@ static void pci_init_host_bridge(struct pci_host_bridge *bridge) bridge->native_dpc = 1; bridge->domain_nr = PCI_DOMAIN_NR_NOT_SET; bridge->native_cxl_error = 1; + bridge->dev.type = &pci_host_bridge_type; device_initialize(&bridge->dev); } @@ -665,7 +676,6 @@ struct pci_host_bridge *pci_alloc_host_bridge(size_t priv) return NULL; pci_init_host_bridge(bridge); - bridge->dev.release = pci_release_host_bridge_dev; return bridge; } diff --git a/include/linux/pci.h b/include/linux/pci.h index 0f9d6aece346..c2f18f31f7a7 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -660,6 +660,14 @@ void pci_set_host_bridge_release(struct pci_host_bridge *bridge, void (*release_fn)(struct pci_host_bridge *), void *release_data); +#ifdef CONFIG_PCI_IDE +void pci_ide_init_nr_streams(struct pci_host_bridge *hb, int nr); +#else +static inline void pci_ide_init_nr_streams(struct pci_host_bridge *hb, int nr) +{ +} +#endif + int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge); #define PCI_REGION_FLAG_MASK 0x0fU /* These bits of resource flags tell us the PCI region flags */ From patchwork Tue Mar 4 07:15:12 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 14000069 X-Patchwork-Delegate: bhelgaas@google.com Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 07A2D1FC7E1 for ; Tue, 4 Mar 2025 07:15:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741072515; cv=none; b=GD6HtzKJTZlzCz85EoNcliaCN3lrNq6H9sui1sFaU5m0ze9TS4GKqwFLgrIyfi90TQBnSettDNcTYXZtCnKhGqiEX3l28DGuF0Q4HO1stT9q9FjA3Uavc5andbF0NbC5S0xaRTavmP7KAx2EA7p5mBN2ibDnNRwMQ67SdPy93rw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741072515; c=relaxed/simple; bh=0nYOb9rBvOvDZ52Sipawfg+Z04xq3rRSZfGlPmWMwLY=; h=Subject:From:To:Cc:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=cKwgyJwHIPpBdoEzhOz6H/N9o/A0pkt50aqtA0Z2OcFdOK81wNep7aigoTNPugQu6kvkTwbFrGmd4UwK9U9CkImc/u/ufj7HAEKx3DXngo8i+Q4AJuEAVwfxSJbpKRuJO8xSohSoX6gvabPWbJvk7Q1PRDhzs4fuBEIxx+mPLYI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=SxP1ebBC; arc=none smtp.client-ip=198.175.65.11 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="SxP1ebBC" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1741072513; x=1772608513; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=0nYOb9rBvOvDZ52Sipawfg+Z04xq3rRSZfGlPmWMwLY=; b=SxP1ebBCi1e4MvA+Bw6kSwdZiCUhW+b9pdr0XBFQei0ad8E5+ns6FQx4 VB1QwMWNMmoVr9vIBHTGuvr7Ygi/lH7gA1DWXw+VzycchX8rZtAFWYmvX IJsqH1vimL+icnMWE0Wx/NP9y3eJGRG7OLCwv2IP/Il9xE3Gx6wcxqySX qDIZJqmcgNpD69urVThl3UY/2+yTQxg3/ceCwFOu0LS/nOyWcguw/IYJb gf6R+wBB0MfDPlmwr+0Ylpqo0kTZUs0Ok3RdSF+OLCDzUKoV3kaV/2m8S 6chGlrdkAtzXft74UQKUvVOwGACJsMKtYs0fXcZfuk7JUDXjb9etVGfHE A==; X-CSE-ConnectionGUID: I2pdkfR9R5aK43eiSHZxMw== X-CSE-MsgGUID: Ur8+rEwcTNOmtAVTD9Jevg== X-IronPort-AV: E=McAfee;i="6700,10204,11362"; a="52181347" X-IronPort-AV: E=Sophos;i="6.13,331,1732608000"; d="scan'208";a="52181347" Received: from orviesa005.jf.intel.com ([10.64.159.145]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Mar 2025 23:15:13 -0800 X-CSE-ConnectionGUID: DDQclEn9SBeCcZ+we2Pk8g== X-CSE-MsgGUID: +YYI8haNTBO0MxMRunKzwA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,224,1728975600"; d="scan'208";a="123497947" Received: from inaky-mobl1.amr.corp.intel.com (HELO dwillia2-xfh.jf.intel.com) ([10.125.109.47]) by orviesa005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Mar 2025 23:15:13 -0800 Subject: [PATCH v2 10/11] PCI/TSM: Report active IDE streams From: Dan Williams To: linux-coco@lists.linux.dev Cc: aik@amd.com, gregkh@linuxfoundation.org, linux-pci@vger.kernel.org, aik@amd.com, lukas@wunner.de Date: Mon, 03 Mar 2025 23:15:12 -0800 Message-ID: <174107251246.1288555.2482012187220793117.stgit@dwillia2-xfh.jf.intel.com> In-Reply-To: <174107245357.1288555.10863541957822891561.stgit@dwillia2-xfh.jf.intel.com> References: <174107245357.1288555.10863541957822891561.stgit@dwillia2-xfh.jf.intel.com> User-Agent: StGit/0.18-3-g996c Precedence: bulk X-Mailing-List: linux-pci@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Given that the platform TSM owns IDE Stream ID allocation, report the active streams via the TSM class device. Establish a symlink from the class device to the PCI endpoint device consuming the stream, named by the Stream ID. Signed-off-by: Dan Williams --- Documentation/ABI/testing/sysfs-class-tsm | 10 ++++++++++ drivers/virt/coco/host/tsm-core.c | 17 +++++++++++++++++ include/linux/tsm.h | 4 ++++ 3 files changed, 31 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-tsm b/Documentation/ABI/testing/sysfs-class-tsm index 7503f04a9eb9..75ee2b9bc555 100644 --- a/Documentation/ABI/testing/sysfs-class-tsm +++ b/Documentation/ABI/testing/sysfs-class-tsm @@ -8,3 +8,13 @@ Description: signals when the PCI layer is able to support establishment of link encryption and other device-security features coordinated through the platform tsm. + +What: /sys/class/tsm/tsm0/streamN:DDDD:BB:DD:F +Date: December, 2024 +Contact: linux-pci@vger.kernel.org +Description: + (RO) When a host bridge has established a secure connection via + the platform TSM, symlink appears. The primary function of this + is have a system global review of TSM resource consumption + across host bridges. The link points to the endpoint PCI device + at domain:DDDD bus:BB device:DD function:F. diff --git a/drivers/virt/coco/host/tsm-core.c b/drivers/virt/coco/host/tsm-core.c index 51146f226a64..bd9e09b07412 100644 --- a/drivers/virt/coco/host/tsm-core.c +++ b/drivers/virt/coco/host/tsm-core.c @@ -2,13 +2,16 @@ /* Copyright(c) 2024 Intel Corporation. All rights reserved. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#define dev_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include #include #include +#include static DECLARE_RWSEM(tsm_core_rwsem); static struct class *tsm_class; @@ -99,6 +102,20 @@ void tsm_unregister(struct tsm_core_dev *core) } EXPORT_SYMBOL_GPL(tsm_unregister); +/* must be invoked between tsm_register / tsm_unregister */ +int tsm_ide_stream_register(struct pci_dev *pdev, struct pci_ide *ide) +{ + return sysfs_create_link(&tsm_core->dev.kobj, &pdev->dev.kobj, + ide->name); +} +EXPORT_SYMBOL_GPL(tsm_ide_stream_register); + +void tsm_ide_stream_unregister(struct pci_ide *ide) +{ + sysfs_remove_link(&tsm_core->dev.kobj, ide->name); +} +EXPORT_SYMBOL_GPL(tsm_ide_stream_unregister); + static void tsm_release(struct device *dev) { struct tsm_core_dev *core = container_of(dev, typeof(*core), dev); diff --git a/include/linux/tsm.h b/include/linux/tsm.h index 59d3848404e1..915c4c8b061b 100644 --- a/include/linux/tsm.h +++ b/include/linux/tsm.h @@ -116,4 +116,8 @@ struct tsm_core_dev *tsm_register(struct device *parent, const struct attribute_group **groups, const struct pci_tsm_ops *ops); void tsm_unregister(struct tsm_core_dev *tsm_core); +struct pci_dev; +struct pci_ide; +int tsm_ide_stream_register(struct pci_dev *pdev, struct pci_ide *ide); +void tsm_ide_stream_unregister(struct pci_ide *ide); #endif /* __TSM_H */ From patchwork Tue Mar 4 07:15:17 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 14000070 X-Patchwork-Delegate: bhelgaas@google.com Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7AE841D88B4 for ; Tue, 4 Mar 2025 07:15:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741072520; cv=none; b=ReH0oaIDZ9zyT8NARMLFMHtyZAKMn0KbFm7F/PGiPp0Acb0MMLOs0Zjyt7hU/Qwa6aR9Qt2Ak1nVcZl8cChbD5mYYuWddEFpUipvyohfFmgCk4Ncu0Mutz/vJQQaexz8yMFTCKwm8HXVDY8/DfU7jEYU+4eXD7QrcwKxY8dSrjo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741072520; c=relaxed/simple; bh=FXjZ31r+HctdlgoJ7qDKW2CKWvFsSSritfdTM7tD5Nk=; h=Subject:From:To:Cc:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=PrDIW6NHto3vGtYmrd1N8msshYg0zDrPfcgIK83GQSxYD+sgmMzZapbZaZ3Jzpayo4EymClUiyELQvmgwGmOdiQDYVj2QkM9YaA+FLFsoLb7LrI5z05hNlAuQ21C8/1zXctkzxQ/9lZbVpcQSCa2jw3Q/y0S4WVJ6pS0fXQsmeE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=i2LiSHOV; arc=none smtp.client-ip=198.175.65.11 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="i2LiSHOV" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1741072519; x=1772608519; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=FXjZ31r+HctdlgoJ7qDKW2CKWvFsSSritfdTM7tD5Nk=; b=i2LiSHOVAoXFhTKEZif8+fRWMqVKJt8QAMc/+yH8Qcx9ffJc4aKt7BEp lX8/tTHkpvcXobQieXBfXH/btmwD11edmT0oykiuKRHQ87ELfhjrP7Iki H50FH2YxcJagZNe1DXboCXDjZChYG+sam+3bnxfzGqJoUhtLxUW1FVrKs qpIbXXXlLhbTylgqhEbemfqEPdby3vsOtCK61Byfv4XJ53/Dl1dw9802c mVzaJpN7G71d84esVmgSkjCSEYQZOSG5VfpLo+uEFw19a2yWFexFgW8r3 KOu6yNkmBgDSy3vfy41azdjMizJwH0buZpeihk5vNjYst7vemKnE23nDr w==; X-CSE-ConnectionGUID: RhwGtJ2OSIuNTE3ATcdJYw== X-CSE-MsgGUID: 1AuolIM/TkGIJmjpKdu0lQ== X-IronPort-AV: E=McAfee;i="6700,10204,11362"; a="52181353" X-IronPort-AV: E=Sophos;i="6.13,331,1732608000"; d="scan'208";a="52181353" Received: from orviesa005.jf.intel.com ([10.64.159.145]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Mar 2025 23:15:19 -0800 X-CSE-ConnectionGUID: 86zNqVLhT0K5qN7cWXARXQ== X-CSE-MsgGUID: fhAaXa5DTLutFzWKIIBzTQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,224,1728975600"; d="scan'208";a="123497962" Received: from inaky-mobl1.amr.corp.intel.com (HELO dwillia2-xfh.jf.intel.com) ([10.125.109.47]) by orviesa005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Mar 2025 23:15:18 -0800 Subject: [PATCH v2 11/11] samples/devsec: Add sample IDE establishment From: Dan Williams To: linux-coco@lists.linux.dev Cc: Bjorn Helgaas , Lukas Wunner , Samuel Ortiz , Alexey Kardashevskiy , Xu Yilun , gregkh@linuxfoundation.org, linux-pci@vger.kernel.org, aik@amd.com, lukas@wunner.de Date: Mon, 03 Mar 2025 23:15:17 -0800 Message-ID: <174107251788.1288555.15627462362017774594.stgit@dwillia2-xfh.jf.intel.com> In-Reply-To: <174107245357.1288555.10863541957822891561.stgit@dwillia2-xfh.jf.intel.com> References: <174107245357.1288555.10863541957822891561.stgit@dwillia2-xfh.jf.intel.com> User-Agent: StGit/0.18-3-g996c Precedence: bulk X-Mailing-List: linux-pci@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Exercise common setup and teardown flows for a sample platform TSM driver that implements the TSM 'connect' and 'disconnect' flows. This is both a template for platform specific implementations and a simple integration test for the PCI core infrastructure + ABI. Cc: Bjorn Helgaas Cc: Lukas Wunner Cc: Samuel Ortiz Cc: Alexey Kardashevskiy Cc: Xu Yilun Signed-off-by: Dan Williams --- samples/devsec/bus.c | 6 ++++ samples/devsec/tsm.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/samples/devsec/bus.c b/samples/devsec/bus.c index 69117db10897..b78c04b21eb9 100644 --- a/samples/devsec/bus.c +++ b/samples/devsec/bus.c @@ -15,6 +15,7 @@ #define NR_DEVSEC_BUSES 1 #define NR_DEVSEC_ROOT_PORTS 1 +#define NR_PLATFORM_STREAMS 4 #define NR_PORT_STREAMS 1 #define NR_ADDR_ASSOC 1 #define NR_DEVSEC_DEVS 1 @@ -589,6 +590,7 @@ static int __init devsec_bus_probe(struct platform_device *pdev) struct devsec *devsec; struct pci_sysdata *sd; u64 mmio_size = SZ_64G; + struct pci_host_bridge *hb; struct device *dev = &pdev->dev; u64 mmio_start = iomem_resource.end + 1 - SZ_64G; @@ -649,6 +651,9 @@ static int __init devsec_bus_probe(struct platform_device *pdev) if (rc) return rc; + hb = pci_find_host_bridge(devsec->bus); + pci_ide_init_nr_streams(hb, NR_PLATFORM_STREAMS); + pci_scan_child_bus(devsec->bus); return 0; @@ -688,5 +693,6 @@ static void __exit devsec_bus_exit(void) } module_exit(devsec_bus_exit); +MODULE_IMPORT_NS("PCI_IDE"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Device Security Sample Infrastructure: TDISP Device Emulation"); diff --git a/samples/devsec/tsm.c b/samples/devsec/tsm.c index 7698df2b4e29..9c033662c1b4 100644 --- a/samples/devsec/tsm.c +++ b/samples/devsec/tsm.c @@ -4,6 +4,7 @@ #define dev_fmt(fmt) "devsec: " fmt #include #include +#include #include #include #include @@ -50,13 +51,83 @@ static void devsec_tsm_pci_remove(struct pci_tsm *tsm) kfree(devsec_tsm); } +/* protected by tsm_ops lock */ +static DECLARE_BITMAP(devsec_stream_ids, NR_TSM_STREAMS); +static struct pci_ide *devsec_streams[NR_TSM_STREAMS]; + static int devsec_tsm_connect(struct pci_dev *pdev) { - return -ENXIO; + struct pci_dev *rp = pcie_find_root_port(pdev); + struct pci_ide *ide; + int rc, stream_id; + + stream_id = + find_first_zero_bit(devsec_stream_ids, NR_TSM_STREAMS); + if (stream_id == NR_TSM_STREAMS) + return -EBUSY; + set_bit(stream_id, devsec_stream_ids); + + ide = pci_ide_stream_alloc(pdev); + if (!ide) { + rc = -ENOMEM; + goto err_stream_alloc; + } + + ide->stream_id = stream_id; + rc = pci_ide_stream_register(ide); + if (rc) + goto err_stream; + + pci_ide_stream_setup(pdev, ide); + pci_ide_stream_setup(rp, ide); + + rc = tsm_ide_stream_register(pdev, ide); + if (rc) + goto err_tsm; + + /* + * Model a TSM that handled enabling the stream at + * tsm_ide_stream_register() time + */ + pci_ide_stream_enable(pdev, ide); + devsec_streams[stream_id] = ide; + + return 0; + +err_tsm: + pci_ide_stream_teardown(rp, ide); + pci_ide_stream_teardown(pdev, ide); + pci_ide_stream_unregister(ide); +err_stream: + pci_ide_stream_free(ide); +err_stream_alloc: + clear_bit(stream_id, devsec_stream_ids); + + return rc; } static void devsec_tsm_disconnect(struct pci_dev *pdev) { + struct pci_dev *rp = pcie_find_root_port(pdev); + struct pci_ide *ide; + int i; + + for_each_set_bit(i, devsec_stream_ids, NR_TSM_STREAMS) + if (devsec_streams[i]->pdev == pdev) + break; + + if (i >= NR_TSM_STREAMS) + return; + + ide = devsec_streams[i]; + devsec_streams[i] = NULL; + pci_ide_stream_disable(pdev, ide); + tsm_ide_stream_unregister(ide); + pci_ide_stream_teardown(rp, ide); + pci_ide_stream_teardown(pdev, ide); + pci_ide_stream_unregister(ide); + pci_ide_stream_free(ide); + clear_bit(i, devsec_stream_ids); } static const struct pci_tsm_ops devsec_pci_ops = {