All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V5 0/3] Intel Software Defined Silicon
@ 2022-02-04  5:30 David E. Box
  2022-02-04  5:30 ` [PATCH V5 1/3] platform/x86: Add Intel Software Defined Silicon driver David E. Box
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: David E. Box @ 2022-02-04  5:30 UTC (permalink / raw)
  To: hdegoede, david.e.box, gregkh, andriy.shevchenko,
	srinivas.pandruvada, mgross
  Cc: linux-kernel, platform-driver-x86

This series adds support for Intel Software Defined Silicon. These
patches are the same as patches 4-6 from this series [1]. Patches 1-3 
of that series were pulled in during the 5.17 merge window.

[1] https://lore.kernel.org/lkml/20211216023146.2361174-1-david.e.box@linux.intel.com/T/

David E. Box (3):
  platform/x86: Add Intel Software Defined Silicon driver
  tools arch x86: Add Intel SDSi provisiong tool
  selftests: sdsi: test sysfs setup

 .../ABI/testing/sysfs-driver-intel_sdsi       |  77 +++
 MAINTAINERS                                   |   7 +
 drivers/platform/x86/intel/Kconfig            |  12 +
 drivers/platform/x86/intel/Makefile           |   2 +
 drivers/platform/x86/intel/sdsi.c             | 568 ++++++++++++++++++
 drivers/platform/x86/intel/vsec.c             |  12 +-
 tools/arch/x86/intel_sdsi/Makefile            |   9 +
 tools/arch/x86/intel_sdsi/sdsi.c              | 540 +++++++++++++++++
 tools/testing/selftests/drivers/sdsi/sdsi.sh  |  18 +
 .../selftests/drivers/sdsi/sdsi_test.py       | 226 +++++++
 10 files changed, 1470 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/ABI/testing/sysfs-driver-intel_sdsi
 create mode 100644 drivers/platform/x86/intel/sdsi.c
 create mode 100644 tools/arch/x86/intel_sdsi/Makefile
 create mode 100644 tools/arch/x86/intel_sdsi/sdsi.c
 create mode 100755 tools/testing/selftests/drivers/sdsi/sdsi.sh
 create mode 100644 tools/testing/selftests/drivers/sdsi/sdsi_test.py

-- 
2.25.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH V5 1/3] platform/x86: Add Intel Software Defined Silicon driver
  2022-02-04  5:30 [PATCH V5 0/3] Intel Software Defined Silicon David E. Box
@ 2022-02-04  5:30 ` David E. Box
  2022-02-04  6:57   ` Greg KH
  2022-02-04 10:14   ` Joe Perches
  2022-02-04  5:30 ` [PATCH V5 2/3] tools arch x86: Add Intel SDSi provisiong tool David E. Box
  2022-02-04  5:30 ` [PATCH V5 3/3] selftests: sdsi: test sysfs setup David E. Box
  2 siblings, 2 replies; 10+ messages in thread
From: David E. Box @ 2022-02-04  5:30 UTC (permalink / raw)
  To: hdegoede, david.e.box, gregkh, andriy.shevchenko,
	srinivas.pandruvada, mgross
  Cc: linux-kernel, platform-driver-x86, Mark Gross

Intel Software Defined Silicon (SDSi) is a post manufacturing mechanism for
activating additional silicon features. Features are enabled through a
license activation process.  The SDSi driver provides a per socket, sysfs
attribute interface for applications to perform 3 main provisioning
functions:

1. Provision an Authentication Key Certificate (AKC), a key written to
   internal NVRAM that is used to authenticate a capability specific
   activation payload.

2. Provision a Capability Activation Payload (CAP), a token authenticated
   using the AKC and applied to the CPU configuration to activate a new
   feature.

3. Read the SDSi State Certificate, containing the CPU configuration
   state.

The operations perform function specific mailbox commands that forward the
requests to SDSi hardware to perform authentication of the payloads and
enable the silicon configuration (to be made available after power
cycling).

The SDSi device itself is enumerated as an auxiliary device from the
intel_vsec driver and as such has a build dependency on CONFIG_INTEL_VSEC.

Link: https://github.com/intel/intel-sdsi
Signed-off-by: David E. Box <david.e.box@linux.intel.com>
Reviewed-by: Mark Gross <markgross@kernel.org>
---
V5
  - Update kernel version to 5.18 in API doc and copyrights to 2022.
  - Remove unneeded prototypes.
  - In binary attribute handlers where ret is only used for errors,
    replace,
              return (ret < 0) ? ret : size;
    with,
              return ret ?: size;

V4
  - Replace dropped semicolon on sdsi_aux_driver struct.
V3
  - In state_certificate_read(), return the actual size instead of the
    requested count. Return 0 if offset is non-zero so that subsequent
    calls attempting to read the rest of the count end.
  - s/folder/directory in ABI documentation.
  - Add comment that all driver resources are devm managed so remove()
    is not needed.
V2
  - Use sysfs_emit() in guid_show()
  - Fix language in ABI, suggested by Bjorn
  - Fix wrong directory name in ABI doc

 .../ABI/testing/sysfs-driver-intel_sdsi       |  77 +++
 MAINTAINERS                                   |   5 +
 drivers/platform/x86/intel/Kconfig            |  12 +
 drivers/platform/x86/intel/Makefile           |   2 +
 drivers/platform/x86/intel/sdsi.c             | 568 ++++++++++++++++++
 drivers/platform/x86/intel/vsec.c             |  12 +-
 6 files changed, 675 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/ABI/testing/sysfs-driver-intel_sdsi
 create mode 100644 drivers/platform/x86/intel/sdsi.c

diff --git a/Documentation/ABI/testing/sysfs-driver-intel_sdsi b/Documentation/ABI/testing/sysfs-driver-intel_sdsi
new file mode 100644
index 000000000000..ab122125ff9a
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-intel_sdsi
@@ -0,0 +1,77 @@
+What:		/sys/bus/auxiliary/devices/intel_vsec.sdsi.X
+Date:		Feb 2022
+KernelVersion:	5.18
+Contact:	"David E. Box" <david.e.box@linux.intel.com>
+Description:
+		This directory contains interface files for accessing Intel
+		Software Defined Silicon (SDSi) features on a CPU. X
+		represents the socket instance (though not the socket ID).
+		The socket ID is determined by reading the registers file
+		and decoding it per the specification.
+
+		Some files communicate with SDSi hardware through a mailbox.
+		Should the operation fail, one of the following error codes
+		may be returned:
+
+		Error Code	Cause
+	        ----------	-----
+	        EIO		General mailbox failure. Log may indicate cause.
+	        EBUSY		Mailbox is owned by another agent.
+	        EPERM		SDSI capability is not enabled in hardware.
+	        EPROTO		Failure in mailbox protocol detected by driver.
+				See log for details.
+	        EOVERFLOW	For provision commands, the size of the data
+				exceeds what may be written.
+	        ESPIPE		Seeking is not allowed.
+	        ETIMEDOUT	Failure to complete mailbox transaction in time.
+
+What:		/sys/bus/auxiliary/devices/intel_vsec.sdsi.X/guid
+Date:		Feb 2022
+KernelVersion:	5.18
+Contact:	"David E. Box" <david.e.box@linux.intel.com>
+Description:
+		(RO) The GUID for the registers file. The GUID identifies
+		the layout of the registers file in this directory.
+		Information about the register layouts for a particular GUID
+		is available at http://github.com/intel/intel-sdsi
+
+What:		/sys/bus/auxiliary/devices/intel_vsec.sdsi.X/registers
+Date:		Feb 2022
+KernelVersion:	5.18
+Contact:	"David E. Box" <david.e.box@linux.intel.com>
+Description:
+		(RO) Contains information needed by applications to provision
+		a CPU and monitor status information. The layout of this file
+		is determined by the GUID in this directory. Information about
+		the layout for a particular GUID is available at
+		http://github.com/intel/intel-sdsi
+
+What:		/sys/bus/auxiliary/devices/intel_vsec.sdsi.X/provision_akc
+Date:		Feb 2022
+KernelVersion:	5.18
+Contact:	"David E. Box" <david.e.box@linux.intel.com>
+Description:
+		(WO) Used to write an Authentication Key Certificate (AKC) to
+		the SDSi NVRAM for the CPU. The AKC is used to authenticate a
+		Capability Activation Payload. Mailbox command.
+
+What:		/sys/bus/auxiliary/devices/intel_vsec.sdsi.X/provision_cap
+Date:		Feb 2022
+KernelVersion:	5.18
+Contact:	"David E. Box" <david.e.box@linux.intel.com>
+Description:
+		(WO) Used to write a Capability Activation Payload (CAP) to the
+		SDSi NVRAM for the CPU. CAPs are used to activate a given CPU
+		feature. A CAP is validated by SDSi hardware using a previously
+		provisioned AKC file. Upon successful authentication, the CPU
+		configuration is updated. A cold reboot is required to fully
+		activate the feature. Mailbox command.
+
+What:		/sys/bus/auxiliary/devices/intel_vsec.sdsi.X/state_certificate
+Date:		Feb 2022
+KernelVersion:	5.18
+Contact:	"David E. Box" <david.e.box@linux.intel.com>
+Description:
+		(RO) Used to read back the current State Certificate for the CPU
+		from SDSi hardware. The State Certificate contains information
+		about the current licenses on the CPU. Mailbox command.
diff --git a/MAINTAINERS b/MAINTAINERS
index f41088418aae..aa773cf996f4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9870,6 +9870,11 @@ S:	Maintained
 F:	arch/x86/include/asm/intel_scu_ipc.h
 F:	drivers/platform/x86/intel_scu_*
 
+INTEL SDSI DRIVER
+M:	David E. Box <david.e.box@linux.intel.com>
+S:	Supported
+F:	drivers/platform/x86/intel/sdsi.c
+
 INTEL SKYLAKE INT3472 ACPI DEVICE DRIVER
 M:	Daniel Scally <djrscally@gmail.com>
 S:	Maintained
diff --git a/drivers/platform/x86/intel/Kconfig b/drivers/platform/x86/intel/Kconfig
index 8e65086bb6c8..99c8834ec979 100644
--- a/drivers/platform/x86/intel/Kconfig
+++ b/drivers/platform/x86/intel/Kconfig
@@ -134,6 +134,18 @@ config INTEL_RST
 	  firmware will copy the memory contents back to RAM and resume the OS
 	  as usual.
 
+config INTEL_SDSI
+	tristate "Intel Software Defined Silicon Driver"
+	depends on INTEL_VSEC
+	depends on X86_64
+	help
+	  This driver enables access to the Intel Software Defined Silicon
+	  interface used to provision silicon features with an authentication
+	  certificate and capability license.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called intel_sdsi.
+
 config INTEL_SMARTCONNECT
 	tristate "Intel Smart Connect disabling driver"
 	depends on ACPI
diff --git a/drivers/platform/x86/intel/Makefile b/drivers/platform/x86/intel/Makefile
index 35f2066578b2..a765d60b6002 100644
--- a/drivers/platform/x86/intel/Makefile
+++ b/drivers/platform/x86/intel/Makefile
@@ -26,6 +26,8 @@ intel_int0002_vgpio-y			:= int0002_vgpio.o
 obj-$(CONFIG_INTEL_INT0002_VGPIO)	+= intel_int0002_vgpio.o
 intel_oaktrail-y			:= oaktrail.o
 obj-$(CONFIG_INTEL_OAKTRAIL)		+= intel_oaktrail.o
+intel_sdsi-y				:= sdsi.o
+obj-$(CONFIG_INTEL_SDSI)		+= intel_sdsi.o
 intel_vsec-y				:= vsec.o
 obj-$(CONFIG_INTEL_VSEC)		+= intel_vsec.o
 
diff --git a/drivers/platform/x86/intel/sdsi.c b/drivers/platform/x86/intel/sdsi.c
new file mode 100644
index 000000000000..794291486bd0
--- /dev/null
+++ b/drivers/platform/x86/intel/sdsi.c
@@ -0,0 +1,568 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel Software Defined Silicon driver
+ *
+ * Copyright (c) 2022, Intel Corporation.
+ * All Rights Reserved.
+ *
+ * Author: "David E. Box" <david.e.box@linux.intel.com>
+ */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+
+#include "vsec.h"
+
+#define ACCESS_TYPE_BARID		2
+#define ACCESS_TYPE_LOCAL		3
+
+#define SDSI_MIN_SIZE_DWORDS		276
+#define SDSI_SIZE_CONTROL		8
+#define SDSI_SIZE_MAILBOX		1024
+#define SDSI_SIZE_REGS			72
+#define SDSI_SIZE_CMD			sizeof(u64)
+
+/*
+ * Write messages are currently up to the size of the mailbox
+ * while read messages are up to 4 times the size of the
+ * mailbox, sent in packets
+ */
+#define SDSI_SIZE_WRITE_MSG		SDSI_SIZE_MAILBOX
+#define SDSI_SIZE_READ_MSG		(SDSI_SIZE_MAILBOX * 4)
+
+#define SDSI_ENABLED_FEATURES_OFFSET	16
+#define SDSI_ENABLED			BIT(3)
+#define SDSI_SOCKET_ID_OFFSET		64
+#define SDSI_SOCKET_ID			GENMASK(3, 0)
+
+#define SDSI_MBOX_CMD_SUCCESS		0x40
+#define SDSI_MBOX_CMD_TIMEOUT		0x80
+
+#define MBOX_TIMEOUT_US			2000
+#define MBOX_TIMEOUT_ACQUIRE_US		1000
+#define MBOX_POLLING_PERIOD_US		100
+#define MBOX_MAX_PACKETS		4
+
+#define MBOX_OWNER_NONE			0x00
+#define MBOX_OWNER_INBAND		0x01
+
+#define CTRL_RUN_BUSY			BIT(0)
+#define CTRL_READ_WRITE			BIT(1)
+#define CTRL_SOM			BIT(2)
+#define CTRL_EOM			BIT(3)
+#define CTRL_OWNER			GENMASK(5, 4)
+#define CTRL_COMPLETE			BIT(6)
+#define CTRL_READY			BIT(7)
+#define CTRL_STATUS			GENMASK(15, 8)
+#define CTRL_PACKET_SIZE		GENMASK(31, 16)
+#define CTRL_MSG_SIZE			GENMASK(63, 48)
+
+#define DISC_TABLE_SIZE			12
+#define DT_ACCESS_TYPE			GENMASK(3, 0)
+#define DT_SIZE				GENMASK(27, 12)
+#define DT_TBIR				GENMASK(2, 0)
+#define DT_OFFSET(v)			((v) & GENMASK(31, 3))
+
+enum sdsi_command {
+	SDSI_CMD_PROVISION_AKC		= 0x04,
+	SDSI_CMD_PROVISION_CAP		= 0x08,
+	SDSI_CMD_READ_STATE		= 0x10,
+};
+
+struct sdsi_mbox_info {
+	u64	*payload;
+	u64	*buffer;
+	int	size;
+};
+
+struct disc_table {
+	u32	access_info;
+	u32	guid;
+	u32	offset;
+};
+
+struct sdsi_priv {
+	struct mutex		mb_lock;	/* Mailbox access lock */
+	struct device		*dev;
+	void __iomem		*control_addr;
+	void __iomem		*mbox_addr;
+	void __iomem		*regs_addr;
+	u32			guid;
+	bool			sdsi_enabled;
+};
+
+/* SDSi mailbox operations must be performed using 64bit mov instructions */
+static __always_inline void
+sdsi_memcpy64_toio(u64 __iomem *to, const u64 *from, size_t count_bytes)
+{
+	size_t count = count_bytes / sizeof(*to);
+	int i;
+
+	for (i = 0; i < count; i++)
+		writeq(from[i], &to[i]);
+}
+
+static __always_inline void
+sdsi_memcpy64_fromio(u64 *to, const u64 __iomem *from, size_t count_bytes)
+{
+	size_t count = count_bytes / sizeof(*to);
+	int i;
+
+	for (i = 0; i < count; i++)
+		to[i] = readq(&from[i]);
+}
+
+static inline void sdsi_complete_transaction(struct sdsi_priv *priv)
+{
+	u64 control = FIELD_PREP(CTRL_COMPLETE, 1);
+
+	lockdep_assert_held(&priv->mb_lock);
+	writeq(control, priv->control_addr);
+}
+
+static int sdsi_status_to_errno(u32 status)
+{
+	switch (status) {
+	case SDSI_MBOX_CMD_SUCCESS:
+		return 0;
+	case SDSI_MBOX_CMD_TIMEOUT:
+		return -ETIMEDOUT;
+	default:
+		return -EIO;
+	}
+}
+
+static int sdsi_mbox_cmd_read(struct sdsi_priv *priv, struct sdsi_mbox_info *info,
+			      size_t *data_size)
+{
+	struct device *dev = priv->dev;
+	u32 total, loop, eom, status, message_size;
+	u64 control;
+	int ret;
+
+	lockdep_assert_held(&priv->mb_lock);
+
+	/* Format and send the read command */
+	control = FIELD_PREP(CTRL_EOM, 1) |
+		  FIELD_PREP(CTRL_SOM, 1) |
+		  FIELD_PREP(CTRL_RUN_BUSY, 1) |
+		  FIELD_PREP(CTRL_PACKET_SIZE, info->size);
+	writeq(control, priv->control_addr);
+
+	/* For reads, data sizes that are larger than the mailbox size are read in packets. */
+	total = 0;
+	loop = 0;
+	do {
+		int offset = SDSI_SIZE_MAILBOX * loop;
+		void __iomem *addr = priv->mbox_addr + offset;
+		u64 *buf = info->buffer + offset / SDSI_SIZE_CMD;
+		u32 packet_size;
+
+		/* Poll on ready bit */
+		ret = readq_poll_timeout(priv->control_addr, control, control & CTRL_READY,
+					 MBOX_POLLING_PERIOD_US, MBOX_TIMEOUT_US);
+		if (ret)
+			break;
+
+		eom = FIELD_GET(CTRL_EOM, control);
+		status = FIELD_GET(CTRL_STATUS, control);
+		packet_size = FIELD_GET(CTRL_PACKET_SIZE, control);
+		message_size = FIELD_GET(CTRL_MSG_SIZE, control);
+
+		ret = sdsi_status_to_errno(status);
+		if (ret)
+			break;
+
+		/* Only the last packet can be less than the mailbox size. */
+		if (!eom && packet_size != SDSI_SIZE_MAILBOX) {
+			dev_err(dev, "Invalid packet size\n");
+			ret = -EPROTO;
+			break;
+		}
+
+		if (packet_size > SDSI_SIZE_MAILBOX) {
+			dev_err(dev, "Packet size to large\n");
+			ret = -EPROTO;
+			break;
+		}
+
+		sdsi_memcpy64_fromio(buf, addr, round_up(packet_size, SDSI_SIZE_CMD));
+
+		total += packet_size;
+
+		sdsi_complete_transaction(priv);
+	} while (!eom && ++loop < MBOX_MAX_PACKETS);
+
+	if (ret) {
+		sdsi_complete_transaction(priv);
+		return ret;
+	}
+
+	if (!eom) {
+		dev_err(dev, "Exceeded read attempts\n");
+		return -EPROTO;
+	}
+
+	/* Message size check is only valid for multi-packet transfers */
+	if (loop && total != message_size)
+		dev_warn(dev, "Read count %d differs from expected count %d\n",
+			 total, message_size);
+
+	*data_size = total;
+
+	return 0;
+}
+
+static int sdsi_mbox_cmd_write(struct sdsi_priv *priv, struct sdsi_mbox_info *info)
+{
+	u64 control;
+	u32 status;
+	int ret;
+
+	lockdep_assert_held(&priv->mb_lock);
+
+	/* Write rest of the payload */
+	sdsi_memcpy64_toio(priv->mbox_addr + SDSI_SIZE_CMD, info->payload + 1,
+			   info->size - SDSI_SIZE_CMD);
+
+	/* Format and send the write command */
+	control = FIELD_PREP(CTRL_EOM, 1) |
+		  FIELD_PREP(CTRL_SOM, 1) |
+		  FIELD_PREP(CTRL_RUN_BUSY, 1) |
+		  FIELD_PREP(CTRL_READ_WRITE, 1) |
+		  FIELD_PREP(CTRL_PACKET_SIZE, info->size);
+	writeq(control, priv->control_addr);
+
+	/* Poll on run_busy bit */
+	ret = readq_poll_timeout(priv->control_addr, control, !(control & CTRL_RUN_BUSY),
+				 MBOX_POLLING_PERIOD_US, MBOX_TIMEOUT_US);
+
+	if (ret)
+		goto release_mbox;
+
+	status = FIELD_GET(CTRL_STATUS, control);
+	ret = sdsi_status_to_errno(status);
+
+release_mbox:
+	sdsi_complete_transaction(priv);
+
+	return ret;
+}
+
+static int sdsi_mbox_acquire(struct sdsi_priv *priv, struct sdsi_mbox_info *info)
+{
+	u64 control;
+	u32 owner;
+	int ret;
+
+	lockdep_assert_held(&priv->mb_lock);
+
+	/* Check mailbox is available */
+	control = readq(priv->control_addr);
+	owner = FIELD_GET(CTRL_OWNER, control);
+	if (owner != MBOX_OWNER_NONE)
+		return -EBUSY;
+
+	/* Write first qword of payload */
+	writeq(info->payload[0], priv->mbox_addr);
+
+	/* Check for ownership */
+	ret = readq_poll_timeout(priv->control_addr, control,
+				 FIELD_GET(CTRL_OWNER, control) & MBOX_OWNER_INBAND,
+				 MBOX_POLLING_PERIOD_US, MBOX_TIMEOUT_ACQUIRE_US);
+
+	return ret;
+}
+
+static int sdsi_mbox_write(struct sdsi_priv *priv, struct sdsi_mbox_info *info)
+{
+	int ret;
+
+	lockdep_assert_held(&priv->mb_lock);
+
+	ret = sdsi_mbox_acquire(priv, info);
+	if (ret)
+		return ret;
+
+	return sdsi_mbox_cmd_write(priv, info);
+}
+
+static int sdsi_mbox_read(struct sdsi_priv *priv, struct sdsi_mbox_info *info, size_t *data_size)
+{
+	int ret;
+
+	lockdep_assert_held(&priv->mb_lock);
+
+	ret = sdsi_mbox_acquire(priv, info);
+	if (ret)
+		return ret;
+
+	return sdsi_mbox_cmd_read(priv, info, data_size);
+}
+
+static ssize_t sdsi_provision(struct sdsi_priv *priv, char *buf, size_t count,
+			      enum sdsi_command command)
+{
+	struct sdsi_mbox_info info;
+	int ret;
+
+	if (!priv->sdsi_enabled)
+		return -EPERM;
+
+	if (count > (SDSI_SIZE_WRITE_MSG - SDSI_SIZE_CMD))
+		return -EOVERFLOW;
+
+	/* Qword aligned message + command qword */
+	info.size = round_up(count, SDSI_SIZE_CMD) + SDSI_SIZE_CMD;
+
+	info.payload = kzalloc(info.size, GFP_KERNEL);
+	if (!info.payload)
+		return -ENOMEM;
+
+	/* Copy message to payload buffer */
+	memcpy(info.payload, buf, count);
+
+	/* Command is last qword of payload buffer */
+	info.payload[(info.size - SDSI_SIZE_CMD) / SDSI_SIZE_CMD] = command;
+
+	ret = mutex_lock_interruptible(&priv->mb_lock);
+	if (ret)
+		goto free_payload;
+	ret = sdsi_mbox_write(priv, &info);
+	mutex_unlock(&priv->mb_lock);
+
+free_payload:
+	kfree(info.payload);
+
+	return ret ?: count;
+}
+
+static ssize_t provision_akc_write(struct file *filp, struct kobject *kobj,
+				   struct bin_attribute *attr, char *buf, loff_t off,
+				   size_t count)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct sdsi_priv *priv = dev_get_drvdata(dev);
+
+	if (off)
+		return -ESPIPE;
+
+	return sdsi_provision(priv, buf, count, SDSI_CMD_PROVISION_AKC);
+}
+static BIN_ATTR_WO(provision_akc, SDSI_SIZE_WRITE_MSG);
+
+static ssize_t provision_cap_write(struct file *filp, struct kobject *kobj,
+				   struct bin_attribute *attr, char *buf, loff_t off,
+				   size_t count)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct sdsi_priv *priv = dev_get_drvdata(dev);
+
+	if (off)
+		return -ESPIPE;
+
+	return sdsi_provision(priv, buf, count, SDSI_CMD_PROVISION_CAP);
+}
+static BIN_ATTR_WO(provision_cap, SDSI_SIZE_WRITE_MSG);
+
+static long state_certificate_read(struct file *filp, struct kobject *kobj,
+				   struct bin_attribute *attr, char *buf, loff_t off,
+				   size_t count)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct sdsi_priv *priv = dev_get_drvdata(dev);
+	u64 command = SDSI_CMD_READ_STATE;
+	struct sdsi_mbox_info info;
+	size_t size;
+	int ret;
+
+	if (!priv->sdsi_enabled)
+		return -EPERM;
+
+	if (off)
+		return 0;
+
+	/* Buffer for return data */
+	info.buffer = kmalloc(SDSI_SIZE_READ_MSG, GFP_KERNEL);
+	if (!info.buffer)
+		return -ENOMEM;
+
+	info.payload = &command;
+	info.size = sizeof(command);
+
+	ret = mutex_lock_interruptible(&priv->mb_lock);
+	if (ret)
+		goto free_buffer;
+	ret = sdsi_mbox_read(priv, &info, &size);
+	mutex_unlock(&priv->mb_lock);
+	if (ret < 0)
+		goto free_buffer;
+
+	if (size > count)
+		size = count;
+
+	memcpy(buf, info.buffer, size);
+
+free_buffer:
+	kfree(info.buffer);
+
+	return ret ?: size;
+}
+static BIN_ATTR(state_certificate, 0400, state_certificate_read, NULL, SDSI_SIZE_READ_MSG);
+
+static ssize_t registers_read(struct file *filp, struct kobject *kobj,
+			      struct bin_attribute *attr, char *buf, loff_t off,
+			      size_t count)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct sdsi_priv *priv = dev_get_drvdata(dev);
+	void __iomem *addr = priv->regs_addr;
+
+	memcpy_fromio(buf, addr + off, count);
+
+	return count;
+}
+static BIN_ATTR(registers, 0400, registers_read, NULL, SDSI_SIZE_REGS);
+
+static struct bin_attribute *sdsi_bin_attrs[] = {
+	&bin_attr_registers,
+	&bin_attr_state_certificate,
+	&bin_attr_provision_akc,
+	&bin_attr_provision_cap,
+	NULL
+};
+
+static ssize_t guid_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sdsi_priv *priv = dev_get_drvdata(dev);
+
+	return sysfs_emit(buf, "0x%x\n", priv->guid);
+}
+static DEVICE_ATTR_RO(guid);
+
+static struct attribute *sdsi_attrs[] = {
+	&dev_attr_guid.attr,
+	NULL
+};
+
+static const struct attribute_group sdsi_group = {
+	.attrs = sdsi_attrs,
+	.bin_attrs = sdsi_bin_attrs,
+};
+__ATTRIBUTE_GROUPS(sdsi);
+
+static int sdsi_map_mbox_registers(struct sdsi_priv *priv, struct pci_dev *parent,
+				   struct disc_table *disc_table, struct resource *disc_res)
+{
+	u32 access_type = FIELD_GET(DT_ACCESS_TYPE, disc_table->access_info);
+	u32 size = FIELD_GET(DT_SIZE, disc_table->access_info);
+	u32 tbir = FIELD_GET(DT_TBIR, disc_table->offset);
+	u32 offset = DT_OFFSET(disc_table->offset);
+	u32 features_offset;
+	struct resource res = {};
+
+	/* Starting location of SDSi MMIO region based on access type */
+	switch (access_type) {
+	case ACCESS_TYPE_LOCAL:
+		if (tbir) {
+			dev_err(priv->dev, "Unsupported BAR index %d for access type %d\n",
+				tbir, access_type);
+			return -EINVAL;
+		}
+
+		/*
+		 * For access_type LOCAL, the base address is as follows:
+		 * base address = end of discovery region + base offset + 1
+		 */
+		res.start = disc_res->end + offset + 1;
+		break;
+
+	case ACCESS_TYPE_BARID:
+		res.start = pci_resource_start(parent, tbir) + offset;
+		break;
+
+	default:
+		dev_err(priv->dev, "Unrecognized access_type %d\n", access_type);
+		return -EINVAL;
+	}
+
+	res.end = res.start + size * sizeof(u32) - 1;
+	res.flags = IORESOURCE_MEM;
+
+	priv->control_addr = devm_ioremap_resource(priv->dev, &res);
+	if (IS_ERR(priv->control_addr))
+		return PTR_ERR(priv->control_addr);
+
+	priv->mbox_addr = priv->control_addr + SDSI_SIZE_CONTROL;
+	priv->regs_addr = priv->mbox_addr + SDSI_SIZE_MAILBOX;
+
+	features_offset = readq(priv->regs_addr + SDSI_ENABLED_FEATURES_OFFSET);
+	priv->sdsi_enabled = !!(features_offset & SDSI_ENABLED);
+
+	return 0;
+}
+
+static int sdsi_probe(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id)
+{
+	struct intel_vsec_device *intel_cap_dev = auxdev_to_ivdev(auxdev);
+	struct disc_table disc_table;
+	struct resource *disc_res;
+	void __iomem *disc_addr;
+	struct sdsi_priv *priv;
+	int ret;
+
+	priv = devm_kzalloc(&auxdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = &auxdev->dev;
+	mutex_init(&priv->mb_lock);
+	auxiliary_set_drvdata(auxdev, priv);
+
+	/* Get the SDSi discovery table */
+	disc_res = &intel_cap_dev->resource[0];
+	disc_addr = devm_ioremap_resource(&auxdev->dev, disc_res);
+	if (IS_ERR(disc_addr))
+		return PTR_ERR(disc_addr);
+
+	memcpy_fromio(&disc_table, disc_addr, DISC_TABLE_SIZE);
+
+	priv->guid = disc_table.guid;
+
+	/* Map the SDSi mailbox registers */
+	ret = sdsi_map_mbox_registers(priv, intel_cap_dev->pcidev, &disc_table, disc_res);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static const struct auxiliary_device_id sdsi_aux_id_table[] = {
+	{ .name = "intel_vsec.sdsi" },
+	{}
+};
+MODULE_DEVICE_TABLE(auxiliary, sdsi_aux_id_table);
+
+static struct auxiliary_driver sdsi_aux_driver = {
+	.driver = {
+		.dev_groups = sdsi_groups,
+	},
+	.id_table	= sdsi_aux_id_table,
+	.probe		= sdsi_probe,
+	/* No remove. All resources are handled under devm */
+};
+module_auxiliary_driver(sdsi_aux_driver);
+
+MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
+MODULE_DESCRIPTION("Intel Software Defined Silicon driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/intel/vsec.c b/drivers/platform/x86/intel/vsec.c
index c3bdd75ed690..bed436bf181f 100644
--- a/drivers/platform/x86/intel/vsec.c
+++ b/drivers/platform/x86/intel/vsec.c
@@ -32,6 +32,7 @@
 #define TABLE_OFFSET_SHIFT		3
 
 static DEFINE_IDA(intel_vsec_ida);
+static DEFINE_IDA(intel_vsec_sdsi_ida);
 
 /**
  * struct intel_vsec_header - Common fields of Intel VSEC and DVSEC registers.
@@ -63,12 +64,14 @@ enum intel_vsec_id {
 	VSEC_ID_TELEMETRY	= 2,
 	VSEC_ID_WATCHER		= 3,
 	VSEC_ID_CRASHLOG	= 4,
+	VSEC_ID_SDSI		= 65,
 };
 
 static enum intel_vsec_id intel_vsec_allow_list[] = {
 	VSEC_ID_TELEMETRY,
 	VSEC_ID_WATCHER,
 	VSEC_ID_CRASHLOG,
+	VSEC_ID_SDSI,
 };
 
 static const char *intel_vsec_name(enum intel_vsec_id id)
@@ -83,6 +86,9 @@ static const char *intel_vsec_name(enum intel_vsec_id id)
 	case VSEC_ID_CRASHLOG:
 		return "crashlog";
 
+	case VSEC_ID_SDSI:
+		return "sdsi";
+
 	default:
 		return NULL;
 	}
@@ -211,7 +217,11 @@ static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *he
 	intel_vsec_dev->resource = res;
 	intel_vsec_dev->num_resources = header->num_entries;
 	intel_vsec_dev->quirks = quirks;
-	intel_vsec_dev->ida = &intel_vsec_ida;
+
+	if (header->id == VSEC_ID_SDSI)
+		intel_vsec_dev->ida = &intel_vsec_sdsi_ida;
+	else
+		intel_vsec_dev->ida = &intel_vsec_ida;
 
 	return intel_vsec_add_aux(pdev, intel_vsec_dev, intel_vsec_name(header->id));
 }
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH V5 2/3] tools arch x86: Add Intel SDSi provisiong tool
  2022-02-04  5:30 [PATCH V5 0/3] Intel Software Defined Silicon David E. Box
  2022-02-04  5:30 ` [PATCH V5 1/3] platform/x86: Add Intel Software Defined Silicon driver David E. Box
@ 2022-02-04  5:30 ` David E. Box
  2022-02-04  5:30 ` [PATCH V5 3/3] selftests: sdsi: test sysfs setup David E. Box
  2 siblings, 0 replies; 10+ messages in thread
From: David E. Box @ 2022-02-04  5:30 UTC (permalink / raw)
  To: hdegoede, david.e.box, gregkh, andriy.shevchenko,
	srinivas.pandruvada, mgross
  Cc: linux-kernel, platform-driver-x86

Add tool for key certificate and activation payload provisioning on
Intel CPUs supporting Software Defined Silicon (SDSi).

Signed-off-by: David E. Box <david.e.box@linux.intel.com>
---
V5
  - Update copyright to 2022
V4
  - No changes.
V3
  - Move from samples to tools.
  - Fix bit fields in availability structure.
  - Check provisioning availability before issuing command.

V2
  - New patch.
 MAINTAINERS                        |   1 +
 tools/arch/x86/intel_sdsi/Makefile |   9 +
 tools/arch/x86/intel_sdsi/sdsi.c   | 540 +++++++++++++++++++++++++++++
 3 files changed, 550 insertions(+)
 create mode 100644 tools/arch/x86/intel_sdsi/Makefile
 create mode 100644 tools/arch/x86/intel_sdsi/sdsi.c

diff --git a/MAINTAINERS b/MAINTAINERS
index aa773cf996f4..c4e95543e927 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9874,6 +9874,7 @@ INTEL SDSI DRIVER
 M:	David E. Box <david.e.box@linux.intel.com>
 S:	Supported
 F:	drivers/platform/x86/intel/sdsi.c
+F:	tools/arch/x86/intel_sdsi/
 
 INTEL SKYLAKE INT3472 ACPI DEVICE DRIVER
 M:	Daniel Scally <djrscally@gmail.com>
diff --git a/tools/arch/x86/intel_sdsi/Makefile b/tools/arch/x86/intel_sdsi/Makefile
new file mode 100644
index 000000000000..1c2d102ff8fb
--- /dev/null
+++ b/tools/arch/x86/intel_sdsi/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+
+.PHONY: sdsi
+
+sdsi: sdsi.o
+	$(CC) -Wall $^ -o $@
+
+clean:
+	rm *.o sdsi
diff --git a/tools/arch/x86/intel_sdsi/sdsi.c b/tools/arch/x86/intel_sdsi/sdsi.c
new file mode 100644
index 000000000000..8d59784e853e
--- /dev/null
+++ b/tools/arch/x86/intel_sdsi/sdsi.c
@@ -0,0 +1,540 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * sdsi: Intel Software Defined Silicon tool for provisioning certificates
+ * and activation payloads on supported cpus.
+ *
+ * See https://github.com/intel/intel-sdsi/blob/master/os-interface.rst
+ * for register descriptions.
+ *
+ * Copyright (C) 2022 Intel Corporation. All rights reserved.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+
+#define SDSI_DEV		"intel_vsec.sdsi"
+#define AUX_DEV_PATH		"/sys/bus/auxiliary/devices/"
+#define SDSI_PATH		(AUX_DEV_DIR SDSI_DEV)
+#define GUID			0x6dd191
+#define REGISTERS_MIN_SIZE	72
+
+#define __round_mask(x, y) ((__typeof__(x))((y) - 1))
+#define round_up(x, y) ((((x) - 1) | __round_mask(x, y)) + 1)
+
+struct enabled_features {
+	uint64_t reserved:3;
+	uint64_t sdsi:1;
+	uint64_t reserved1:60;
+};
+
+struct auth_fail_count {
+	uint64_t key_failure_count:3;
+	uint64_t key_failure_threshold:3;
+	uint64_t auth_failure_count:3;
+	uint64_t auth_failure_threshold:3;
+	uint64_t reserved:52;
+};
+
+struct availability {
+	uint64_t reserved:48;
+	uint64_t available:3;
+	uint64_t threshold:3;
+};
+
+struct sdsi_regs {
+	uint64_t ppin;
+	uint64_t reserved;
+	struct enabled_features en_features;
+	uint64_t reserved1;
+	struct auth_fail_count auth_fail_count;
+	struct availability prov_avail;
+	uint64_t reserved2;
+	uint64_t reserved3;
+	uint64_t socket_id;
+};
+
+struct sdsi_dev {
+	struct sdsi_regs regs;
+	char *dev_name;
+	char *dev_path;
+	int guid;
+};
+
+enum command {
+	CMD_NONE,
+	CMD_LIST_DEVICES,
+	CMD_SOCKET_INFO,
+	CMD_DUMP_CERT,
+	CMD_PROV_AKC,
+	CMD_PROV_CAP,
+};
+
+static void sdsi_list_devices(void)
+{
+	struct dirent *entry;
+	DIR *aux_dir;
+	bool found = false;
+
+	aux_dir = opendir(AUX_DEV_PATH);
+	if (!aux_dir) {
+		fprintf(stderr, "Cannot open directory %s\n", AUX_DEV_PATH);
+		return;
+	}
+
+	while ((entry = readdir(aux_dir))) {
+		if (!strncmp(SDSI_DEV, entry->d_name, strlen(SDSI_DEV))) {
+			found = true;
+			printf("%s\n", entry->d_name);
+		}
+	}
+
+	if (!found)
+		fprintf(stderr, "No sdsi devices found.\n");
+}
+
+static int sdsi_update_registers(struct sdsi_dev *s)
+{
+	FILE *regs_ptr;
+	int ret;
+
+	memset(&s->regs, 0, sizeof(s->regs));
+
+	/* Open the registers file */
+	ret = chdir(s->dev_path);
+	if (ret == -1) {
+		perror("chdir");
+		return ret;
+	}
+
+	regs_ptr = fopen("registers", "r");
+	if (!regs_ptr) {
+		perror("Could not open 'registers' file");
+		return -1;
+	}
+
+	if (s->guid != GUID) {
+		fprintf(stderr, "Unrecognized guid, 0x%x\n", s->guid);
+		fclose(regs_ptr);
+		return -1;
+	}
+
+	/* Update register info for this guid */
+	ret = fread(&s->regs, sizeof(uint8_t), sizeof(s->regs), regs_ptr);
+	if (ret != sizeof(s->regs)) {
+		fprintf(stderr, "Could not read 'registers' file\n");
+		fclose(regs_ptr);
+		return -1;
+	}
+
+	fclose(regs_ptr);
+
+	return 0;
+}
+
+static int sdsi_read_reg(struct sdsi_dev *s)
+{
+	int ret;
+
+	ret = sdsi_update_registers(s);
+	if (ret)
+		return ret;
+
+	/* Print register info for this guid */
+	printf("\n");
+	printf("Socket information for device %s\n", s->dev_name);
+	printf("\n");
+	printf("PPIN:                           0x%lx\n", s->regs.ppin);
+	printf("Enabled Features\n");
+	printf("    SDSi:                       %s\n", !!s->regs.en_features.sdsi ? "Enabled" : "Disabled");
+	printf("Authorization Failure Count\n");
+	printf("    AKC Failure Count:          %d\n", s->regs.auth_fail_count.key_failure_count);
+	printf("    AKC Failure Threshold:      %d\n", s->regs.auth_fail_count.key_failure_threshold);
+	printf("    CAP Failure Count:          %d\n", s->regs.auth_fail_count.auth_failure_count);
+	printf("    CAP Failure Threshold:      %d\n", s->regs.auth_fail_count.auth_failure_threshold);
+	printf("Provisioning Availability\n");
+	printf("    Updates Available:          %d\n", s->regs.prov_avail.available);
+	printf("    Updates Threshold:          %d\n", s->regs.prov_avail.threshold);
+	printf("Socket ID:                      %ld\n", s->regs.socket_id & 0xF);
+
+	return 0;
+}
+
+static int sdsi_certificate_dump(struct sdsi_dev *s)
+{
+	uint64_t state_certificate[512] = {0};
+	bool first_instance;
+	uint64_t previous;
+	FILE *cert_ptr;
+	int i, ret, size;
+
+	ret = sdsi_update_registers(s);
+	if (ret)
+		return ret;
+
+	if (!s->regs.en_features.sdsi) {
+		fprintf(stderr, "SDSi feature is present but not enabled.");
+		fprintf(stderr, " Unable to read state certificate");
+		return -1;
+	}
+
+	ret = chdir(s->dev_path);
+	if (ret == -1) {
+		perror("chdir");
+		return ret;
+	}
+
+	cert_ptr = fopen("state_certificate", "r");
+	if (!cert_ptr) {
+		perror("Could not open 'state_certificate' file");
+		return -1;
+	}
+
+	size = fread(state_certificate, 1, sizeof(state_certificate), cert_ptr);
+	if (!size) {
+		fprintf(stderr, "Could not read 'state_certificate' file\n");
+		fclose(cert_ptr);
+		return -1;
+	}
+
+	printf("%3d: 0x%lx\n", 0, state_certificate[0]);
+	previous = state_certificate[0];
+	first_instance = true;
+
+	for (i = 1; i < (round_up(size, sizeof(uint64_t))/sizeof(uint64_t)); i++) {
+		if (state_certificate[i] == previous) {
+			if (first_instance) {
+				puts("*");
+				first_instance = false;
+			}
+			continue;
+		}
+		printf("%3d: 0x%lx\n", i, state_certificate[i]);
+		previous = state_certificate[i];
+		first_instance = true;
+	}
+	printf("%3d\n", i);
+
+	fclose(cert_ptr);
+
+	return 0;
+}
+
+static int sdsi_provision(struct sdsi_dev *s, char *bin_file, enum command command)
+{
+	int bin_fd, prov_fd, size, ret;
+	char buf[4096] = { 0 };
+	char cap[] = "provision_cap";
+	char akc[] = "provision_akc";
+	char *prov_file;
+
+	if (!bin_file) {
+		fprintf(stderr, "No binary file provided\n");
+		return -1;
+	}
+
+	/* Open the binary */
+	bin_fd = open(bin_file, O_RDONLY);
+	if (bin_fd == -1) {
+		fprintf(stderr, "Could not open file %s: %s\n", bin_file, strerror(errno));
+		return bin_fd;
+	}
+
+	prov_file = (command == CMD_PROV_AKC) ? akc : cap;
+
+	ret = chdir(s->dev_path);
+	if (ret == -1) {
+		perror("chdir");
+		close(bin_fd);
+		return ret;
+	}
+
+	/* Open the provision file */
+	prov_fd = open(prov_file, O_WRONLY);
+	if (prov_fd == -1) {
+		fprintf(stderr, "Could not open file %s: %s\n", prov_file, strerror(errno));
+		close(bin_fd);
+		return prov_fd;
+	}
+
+	/* Read the binary file into the buffer */
+	size = read(bin_fd, buf, 4096);
+	if (size == -1) {
+		close(bin_fd);
+		close(prov_fd);
+		return -1;
+	}
+
+	ret = write(prov_fd, buf, size);
+	if (ret == -1) {
+		close(bin_fd);
+		close(prov_fd);
+		perror("Provisioning failed");
+		return ret;
+	}
+
+	printf("Provisioned %s file %s successfully\n", prov_file, bin_file);
+
+	close(bin_fd);
+	close(prov_fd);
+
+	return 0;
+}
+
+static int sdsi_provision_akc(struct sdsi_dev *s, char *bin_file)
+{
+	int ret;
+
+	ret = sdsi_update_registers(s);
+	if (ret)
+		return ret;
+
+	if (!s->regs.en_features.sdsi) {
+		fprintf(stderr, "SDSi feature is present but not enabled. Unable to provision");
+		return -1;
+	}
+
+	if (!s->regs.prov_avail.available) {
+		fprintf(stderr, "Maximum number of updates (%d) has been reached.\n",
+			s->regs.prov_avail.threshold);
+		return -1;
+	}
+
+	if (s->regs.auth_fail_count.key_failure_count ==
+	    s->regs.auth_fail_count.key_failure_threshold) {
+		fprintf(stderr, "Maximum number of AKC provision failures (%d) has been reached.\n",
+			s->regs.auth_fail_count.key_failure_threshold);
+		fprintf(stderr, "Power cycle the system to reset the counter\n");
+		return -1;
+	}
+
+	return sdsi_provision(s, bin_file, CMD_PROV_AKC);
+}
+
+static int sdsi_provision_cap(struct sdsi_dev *s, char *bin_file)
+{
+	int ret;
+
+	ret = sdsi_update_registers(s);
+	if (ret)
+		return ret;
+
+	if (!s->regs.en_features.sdsi) {
+		fprintf(stderr, "SDSi feature is present but not enabled. Unable to provision");
+		return -1;
+	}
+
+	if (!s->regs.prov_avail.available) {
+		fprintf(stderr, "Maximum number of updates (%d) has been reached.\n",
+			s->regs.prov_avail.threshold);
+		return -1;
+	}
+
+	if (s->regs.auth_fail_count.auth_failure_count ==
+	    s->regs.auth_fail_count.auth_failure_threshold) {
+		fprintf(stderr, "Maximum number of CAP provision failures (%d) has been reached.\n",
+			s->regs.auth_fail_count.auth_failure_threshold);
+		fprintf(stderr, "Power cycle the system to reset the counter\n");
+		return -1;
+	}
+
+	return sdsi_provision(s, bin_file, CMD_PROV_CAP);
+}
+
+static int read_sysfs_data(const char *file, int *value)
+{
+	char buff[16];
+	FILE *fp;
+
+	fp = fopen(file, "r");
+	if (!fp) {
+		perror(file);
+		return -1;
+	}
+
+	if (!fgets(buff, 16, fp)) {
+		fprintf(stderr, "Failed to read file '%s'", file);
+		fclose(fp);
+		return -1;
+	}
+
+	fclose(fp);
+	*value = strtol(buff, NULL, 0);
+
+	return 0;
+}
+
+static struct sdsi_dev *sdsi_create_dev(char *dev_no)
+{
+	int dev_name_len = sizeof(SDSI_DEV) + strlen(dev_no) + 1;
+	struct sdsi_dev *s;
+	int guid;
+	DIR *dir;
+
+	s = (struct sdsi_dev *)malloc(sizeof(*s));
+	if (!s) {
+		perror("malloc");
+		return NULL;
+	}
+
+	s->dev_name = (char *)malloc(sizeof(SDSI_DEV) + strlen(dev_no) + 1);
+	if (!s->dev_name) {
+		perror("malloc");
+		free(s);
+		return NULL;
+	}
+
+	snprintf(s->dev_name, dev_name_len, "%s.%s", SDSI_DEV, dev_no);
+
+	s->dev_path = (char *)malloc(sizeof(AUX_DEV_PATH) + dev_name_len);
+	if (!s->dev_path) {
+		perror("malloc");
+		free(s->dev_name);
+		free(s);
+		return NULL;
+	}
+
+	snprintf(s->dev_path, sizeof(AUX_DEV_PATH) + dev_name_len, "%s%s", AUX_DEV_PATH,
+		 s->dev_name);
+	dir = opendir(s->dev_path);
+	if (!dir) {
+		fprintf(stderr, "Could not open directory '%s': %s\n", s->dev_path,
+			strerror(errno));
+		free(s->dev_path);
+		free(s->dev_name);
+		free(s);
+		return NULL;
+	}
+
+	if (chdir(s->dev_path) == -1) {
+		perror("chdir");
+		free(s->dev_path);
+		free(s->dev_name);
+		free(s);
+		return NULL;
+	}
+
+	if (read_sysfs_data("guid", &guid)) {
+		free(s->dev_path);
+		free(s->dev_name);
+		free(s);
+		return NULL;
+	}
+
+	s->guid = guid;
+
+	return s;
+}
+
+static void sdsi_free_dev(struct sdsi_dev *s)
+{
+	free(s->dev_path);
+	free(s->dev_name);
+	free(s);
+}
+
+static void print_help(char *prog)
+{
+	printf("Usage: %s [-l] [-d dev_no [-is] [-a file] [-c file]]\n", prog);
+
+	printf("\n");
+	printf("Commands:\n");
+	printf("  %-13s\t%s\n", "-l", "list available sdsi devices");
+	printf("  %-13s\t%s\n", "-d <dev_no>", "sdsi device number");
+	printf("  %-13s\t%s\n", "-i", "show socket information");
+	printf("  %-13s\t%s\n", "-s", "dump state certificate data");
+	printf("  %-13s\t%s\n", "-a <file>", "provision socket with AKC file");
+	printf("  %-13s\t%s\n", "-c <file>", "provision socket with CAP file");
+}
+
+int main(int argc, char *argv[])
+{
+	char bin_file[PATH_MAX], *dev_no = NULL;
+	enum command command = CMD_NONE;
+	struct sdsi_dev *s;
+	int ret = 0, opt;
+
+	while ((opt = getopt(argc, argv, "d:lisa:c:h")) != -1) {
+		switch (opt) {
+		case 'd':
+			dev_no = optarg;
+			break;
+		case 'l':
+			command = CMD_LIST_DEVICES;
+			break;
+		case 'i':
+			command = CMD_SOCKET_INFO;
+			break;
+		case 's':
+			command = CMD_DUMP_CERT;
+			break;
+		case 'a':
+		case 'c':
+			if (!access(optarg, F_OK) == 0) {
+				fprintf(stderr, "Could not open file '%s': %s\n", optarg,
+					strerror(errno));
+				return -1;
+			}
+
+			if (!realpath(optarg, bin_file)) {
+				perror("realpath");
+				return -1;
+			}
+
+			command = (opt == 'a') ? CMD_PROV_AKC : CMD_PROV_CAP;
+			break;
+		case 'h':
+		default:
+			print_help(argv[0]);
+			return 0;
+		}
+	}
+
+	if (!dev_no && command != CMD_LIST_DEVICES) {
+		print_help(argv[0]);
+		return -1;
+	}
+
+	if (dev_no) {
+		s = sdsi_create_dev(dev_no);
+		if (!s)
+			return -1;
+	}
+
+	/* Run the command */
+	switch (command) {
+	case CMD_NONE:
+		fprintf(stderr, "need to specify a command\n");
+		print_help(argv[0]);
+		ret = -1;
+	case CMD_LIST_DEVICES:
+		sdsi_list_devices();
+		break;
+	case CMD_SOCKET_INFO:
+		ret = sdsi_read_reg(s);
+		break;
+	case CMD_DUMP_CERT:
+		ret = sdsi_certificate_dump(s);
+		break;
+	case CMD_PROV_AKC:
+		ret = sdsi_provision_akc(s, bin_file);
+		break;
+	case CMD_PROV_CAP:
+		ret = sdsi_provision_cap(s, bin_file);
+		break;
+	}
+
+
+	if (dev_no)
+		sdsi_free_dev(s);
+
+	return ret;
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH V5 3/3] selftests: sdsi: test sysfs setup
  2022-02-04  5:30 [PATCH V5 0/3] Intel Software Defined Silicon David E. Box
  2022-02-04  5:30 ` [PATCH V5 1/3] platform/x86: Add Intel Software Defined Silicon driver David E. Box
  2022-02-04  5:30 ` [PATCH V5 2/3] tools arch x86: Add Intel SDSi provisiong tool David E. Box
@ 2022-02-04  5:30 ` David E. Box
  2 siblings, 0 replies; 10+ messages in thread
From: David E. Box @ 2022-02-04  5:30 UTC (permalink / raw)
  To: hdegoede, david.e.box, gregkh, andriy.shevchenko,
	srinivas.pandruvada, mgross
  Cc: linux-kernel, platform-driver-x86

Tests file configuration and error handling of the Intel Software
Defined Silicon sysfs ABI.

Signed-off-by: David E. Box <david.e.box@linux.intel.com>
---
V5
  - No changes.
V4
  - No changes.
V3
  - Add tests to check PCI device removal handling and to check for
    driver memory leaks.
V2
  - New patch.

 MAINTAINERS                                   |   1 +
 tools/testing/selftests/drivers/sdsi/sdsi.sh  |  18 ++
 .../selftests/drivers/sdsi/sdsi_test.py       | 226 ++++++++++++++++++
 3 files changed, 245 insertions(+)
 create mode 100755 tools/testing/selftests/drivers/sdsi/sdsi.sh
 create mode 100644 tools/testing/selftests/drivers/sdsi/sdsi_test.py

diff --git a/MAINTAINERS b/MAINTAINERS
index c4e95543e927..9c7d75bdb5ac 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9875,6 +9875,7 @@ M:	David E. Box <david.e.box@linux.intel.com>
 S:	Supported
 F:	drivers/platform/x86/intel/sdsi.c
 F:	tools/arch/x86/intel_sdsi/
+F:	tools/testing/selftests/drivers/sdsi/
 
 INTEL SKYLAKE INT3472 ACPI DEVICE DRIVER
 M:	Daniel Scally <djrscally@gmail.com>
diff --git a/tools/testing/selftests/drivers/sdsi/sdsi.sh b/tools/testing/selftests/drivers/sdsi/sdsi.sh
new file mode 100755
index 000000000000..8db71961d164
--- /dev/null
+++ b/tools/testing/selftests/drivers/sdsi/sdsi.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# Runs tests for the intel_sdsi driver
+
+if ! /sbin/modprobe -q -r intel_sdsi; then
+	echo "drivers/sdsi: [SKIP]"
+	exit 77
+fi
+
+if /sbin/modprobe -q intel_sdsi; then
+	python3 -m pytest sdsi_test.py
+	/sbin/modprobe -q -r intel_sdsi
+
+	echo "drivers/sdsi: ok"
+else
+	echo "drivers/sdsi: [FAIL]"
+	exit 1
+fi
diff --git a/tools/testing/selftests/drivers/sdsi/sdsi_test.py b/tools/testing/selftests/drivers/sdsi/sdsi_test.py
new file mode 100644
index 000000000000..4922edfe461f
--- /dev/null
+++ b/tools/testing/selftests/drivers/sdsi/sdsi_test.py
@@ -0,0 +1,226 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+
+from struct import pack
+from time import sleep
+
+import errno
+import glob
+import os
+import subprocess
+
+try:
+    import pytest
+except ImportError:
+    print("Unable to import pytest python module.")
+    print("\nIf not already installed, you may do so with:")
+    print("\t\tpip3 install pytest")
+    exit(1)
+
+SOCKETS = glob.glob('/sys/bus/auxiliary/devices/intel_vsec.sdsi.*')
+NUM_SOCKETS = len(SOCKETS)
+
+MODULE_NAME = 'sdsi'
+DEV_PREFIX = 'intel_vsec.sdsi'
+CLASS_DIR = '/sys/bus/auxiliary/devices'
+GUID = "0x6dd191"
+
+def read_bin_file(file):
+    with open(file, mode='rb') as f:
+        content = f.read()
+    return content
+
+def get_dev_file_path(socket, file):
+    return CLASS_DIR + '/' + DEV_PREFIX + '.' + str(socket) + '/' + file
+
+def kmemleak_enabled():
+    kmemleak = "/sys/kernel/debug/kmemleak"
+    return os.path.isfile(kmemleak)
+
+class TestSDSiDriver:
+    def test_driver_loaded(self):
+        lsmod_p = subprocess.Popen(('lsmod'), stdout=subprocess.PIPE)
+        result = subprocess.check_output(('grep', '-q', MODULE_NAME), stdin=lsmod_p.stdout)
+
+@pytest.mark.parametrize('socket', range(0, NUM_SOCKETS))
+class TestSDSiFilesClass:
+
+    def read_value(self, file):
+        f = open(file, "r")
+        value = f.read().strip("\n")
+        return value
+
+    def get_dev_folder(self, socket):
+        return CLASS_DIR + '/' + DEV_PREFIX + '.' + str(socket) + '/'
+
+    def test_sysfs_files_exist(self, socket):
+        folder = self.get_dev_folder(socket)
+        print (folder)
+        assert os.path.isfile(folder + "guid") == True
+        assert os.path.isfile(folder + "provision_akc") == True
+        assert os.path.isfile(folder + "provision_cap") == True
+        assert os.path.isfile(folder + "state_certificate") == True
+        assert os.path.isfile(folder + "registers") == True
+
+    def test_sysfs_file_permissions(self, socket):
+        folder = self.get_dev_folder(socket)
+        mode = os.stat(folder + "guid").st_mode & 0o777
+        assert mode == 0o444    # Read all
+        mode = os.stat(folder + "registers").st_mode & 0o777
+        assert mode == 0o400    # Read owner
+        mode = os.stat(folder + "provision_akc").st_mode & 0o777
+        assert mode == 0o200    # Read owner
+        mode = os.stat(folder + "provision_cap").st_mode & 0o777
+        assert mode == 0o200    # Read owner
+        mode = os.stat(folder + "state_certificate").st_mode & 0o777
+        assert mode == 0o400    # Read owner
+
+    def test_sysfs_file_ownership(self, socket):
+        folder = self.get_dev_folder(socket)
+
+        st = os.stat(folder + "guid")
+        assert st.st_uid == 0
+        assert st.st_gid == 0
+
+        st = os.stat(folder + "registers")
+        assert st.st_uid == 0
+        assert st.st_gid == 0
+
+        st = os.stat(folder + "provision_akc")
+        assert st.st_uid == 0
+        assert st.st_gid == 0
+
+        st = os.stat(folder + "provision_cap")
+        assert st.st_uid == 0
+        assert st.st_gid == 0
+
+        st = os.stat(folder + "state_certificate")
+        assert st.st_uid == 0
+        assert st.st_gid == 0
+
+    def test_sysfs_file_sizes(self, socket):
+        folder = self.get_dev_folder(socket)
+
+        if self.read_value(folder + "guid") == GUID:
+            st = os.stat(folder + "registers")
+            assert st.st_size == 72
+
+        st = os.stat(folder + "provision_akc")
+        assert st.st_size == 1024
+
+        st = os.stat(folder + "provision_cap")
+        assert st.st_size == 1024
+
+        st = os.stat(folder + "state_certificate")
+        assert st.st_size == 4096
+
+    def test_no_seek_allowed(self, socket):
+        folder = self.get_dev_folder(socket)
+        rand_file = bytes(os.urandom(8))
+
+        f = open(folder + "provision_cap", "wb", 0)
+        f.seek(1)
+        with pytest.raises(OSError) as error:
+            f.write(rand_file)
+        assert error.value.errno == errno.ESPIPE
+        f.close()
+
+        f = open(folder + "provision_akc", "wb", 0)
+        f.seek(1)
+        with pytest.raises(OSError) as error:
+            f.write(rand_file)
+        assert error.value.errno == errno.ESPIPE
+        f.close()
+
+    def test_registers_seek(self, socket):
+        folder = self.get_dev_folder(socket)
+
+        # Check that the value read from an offset of the entire
+        # file is none-zero and the same as the value read
+        # from seeking to the same location
+        f = open(folder + "registers", "rb")
+        data = f.read()
+        f.seek(64)
+        id = f.read()
+        assert id != bytes(0)
+        assert data[64:] == id
+        f.close()
+
+@pytest.mark.parametrize('socket', range(0, NUM_SOCKETS))
+class TestSDSiMailboxCmdsClass:
+    def test_provision_akc_eoverflow_1017_bytes(self, socket):
+
+        # The buffer for writes is 1k, of with 8 bytes must be
+        # reserved for the command, leaving 1016 bytes max.
+        # Check that we get an overflow error for 1017 bytes.
+        node = get_dev_file_path(socket, "provision_akc")
+        rand_file = bytes(os.urandom(1017))
+
+        f = open(node, 'wb', 0)
+        with pytest.raises(OSError) as error:
+            f.write(rand_file)
+        assert error.value.errno == errno.EOVERFLOW
+        f.close()
+
+@pytest.mark.parametrize('socket', range(0, NUM_SOCKETS))
+class TestSdsiDriverLocksClass:
+    def test_enodev_when_pci_device_removed(self, socket):
+        node = get_dev_file_path(socket, "provision_akc")
+        dev_name = DEV_PREFIX + '.' + str(socket)
+        driver_dir = CLASS_DIR + '/' + dev_name + "/driver/"
+        rand_file = bytes(os.urandom(8))
+
+        f = open(node, 'wb', 0)
+        g = open(node, 'wb', 0)
+
+        with open(driver_dir + 'unbind', 'w') as k:
+            print(dev_name, file = k)
+
+        with pytest.raises(OSError) as error:
+            f.write(rand_file)
+        assert error.value.errno == errno.ENODEV
+
+        with pytest.raises(OSError) as error:
+            g.write(rand_file)
+        assert error.value.errno == errno.ENODEV
+
+        f.close()
+        g.close()
+
+        # Short wait needed to allow file to close before pulling driver
+        sleep(1)
+
+        p = subprocess.Popen(('modprobe', '-r', 'intel_sdsi'))
+        p.wait()
+        p = subprocess.Popen(('modprobe', '-r', 'intel_vsec'))
+        p.wait()
+        p = subprocess.Popen(('modprobe', 'intel_vsec'))
+        p.wait()
+
+        # Short wait needed to allow driver time to get inserted
+        # before continuing tests
+        sleep(1)
+
+    def test_memory_leak(self, socket):
+        if not kmemleak_enabled:
+            pytest.skip("kmemleak not enabled in kernel")
+
+        dev_name = DEV_PREFIX + '.' + str(socket)
+        driver_dir = CLASS_DIR + '/' + dev_name + "/driver/"
+
+        with open(driver_dir + 'unbind', 'w') as k:
+            print(dev_name, file = k)
+
+        sleep(1)
+
+        subprocess.check_output(('modprobe', '-r', 'intel_sdsi'))
+        subprocess.check_output(('modprobe', '-r', 'intel_vsec'))
+
+        with open('/sys/kernel/debug/kmemleak', 'w') as f:
+            print('scan', file = f)
+        sleep(5)
+
+        assert os.stat('/sys/kernel/debug/kmemleak').st_size == 0
+
+        subprocess.check_output(('modprobe', 'intel_vsec'))
+        sleep(1)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH V5 1/3] platform/x86: Add Intel Software Defined Silicon driver
  2022-02-04  5:30 ` [PATCH V5 1/3] platform/x86: Add Intel Software Defined Silicon driver David E. Box
@ 2022-02-04  6:57   ` Greg KH
  2022-02-04 10:14   ` Joe Perches
  1 sibling, 0 replies; 10+ messages in thread
From: Greg KH @ 2022-02-04  6:57 UTC (permalink / raw)
  To: David E. Box
  Cc: hdegoede, andriy.shevchenko, srinivas.pandruvada, mgross,
	linux-kernel, platform-driver-x86, Mark Gross

On Thu, Feb 03, 2022 at 09:30:44PM -0800, David E. Box wrote:
> Intel Software Defined Silicon (SDSi) is a post manufacturing mechanism for
> activating additional silicon features. Features are enabled through a
> license activation process.  The SDSi driver provides a per socket, sysfs
> attribute interface for applications to perform 3 main provisioning
> functions:
> 
> 1. Provision an Authentication Key Certificate (AKC), a key written to
>    internal NVRAM that is used to authenticate a capability specific
>    activation payload.
> 
> 2. Provision a Capability Activation Payload (CAP), a token authenticated
>    using the AKC and applied to the CPU configuration to activate a new
>    feature.
> 
> 3. Read the SDSi State Certificate, containing the CPU configuration
>    state.
> 
> The operations perform function specific mailbox commands that forward the
> requests to SDSi hardware to perform authentication of the payloads and
> enable the silicon configuration (to be made available after power
> cycling).
> 
> The SDSi device itself is enumerated as an auxiliary device from the
> intel_vsec driver and as such has a build dependency on CONFIG_INTEL_VSEC.
> 
> Link: https://github.com/intel/intel-sdsi
> Signed-off-by: David E. Box <david.e.box@linux.intel.com>
> Reviewed-by: Mark Gross <markgross@kernel.org>
> ---
> V5
>   - Update kernel version to 5.18 in API doc and copyrights to 2022.
>   - Remove unneeded prototypes.
>   - In binary attribute handlers where ret is only used for errors,
>     replace,
>               return (ret < 0) ? ret : size;
>     with,
>               return ret ?: size;

That's horrible, please no.

Will you remember what this does in 5 years when you have to look at it
again?  Spell it out, this saves nothing in runtime or code size:
	if (ret < 0)
		return ret;
	return size;

There, obvious, simple, and can be read by anyone.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH V5 1/3] platform/x86: Add Intel Software Defined Silicon driver
  2022-02-04  5:30 ` [PATCH V5 1/3] platform/x86: Add Intel Software Defined Silicon driver David E. Box
  2022-02-04  6:57   ` Greg KH
@ 2022-02-04 10:14   ` Joe Perches
  2022-02-04 13:23     ` David E. Box
  1 sibling, 1 reply; 10+ messages in thread
From: Joe Perches @ 2022-02-04 10:14 UTC (permalink / raw)
  To: David E. Box, hdegoede, gregkh, andriy.shevchenko,
	srinivas.pandruvada, mgross
  Cc: linux-kernel, platform-driver-x86, Mark Gross

On Thu, 2022-02-03 at 21:30 -0800, David E. Box wrote:
> Intel Software Defined Silicon (SDSi) is a post manufacturing mechanism for
> activating additional silicon features. Features are enabled through a
> license activation process.

Why isn't this a user process and not a kernel one?

> V5
>   - Update kernel version to 5.18 in API doc and copyrights to 2022.
>   - Remove unneeded prototypes.
>   - In binary attribute handlers where ret is only used for errors,
>     replace,
>               return (ret < 0) ? ret : size;
>     with,
>               return ret ?: size;

I think this style overly tricky.

Why not the canonical:

	if (ret < 0)
		return ret;

	return size;



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH V5 1/3] platform/x86: Add Intel Software Defined Silicon driver
  2022-02-04 10:14   ` Joe Perches
@ 2022-02-04 13:23     ` David E. Box
  2022-02-04 13:43       ` Greg KH
  2022-02-04 14:01       ` Joe Perches
  0 siblings, 2 replies; 10+ messages in thread
From: David E. Box @ 2022-02-04 13:23 UTC (permalink / raw)
  To: Joe Perches, hdegoede, gregkh, andriy.shevchenko,
	srinivas.pandruvada, mgross
  Cc: linux-kernel, platform-driver-x86, Mark Gross

On Fri, 2022-02-04 at 02:14 -0800, Joe Perches wrote:
> On Thu, 2022-02-03 at 21:30 -0800, David E. Box wrote:
> > Intel Software Defined Silicon (SDSi) is a post manufacturing mechanism for
> > activating additional silicon features. Features are enabled through a
> > license activation process.
> 
> Why isn't this a user process and not a kernel one?

This is a mechanism for provisioning CPU features during runtime. It requires a
driver to access the functionality. That functionality is discovered on a multi
functional PCI device that is owned by the upstream intel_vsec driver.

> 
> > V5
> >   - Update kernel version to 5.18 in API doc and copyrights to 2022.
> >   - Remove unneeded prototypes.
> >   - In binary attribute handlers where ret is only used for errors,
> >     replace,
> >               return (ret < 0) ? ret : size;
> >     with,
> >               return ret ?: size;
> 
> I think this style overly tricky.
> 
> Why not the canonical:
> 
> 	if (ret < 0)
> 		return ret;
> 
> 	return size;

I can see not using the 2 parameter shortcut of the ternary operator, but the
regular 3 parameter expression is easy to read for simple operations.

David

> 
> 


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH V5 1/3] platform/x86: Add Intel Software Defined Silicon driver
  2022-02-04 13:23     ` David E. Box
@ 2022-02-04 13:43       ` Greg KH
  2022-02-04 14:01       ` Joe Perches
  1 sibling, 0 replies; 10+ messages in thread
From: Greg KH @ 2022-02-04 13:43 UTC (permalink / raw)
  To: David E. Box
  Cc: Joe Perches, hdegoede, andriy.shevchenko, srinivas.pandruvada,
	mgross, linux-kernel, platform-driver-x86, Mark Gross

On Fri, Feb 04, 2022 at 05:23:07AM -0800, David E. Box wrote:
> On Fri, 2022-02-04 at 02:14 -0800, Joe Perches wrote:
> > On Thu, 2022-02-03 at 21:30 -0800, David E. Box wrote:
> > > Intel Software Defined Silicon (SDSi) is a post manufacturing mechanism for
> > > activating additional silicon features. Features are enabled through a
> > > license activation process.
> > 
> > Why isn't this a user process and not a kernel one?
> 
> This is a mechanism for provisioning CPU features during runtime. It requires a
> driver to access the functionality. That functionality is discovered on a multi
> functional PCI device that is owned by the upstream intel_vsec driver.
> 
> > 
> > > V5
> > >   - Update kernel version to 5.18 in API doc and copyrights to 2022.
> > >   - Remove unneeded prototypes.
> > >   - In binary attribute handlers where ret is only used for errors,
> > >     replace,
> > >               return (ret < 0) ? ret : size;
> > >     with,
> > >               return ret ?: size;
> > 
> > I think this style overly tricky.
> > 
> > Why not the canonical:
> > 
> > 	if (ret < 0)
> > 		return ret;
> > 
> > 	return size;
> 
> I can see not using the 2 parameter shortcut of the ternary operator, but the
> regular 3 parameter expression is easy to read for simple operations.

Not always.  Spell it out please and be obvious.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH V5 1/3] platform/x86: Add Intel Software Defined Silicon driver
  2022-02-04 13:23     ` David E. Box
  2022-02-04 13:43       ` Greg KH
@ 2022-02-04 14:01       ` Joe Perches
  2022-02-04 17:01         ` David E. Box
  1 sibling, 1 reply; 10+ messages in thread
From: Joe Perches @ 2022-02-04 14:01 UTC (permalink / raw)
  To: david.e.box, hdegoede, gregkh, andriy.shevchenko,
	srinivas.pandruvada, mgross
  Cc: linux-kernel, platform-driver-x86, Mark Gross

On Fri, 2022-02-04 at 05:23 -0800, David E. Box wrote:
> On Fri, 2022-02-04 at 02:14 -0800, Joe Perches wrote:
> > On Thu, 2022-02-03 at 21:30 -0800, David E. Box wrote:
[]
> > >   - In binary attribute handlers where ret is only used for errors,
> > >     replace,
> > >               return (ret < 0) ? ret : size;
> > >     with,
> > >               return ret ?: size;
> > 
> > I think this style overly tricky.
> > 
> > Why not the canonical:
> > 
> > 	if (ret < 0)
> > 		return ret;
> > 
> > 	return size;
> 
> I can see not using the 2 parameter shortcut of the ternary operator, but the
> regular 3 parameter expression is easy to read for simple operations.

The issue to me is it combines an error test and error return
with the common return.

it's also being used and avoided / naked with the similar

	return min(ret, size);

https://lore.kernel.org/lkml/20211116121014.1675-1-zhaoxiao@uniontech.com/T/



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH V5 1/3] platform/x86: Add Intel Software Defined Silicon driver
  2022-02-04 14:01       ` Joe Perches
@ 2022-02-04 17:01         ` David E. Box
  0 siblings, 0 replies; 10+ messages in thread
From: David E. Box @ 2022-02-04 17:01 UTC (permalink / raw)
  To: Joe Perches, hdegoede, gregkh, andriy.shevchenko,
	srinivas.pandruvada, mgross
  Cc: linux-kernel, platform-driver-x86, Mark Gross

On Fri, 2022-02-04 at 06:01 -0800, Joe Perches wrote:
> On Fri, 2022-02-04 at 05:23 -0800, David E. Box wrote:
> > On Fri, 2022-02-04 at 02:14 -0800, Joe Perches wrote:
> > > On Thu, 2022-02-03 at 21:30 -0800, David E. Box wrote:
> []
> > > >   - In binary attribute handlers where ret is only used for errors,
> > > >     replace,
> > > >               return (ret < 0) ? ret : size;
> > > >     with,
> > > >               return ret ?: size;
> > > 
> > > I think this style overly tricky.
> > > 
> > > Why not the canonical:
> > > 
> > > 	if (ret < 0)
> > > 		return ret;
> > > 
> > > 	return size;
> > 
> > I can see not using the 2 parameter shortcut of the ternary operator, but
> > the
> > regular 3 parameter expression is easy to read for simple operations.
> 
> The issue to me is it combines an error test and error return
> with the common return.

Ah, okay.

> 
> it's also being used and avoided / naked with the similar
> 
> 	return min(ret, size);
> 
> https://lore.kernel.org/lkml/20211116121014.1675-1-zhaoxiao@uniontech.com/T/

Thanks.


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2022-02-04 17:01 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-04  5:30 [PATCH V5 0/3] Intel Software Defined Silicon David E. Box
2022-02-04  5:30 ` [PATCH V5 1/3] platform/x86: Add Intel Software Defined Silicon driver David E. Box
2022-02-04  6:57   ` Greg KH
2022-02-04 10:14   ` Joe Perches
2022-02-04 13:23     ` David E. Box
2022-02-04 13:43       ` Greg KH
2022-02-04 14:01       ` Joe Perches
2022-02-04 17:01         ` David E. Box
2022-02-04  5:30 ` [PATCH V5 2/3] tools arch x86: Add Intel SDSi provisiong tool David E. Box
2022-02-04  5:30 ` [PATCH V5 3/3] selftests: sdsi: test sysfs setup David E. Box

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.