[PATCH 10/14] peci: Add peci-cpu driver

Zev Weiss zweiss at equinix.com
Tue Jul 27 14:33:58 PDT 2021


On Mon, Jul 12, 2021 at 05:04:43PM CDT, Iwona Winiarska wrote:
>PECI is an interface that may be used by different types of devices.
>Here we're adding a peci-cpu driver compatible with Intel processors.
>The driver is responsible for handling auxiliary devices that can
>subsequently be used by other drivers (e.g. hwmons).
>
>Signed-off-by: Iwona Winiarska <iwona.winiarska at intel.com>
>Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
>---
> MAINTAINERS              |   1 +
> drivers/peci/Kconfig     |  15 ++
> drivers/peci/Makefile    |   2 +
> drivers/peci/cpu.c       | 347 +++++++++++++++++++++++++++++++++++++++
> drivers/peci/device.c    |   1 +
> drivers/peci/internal.h  |  27 +++
> drivers/peci/request.c   | 211 ++++++++++++++++++++++++
> include/linux/peci-cpu.h |  38 +++++
> include/linux/peci.h     |   8 -
> 9 files changed, 642 insertions(+), 8 deletions(-)
> create mode 100644 drivers/peci/cpu.c
> create mode 100644 include/linux/peci-cpu.h
>
>diff --git a/MAINTAINERS b/MAINTAINERS
>index 4ba874afa2fa..f47b5f634293 100644
>--- a/MAINTAINERS
>+++ b/MAINTAINERS
>@@ -14511,6 +14511,7 @@ L:	openbmc at lists.ozlabs.org (moderated for non-subscribers)
> S:	Supported
> F:	Documentation/devicetree/bindings/peci/
> F:	drivers/peci/
>+F:	include/linux/peci-cpu.h
> F:	include/linux/peci.h
>
> PENSANDO ETHERNET DRIVERS
>diff --git a/drivers/peci/Kconfig b/drivers/peci/Kconfig
>index 27c31535843c..9e17e06fda90 100644
>--- a/drivers/peci/Kconfig
>+++ b/drivers/peci/Kconfig
>@@ -16,6 +16,21 @@ menuconfig PECI
>
> if PECI
>
>+config PECI_CPU
>+	tristate "PECI CPU"
>+	select AUXILIARY_BUS
>+	help
>+	  This option enables peci-cpu driver for Intel processors. It is
>+	  responsible for creating auxiliary devices that can subsequently
>+	  be used by other drivers in order to perform various
>+	  functionalities such as e.g. temperature monitoring.
>+
>+	  Additional drivers must be enabled in order to use the functionality
>+	  of the device.
>+
>+	  This driver can also be built as a module. If so, the module
>+	  will be called peci-cpu.
>+
> source "drivers/peci/controller/Kconfig"
>
> endif # PECI
>diff --git a/drivers/peci/Makefile b/drivers/peci/Makefile
>index 917f689e147a..7de18137e738 100644
>--- a/drivers/peci/Makefile
>+++ b/drivers/peci/Makefile
>@@ -3,6 +3,8 @@
> # Core functionality
> peci-y := core.o request.o device.o sysfs.o
> obj-$(CONFIG_PECI) += peci.o
>+peci-cpu-y := cpu.o
>+obj-$(CONFIG_PECI_CPU) += peci-cpu.o
>
> # Hardware specific bus drivers
> obj-y += controller/
>diff --git a/drivers/peci/cpu.c b/drivers/peci/cpu.c
>new file mode 100644
>index 000000000000..8d130a9a71ad
>--- /dev/null
>+++ b/drivers/peci/cpu.c
>@@ -0,0 +1,347 @@
>+// SPDX-License-Identifier: GPL-2.0-only
>+// Copyright (c) 2021 Intel Corporation
>+
>+#include <linux/auxiliary_bus.h>
>+#include <linux/module.h>
>+#include <linux/peci.h>
>+#include <linux/peci-cpu.h>
>+#include <linux/slab.h>
>+#include <linux/x86/intel-family.h>
>+
>+#include "internal.h"
>+
>+/**
>+ * peci_temp_read() - read the maximum die temperature from PECI target device
>+ * @device: PECI device to which request is going to be sent
>+ * @temp_raw: where to store the read temperature
>+ *
>+ * It uses GetTemp PECI command.
>+ *
>+ * Return: 0 if succeeded, other values in case errors.
>+ */
>+int peci_temp_read(struct peci_device *device, s16 *temp_raw)
>+{
>+	struct peci_request *req;
>+
>+	req = peci_get_temp(device);
>+	if (IS_ERR(req))
>+		return PTR_ERR(req);
>+
>+	*temp_raw = peci_request_data_temp(req);
>+
>+	peci_request_free(req);
>+
>+	return 0;
>+}
>+EXPORT_SYMBOL_NS_GPL(peci_temp_read, PECI_CPU);
>+
>+/**
>+ * peci_pcs_read() - read PCS register
>+ * @device: PECI device to which request is going to be sent
>+ * @index: PCS index
>+ * @param: PCS parameter
>+ * @data: where to store the read data
>+ *
>+ * It uses RdPkgConfig PECI command.
>+ *
>+ * Return: 0 if succeeded, other values in case errors.
>+ */
>+int peci_pcs_read(struct peci_device *device, u8 index, u16 param, u32 *data)
>+{
>+	struct peci_request *req;
>+	int ret;
>+
>+	req = peci_pkg_cfg_readl(device, index, param);
>+	if (IS_ERR(req))
>+		return PTR_ERR(req);
>+
>+	ret = peci_request_status(req);
>+	if (ret)
>+		goto out_req_free;
>+
>+	*data = peci_request_data_readl(req);
>+out_req_free:

As in patch 9, this control flow could be rewritten as just

	if (!ret)
		*data = peci_request_data_readl(req);

and avoid the goto.

>+	peci_request_free(req);
>+
>+	return ret;
>+}
>+EXPORT_SYMBOL_NS_GPL(peci_pcs_read, PECI_CPU);
>+
>+/**
>+ * peci_pci_local_read() - read 32-bit memory location using raw address
>+ * @device: PECI device to which request is going to be sent
>+ * @bus: bus
>+ * @dev: device
>+ * @func: function
>+ * @reg: register
>+ * @data: where to store the read data
>+ *
>+ * It uses RdPCIConfigLocal PECI command.
>+ *
>+ * Return: 0 if succeeded, other values in case errors.
>+ */
>+int peci_pci_local_read(struct peci_device *device, u8 bus, u8 dev, u8 func,
>+			u16 reg, u32 *data)
>+{
>+	struct peci_request *req;
>+	int ret;
>+
>+	req = peci_pci_cfg_local_readl(device, bus, dev, func, reg);
>+	if (IS_ERR(req))
>+		return PTR_ERR(req);
>+
>+	ret = peci_request_status(req);
>+	if (ret)
>+		goto out_req_free;
>+
>+	*data = peci_request_data_readl(req);
>+out_req_free:
>+	peci_request_free(req);
>+
>+	return ret;
>+}
>+EXPORT_SYMBOL_NS_GPL(peci_pci_local_read, PECI_CPU);
>+
>+/**
>+ * peci_ep_pci_local_read() - read 32-bit memory location using raw address
>+ * @device: PECI device to which request is going to be sent
>+ * @seg: PCI segment
>+ * @bus: bus
>+ * @dev: device
>+ * @func: function
>+ * @reg: register
>+ * @data: where to store the read data
>+ *
>+ * Like &peci_pci_local_read, but it uses RdEndpointConfig PECI command.
>+ *
>+ * Return: 0 if succeeded, other values in case errors.
>+ */
>+int peci_ep_pci_local_read(struct peci_device *device, u8 seg,
>+			   u8 bus, u8 dev, u8 func, u16 reg, u32 *data)
>+{
>+	struct peci_request *req;
>+	int ret;
>+
>+	req = peci_ep_pci_cfg_local_readl(device, seg, bus, dev, func, reg);
>+	if (IS_ERR(req))
>+		return PTR_ERR(req);
>+
>+	ret = peci_request_status(req);
>+	if (ret)
>+		goto out_req_free;
>+
>+	*data = peci_request_data_readl(req);
>+out_req_free:
>+	peci_request_free(req);
>+
>+	return ret;
>+}
>+EXPORT_SYMBOL_NS_GPL(peci_ep_pci_local_read, PECI_CPU);
>+
>+/**
>+ * peci_mmio_read() - read 32-bit memory location using 64-bit bar offset address
>+ * @device: PECI device to which request is going to be sent
>+ * @bar: PCI bar
>+ * @seg: PCI segment
>+ * @bus: bus
>+ * @dev: device
>+ * @func: function
>+ * @address: 64-bit MMIO address
>+ * @data: where to store the read data
>+ *
>+ * It uses RdEndpointConfig PECI command.
>+ *
>+ * Return: 0 if succeeded, other values in case errors.
>+ */
>+int peci_mmio_read(struct peci_device *device, u8 bar, u8 seg,
>+		   u8 bus, u8 dev, u8 func, u64 address, u32 *data)
>+{
>+	struct peci_request *req;
>+	int ret;
>+
>+	req = peci_ep_mmio64_readl(device, bar, seg, bus, dev, func, address);
>+	if (IS_ERR(req))
>+		return PTR_ERR(req);
>+
>+	ret = peci_request_status(req);
>+	if (ret)
>+		goto out_req_free;
>+
>+	*data = peci_request_data_readl(req);
>+out_req_free:
>+	peci_request_free(req);
>+
>+	return ret;
>+}
>+EXPORT_SYMBOL_NS_GPL(peci_mmio_read, PECI_CPU);
>+
>+struct peci_cpu {
>+	struct peci_device *device;
>+	const struct peci_device_id *id;
>+	struct auxiliary_device **aux_devices;

Given that the size for this allocation is a compile-time constant,
should we just inline this as 'struct auxiliary_device
*aux_devices[ARRAY_SIZE(type)]' and avoid some kmalloc work in
peci_cpu_add_adevices()?

>+};
>+
>+static const char * const type[] = {

A slightly more descriptive name might be good -- maybe something like
'peci_adevice_types'?

>+	"cputemp",
>+	"dimmtemp",
>+};
>+
>+static void adev_release(struct device *dev)
>+{
>+	struct auxiliary_device *adev = to_auxiliary_dev(dev);
>+
>+	kfree(adev->name);
>+	kfree(adev);
>+}
>+
>+static struct auxiliary_device *add_adev(struct peci_cpu *priv, int idx)
>+{
>+	struct peci_controller *controller = priv->device->controller;
>+	struct auxiliary_device *adev;
>+	const char *name;
>+	int ret;
>+
>+	adev = kzalloc(sizeof(*adev), GFP_KERNEL);
>+	if (!adev)
>+		return ERR_PTR(-ENOMEM);
>+
>+	name = kasprintf(GFP_KERNEL, "%s.%s", type[idx], (const char *)priv->id->data);
>+	if (!name) {
>+		ret = -ENOMEM;
>+		goto free_adev;
>+	}
>+
>+	adev->name = name;
>+	adev->dev.parent = &priv->device->dev;
>+	adev->dev.release = adev_release;
>+	adev->id = (controller->id << 16) | (priv->device->addr);
>+
>+	ret = auxiliary_device_init(adev);
>+	if (ret)
>+		goto free_name;
>+
>+	ret = auxiliary_device_add(adev);
>+	if (ret) {
>+		auxiliary_device_uninit(adev);
>+		return ERR_PTR(ret);
>+	}
>+
>+	return adev;
>+
>+free_name:
>+	kfree(name);
>+free_adev:
>+	kfree(adev);
>+	return ERR_PTR(ret);
>+}
>+
>+static void del_adev(struct auxiliary_device *adev)
>+{
>+	auxiliary_device_delete(adev);
>+	auxiliary_device_uninit(adev);
>+}
>+
>+static int peci_cpu_add_adevices(struct peci_cpu *priv)
>+{
>+	struct device *dev = &priv->device->dev;
>+	struct auxiliary_device *adev;
>+	int i;
>+
>+	priv->aux_devices = devm_kcalloc(dev, ARRAY_SIZE(type),
>+					 sizeof(*priv->aux_devices),
>+					 GFP_KERNEL);
>+	if (!priv->aux_devices)
>+		return -ENOMEM;
>+
>+	for (i = 0; i < ARRAY_SIZE(type); i++) {
>+		adev = add_adev(priv, i);
>+		if (IS_ERR(adev)) {
>+			dev_warn(dev, "Failed to add PECI auxiliary: %s, ret = %ld\n",
>+				 type[i], PTR_ERR(adev));
>+			continue;
>+		}
>+
>+		priv->aux_devices[i] = adev;
>+	}
>+	return 0;
>+}
>+
>+static int
>+peci_cpu_probe(struct peci_device *device, const struct peci_device_id *id)
>+{
>+	struct device *dev = &device->dev;
>+	struct peci_cpu *priv;
>+
>+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
>+	if (!priv)
>+		return -ENOMEM;
>+
>+	dev_set_drvdata(dev, priv);
>+	priv->device = device;
>+	priv->id = id;
>+
>+	return peci_cpu_add_adevices(priv);
>+}
>+
>+static void peci_cpu_remove(struct peci_device *device)
>+{
>+	struct peci_cpu *priv = dev_get_drvdata(&device->dev);
>+	int i;
>+
>+	for (i = 0; i < ARRAY_SIZE(type); i++) {
>+		struct auxiliary_device *adev = priv->aux_devices[i];
>+
>+		if (adev)
>+			del_adev(adev);
>+	}
>+}
>+
>+static const struct peci_device_id peci_cpu_device_ids[] = {
>+	{ /* Haswell Xeon */
>+		.family	= 6,
>+		.model	= INTEL_FAM6_HASWELL_X,
>+		.data	= "hsx",
>+	},
>+	{ /* Broadwell Xeon */
>+		.family	= 6,
>+		.model	= INTEL_FAM6_BROADWELL_X,
>+		.data	= "bdx",
>+	},
>+	{ /* Broadwell Xeon D */
>+		.family	= 6,
>+		.model	= INTEL_FAM6_BROADWELL_D,
>+		.data	= "skxd",
>+	},
>+	{ /* Skylake Xeon */
>+		.family	= 6,
>+		.model	= INTEL_FAM6_SKYLAKE_X,
>+		.data	= "skx",
>+	},
>+	{ /* Icelake Xeon */
>+		.family	= 6,
>+		.model	= INTEL_FAM6_ICELAKE_X,
>+		.data	= "icx",
>+	},
>+	{ /* Icelake Xeon D */
>+		.family	= 6,
>+		.model	= INTEL_FAM6_ICELAKE_D,
>+		.data	= "icxd",
>+	},
>+	{ }
>+};
>+MODULE_DEVICE_TABLE(peci, peci_cpu_device_ids);
>+
>+static struct peci_driver peci_cpu_driver = {
>+	.probe		= peci_cpu_probe,
>+	.remove		= peci_cpu_remove,
>+	.id_table	= peci_cpu_device_ids,
>+	.driver		= {
>+		.name		= "peci-cpu",
>+	},
>+};
>+module_peci_driver(peci_cpu_driver);
>+
>+MODULE_AUTHOR("Iwona Winiarska <iwona.winiarska at intel.com>");
>+MODULE_DESCRIPTION("PECI CPU driver");
>+MODULE_LICENSE("GPL");
>+MODULE_IMPORT_NS(PECI);
>diff --git a/drivers/peci/device.c b/drivers/peci/device.c
>index 8c4bd1ebbc29..c278c9ea166c 100644
>--- a/drivers/peci/device.c
>+++ b/drivers/peci/device.c
>@@ -3,6 +3,7 @@
>
> #include <linux/bitfield.h>
> #include <linux/peci.h>
>+#include <linux/peci-cpu.h>
> #include <linux/slab.h>
> #include <linux/x86/cpu.h>
>
>diff --git a/drivers/peci/internal.h b/drivers/peci/internal.h
>index c891c93e077a..1d39483a8acf 100644
>--- a/drivers/peci/internal.h
>+++ b/drivers/peci/internal.h
>@@ -21,6 +21,7 @@ void peci_request_free(struct peci_request *req);
>
> int peci_request_status(struct peci_request *req);
> u64 peci_request_data_dib(struct peci_request *req);
>+s16 peci_request_data_temp(struct peci_request *req);
>
> u8 peci_request_data_readb(struct peci_request *req);
> u16 peci_request_data_readw(struct peci_request *req);
>@@ -35,6 +36,32 @@ struct peci_request *peci_pkg_cfg_readw(struct peci_device *device, u8 index, u1
> struct peci_request *peci_pkg_cfg_readl(struct peci_device *device, u8 index, u16 param);
> struct peci_request *peci_pkg_cfg_readq(struct peci_device *device, u8 index, u16 param);
>
>+struct peci_request *peci_pci_cfg_local_readb(struct peci_device *device,
>+					      u8 bus, u8 dev, u8 func, u16 reg);
>+struct peci_request *peci_pci_cfg_local_readw(struct peci_device *device,
>+					      u8 bus, u8 dev, u8 func, u16 reg);
>+struct peci_request *peci_pci_cfg_local_readl(struct peci_device *device,
>+					      u8 bus, u8 dev, u8 func, u16 reg);
>+
>+struct peci_request *peci_ep_pci_cfg_local_readb(struct peci_device *device, u8 seg,
>+						 u8 bus, u8 dev, u8 func, u16 reg);
>+struct peci_request *peci_ep_pci_cfg_local_readw(struct peci_device *device, u8 seg,
>+						 u8 bus, u8 dev, u8 func, u16 reg);
>+struct peci_request *peci_ep_pci_cfg_local_readl(struct peci_device *device, u8 seg,
>+						 u8 bus, u8 dev, u8 func, u16 reg);
>+
>+struct peci_request *peci_ep_pci_cfg_readb(struct peci_device *device, u8 seg,
>+					   u8 bus, u8 dev, u8 func, u16 reg);
>+struct peci_request *peci_ep_pci_cfg_readw(struct peci_device *device, u8 seg,
>+					   u8 bus, u8 dev, u8 func, u16 reg);
>+struct peci_request *peci_ep_pci_cfg_readl(struct peci_device *device, u8 seg,
>+					   u8 bus, u8 dev, u8 func, u16 reg);
>+
>+struct peci_request *peci_ep_mmio32_readl(struct peci_device *device, u8 bar, u8 seg,
>+					  u8 bus, u8 dev, u8 func, u64 offset);
>+
>+struct peci_request *peci_ep_mmio64_readl(struct peci_device *device, u8 bar, u8 seg,
>+					  u8 bus, u8 dev, u8 func, u64 offset);
> /**
>  * struct peci_device_id - PECI device data to match
>  * @data: pointer to driver private data specific to device
>diff --git a/drivers/peci/request.c b/drivers/peci/request.c
>index 48354455b554..c5d39f7e8142 100644
>--- a/drivers/peci/request.c
>+++ b/drivers/peci/request.c
>@@ -3,6 +3,7 @@
>
> #include <linux/bug.h>
> #include <linux/export.h>
>+#include <linux/pci.h>
> #include <linux/peci.h>
> #include <linux/slab.h>
> #include <linux/types.h>
>@@ -15,6 +16,10 @@
> #define  PECI_GET_DIB_WR_LEN		1
> #define  PECI_GET_DIB_RD_LEN		8
>
>+#define PECI_GET_TEMP_CMD		0x01
>+#define  PECI_GET_TEMP_WR_LEN		1
>+#define  PECI_GET_TEMP_RD_LEN		2
>+
> #define PECI_RDPKGCFG_CMD		0xa1
> #define  PECI_RDPKGCFG_WRITE_LEN	5
> #define  PECI_RDPKGCFG_READ_LEN_BASE	1
>@@ -22,6 +27,44 @@
> #define  PECI_WRPKGCFG_WRITE_LEN_BASE	6
> #define  PECI_WRPKGCFG_READ_LEN		1
>
>+#define PECI_RDIAMSR_CMD		0xb1
>+#define  PECI_RDIAMSR_WRITE_LEN		5
>+#define  PECI_RDIAMSR_READ_LEN		9
>+#define PECI_WRIAMSR_CMD		0xb5
>+#define PECI_RDIAMSREX_CMD		0xd1
>+#define  PECI_RDIAMSREX_WRITE_LEN	6
>+#define  PECI_RDIAMSREX_READ_LEN	9
>+
>+#define PECI_RDPCICFG_CMD		0x61
>+#define  PECI_RDPCICFG_WRITE_LEN	6
>+#define  PECI_RDPCICFG_READ_LEN		5
>+#define  PECI_RDPCICFG_READ_LEN_MAX	24
>+#define PECI_WRPCICFG_CMD		0x65
>+
>+#define PECI_RDPCICFGLOCAL_CMD			0xe1
>+#define  PECI_RDPCICFGLOCAL_WRITE_LEN		5
>+#define  PECI_RDPCICFGLOCAL_READ_LEN_BASE	1
>+#define PECI_WRPCICFGLOCAL_CMD			0xe5
>+#define  PECI_WRPCICFGLOCAL_WRITE_LEN_BASE	6
>+#define  PECI_WRPCICFGLOCAL_READ_LEN		1
>+
>+#define PECI_ENDPTCFG_TYPE_LOCAL_PCI		0x03
>+#define PECI_ENDPTCFG_TYPE_PCI			0x04
>+#define PECI_ENDPTCFG_TYPE_MMIO			0x05
>+#define PECI_ENDPTCFG_ADDR_TYPE_PCI		0x04
>+#define PECI_ENDPTCFG_ADDR_TYPE_MMIO_D		0x05
>+#define PECI_ENDPTCFG_ADDR_TYPE_MMIO_Q		0x06
>+#define PECI_RDENDPTCFG_CMD			0xc1
>+#define  PECI_RDENDPTCFG_PCI_WRITE_LEN		12
>+#define  PECI_RDENDPTCFG_MMIO_D_WRITE_LEN	14
>+#define  PECI_RDENDPTCFG_MMIO_Q_WRITE_LEN	18
>+#define  PECI_RDENDPTCFG_READ_LEN_BASE		1
>+#define PECI_WRENDPTCFG_CMD			0xc5
>+#define  PECI_WRENDPTCFG_PCI_WRITE_LEN_BASE	13
>+#define  PECI_WRENDPTCFG_MMIO_D_WRITE_LEN_BASE	15
>+#define  PECI_WRENDPTCFG_MMIO_Q_WRITE_LEN_BASE	19
>+#define  PECI_WRENDPTCFG_READ_LEN		1
>+
> /* Device Specific Completion Code (CC) Definition */
> #define PECI_CC_SUCCESS				0x40
> #define PECI_CC_NEED_RETRY			0x80
>@@ -223,6 +266,27 @@ struct peci_request *peci_get_dib(struct peci_device *device)
> }
> EXPORT_SYMBOL_NS_GPL(peci_get_dib, PECI);
>
>+struct peci_request *peci_get_temp(struct peci_device *device)
>+{
>+	struct peci_request *req;
>+	int ret;
>+
>+	req = peci_request_alloc(device, PECI_GET_TEMP_WR_LEN, PECI_GET_TEMP_RD_LEN);
>+	if (!req)
>+		return ERR_PTR(-ENOMEM);
>+
>+	req->tx.buf[0] = PECI_GET_TEMP_CMD;
>+
>+	ret = peci_request_xfer(req);
>+	if (ret) {
>+		peci_request_free(req);
>+		return ERR_PTR(ret);
>+	}
>+
>+	return req;
>+}
>+EXPORT_SYMBOL_NS_GPL(peci_get_temp, PECI);
>+
> static struct peci_request *
> __pkg_cfg_read(struct peci_device *device, u8 index, u16 param, u8 len)
> {
>@@ -248,6 +312,108 @@ __pkg_cfg_read(struct peci_device *device, u8 index, u16 param, u8 len)
> 	return req;
> }
>
>+static u32 __get_pci_addr(u8 bus, u8 dev, u8 func, u16 reg)
>+{
>+	return reg | PCI_DEVID(bus, PCI_DEVFN(dev, func)) << 12;
>+}
>+
>+static struct peci_request *
>+__pci_cfg_local_read(struct peci_device *device, u8 bus, u8 dev, u8 func, u16 reg, u8 len)
>+{
>+	struct peci_request *req;
>+	u32 pci_addr;
>+	int ret;
>+
>+	req = peci_request_alloc(device, PECI_RDPCICFGLOCAL_WRITE_LEN,
>+				 PECI_RDPCICFGLOCAL_READ_LEN_BASE + len);
>+	if (!req)
>+		return ERR_PTR(-ENOMEM);
>+
>+	pci_addr = __get_pci_addr(bus, dev, func, reg);
>+
>+	req->tx.buf[0] = PECI_RDPCICFGLOCAL_CMD;
>+	req->tx.buf[1] = 0;
>+	put_unaligned_le24(pci_addr, &req->tx.buf[2]);
>+
>+	ret = peci_request_xfer_retry(req);
>+	if (ret) {
>+		peci_request_free(req);
>+		return ERR_PTR(ret);
>+	}
>+
>+	return req;
>+}
>+
>+static struct peci_request *
>+__ep_pci_cfg_read(struct peci_device *device, u8 msg_type, u8 seg,
>+		  u8 bus, u8 dev, u8 func, u16 reg, u8 len)
>+{
>+	struct peci_request *req;
>+	u32 pci_addr;
>+	int ret;
>+
>+	req = peci_request_alloc(device, PECI_RDENDPTCFG_PCI_WRITE_LEN,
>+				 PECI_RDENDPTCFG_READ_LEN_BASE + len);
>+	if (!req)
>+		return ERR_PTR(-ENOMEM);
>+
>+	pci_addr = __get_pci_addr(bus, dev, func, reg);
>+
>+	req->tx.buf[0] = PECI_RDENDPTCFG_CMD;
>+	req->tx.buf[1] = 0;
>+	req->tx.buf[2] = msg_type;
>+	req->tx.buf[3] = 0;
>+	req->tx.buf[4] = 0;
>+	req->tx.buf[5] = 0;
>+	req->tx.buf[6] = PECI_ENDPTCFG_ADDR_TYPE_PCI;
>+	req->tx.buf[7] = seg; /* PCI Segment */
>+	put_unaligned_le32(pci_addr, &req->tx.buf[8]);
>+
>+	ret = peci_request_xfer_retry(req);
>+	if (ret) {
>+		peci_request_free(req);
>+		return ERR_PTR(ret);
>+	}
>+
>+	return req;
>+}
>+
>+static struct peci_request *
>+__ep_mmio_read(struct peci_device *device, u8 bar, u8 addr_type, u8 seg,
>+	       u8 bus, u8 dev, u8 func, u64 offset, u8 tx_len, u8 len)
>+{
>+	struct peci_request *req;
>+	int ret;
>+
>+	req = peci_request_alloc(device, tx_len, PECI_RDENDPTCFG_READ_LEN_BASE + len);
>+	if (!req)
>+		return ERR_PTR(-ENOMEM);
>+
>+	req->tx.buf[0] = PECI_RDENDPTCFG_CMD;
>+	req->tx.buf[1] = 0;
>+	req->tx.buf[2] = PECI_ENDPTCFG_TYPE_MMIO;
>+	req->tx.buf[3] = 0; /* Endpoint ID */
>+	req->tx.buf[4] = 0; /* Reserved */
>+	req->tx.buf[5] = bar;
>+	req->tx.buf[6] = addr_type;
>+	req->tx.buf[7] = seg; /* PCI Segment */
>+	req->tx.buf[8] = PCI_DEVFN(dev, func);
>+	req->tx.buf[9] = bus; /* PCI Bus */
>+
>+	if (addr_type == PECI_ENDPTCFG_ADDR_TYPE_MMIO_D)
>+		put_unaligned_le32(offset, &req->tx.buf[10]);
>+	else
>+		put_unaligned_le64(offset, &req->tx.buf[10]);
>+
>+	ret = peci_request_xfer_retry(req);
>+	if (ret) {
>+		peci_request_free(req);
>+		return ERR_PTR(ret);
>+	}
>+
>+	return req;
>+}
>+
> u8 peci_request_data_readb(struct peci_request *req)
> {
> 	return req->rx.buf[1];
>@@ -278,6 +444,12 @@ u64 peci_request_data_dib(struct peci_request *req)
> }
> EXPORT_SYMBOL_NS_GPL(peci_request_data_dib, PECI);
>
>+s16 peci_request_data_temp(struct peci_request *req)
>+{
>+	return get_unaligned_le16(&req->rx.buf[0]);
>+}
>+EXPORT_SYMBOL_NS_GPL(peci_request_data_temp, PECI);
>+
> #define __read_pkg_config(x, type) \
> struct peci_request *peci_pkg_cfg_##x(struct peci_device *device, u8 index, u16 param) \
> { \
>@@ -289,3 +461,42 @@ __read_pkg_config(readb, u8);
> __read_pkg_config(readw, u16);
> __read_pkg_config(readl, u32);
> __read_pkg_config(readq, u64);
>+
>+#define __read_pci_config_local(x, type) \
>+struct peci_request * \
>+peci_pci_cfg_local_##x(struct peci_device *device, u8 bus, u8 dev, u8 func, u16 reg) \
>+{ \
>+	return __pci_cfg_local_read(device, bus, dev, func, reg, sizeof(type)); \
>+} \

As with peci_pkg_cfg_*() in patch 9, it seems like this could relieve
callers of some busy-work by returning a status int and writing the data
to a 'type*' pointer instead of returning a struct peci_request*.

>+EXPORT_SYMBOL_NS_GPL(peci_pci_cfg_local_##x, PECI)
>+
>+__read_pci_config_local(readb, u8);
>+__read_pci_config_local(readw, u16);
>+__read_pci_config_local(readl, u32);
>+
>+#define __read_ep_pci_config(x, msg_type, type) \
>+struct peci_request * \
>+peci_ep_pci_cfg_##x(struct peci_device *device, u8 seg, u8 bus, u8 dev, u8 func, u16 reg) \
>+{ \
>+	return __ep_pci_cfg_read(device, msg_type, seg, bus, dev, func, reg, sizeof(type)); \
>+} \

Likewise here.

>+EXPORT_SYMBOL_NS_GPL(peci_ep_pci_cfg_##x, PECI)
>+
>+__read_ep_pci_config(local_readb, PECI_ENDPTCFG_TYPE_LOCAL_PCI, u8);
>+__read_ep_pci_config(local_readw, PECI_ENDPTCFG_TYPE_LOCAL_PCI, u16);
>+__read_ep_pci_config(local_readl, PECI_ENDPTCFG_TYPE_LOCAL_PCI, u32);
>+__read_ep_pci_config(readb, PECI_ENDPTCFG_TYPE_PCI, u8);
>+__read_ep_pci_config(readw, PECI_ENDPTCFG_TYPE_PCI, u16);
>+__read_ep_pci_config(readl, PECI_ENDPTCFG_TYPE_PCI, u32);
>+
>+#define __read_ep_mmio(x, y, addr_type, type1, type2) \
>+struct peci_request *peci_ep_mmio##y##_##x(struct peci_device *device, u8 bar, u8 seg, \
>+					   u8 bus, u8 dev, u8 func, u64 offset) \
>+{ \
>+	return __ep_mmio_read(device, bar, addr_type, seg, bus, dev, func, \
>+			      offset, 10 + sizeof(type1), sizeof(type2)); \
>+} \

And here (I think).

Also, the '10 +' looks a bit magical/mysterious.  Could that be
clarified a bit with a macro or something?

>+EXPORT_SYMBOL_NS_GPL(peci_ep_mmio##y##_##x, PECI)
>+
>+__read_ep_mmio(readl, 32, PECI_ENDPTCFG_ADDR_TYPE_MMIO_D, u32, u32);
>+__read_ep_mmio(readl, 64, PECI_ENDPTCFG_ADDR_TYPE_MMIO_Q, u64, u32);
>diff --git a/include/linux/peci-cpu.h b/include/linux/peci-cpu.h
>new file mode 100644
>index 000000000000..d1b307ec2429
>--- /dev/null
>+++ b/include/linux/peci-cpu.h
>@@ -0,0 +1,38 @@
>+/* SPDX-License-Identifier: GPL-2.0-only */
>+/* Copyright (c) 2021 Intel Corporation */
>+
>+#ifndef __LINUX_PECI_CPU_H
>+#define __LINUX_PECI_CPU_H
>+
>+#include <linux/types.h>
>+
>+#define PECI_PCS_PKG_ID			0  /* Package Identifier Read */
>+#define  PECI_PKG_ID_CPU_ID		0x0000  /* CPUID Info */
>+#define  PECI_PKG_ID_PLATFORM_ID	0x0001  /* Platform ID */
>+#define  PECI_PKG_ID_DEVICE_ID		0x0002  /* Uncore Device ID */
>+#define  PECI_PKG_ID_MAX_THREAD_ID	0x0003  /* Max Thread ID */
>+#define  PECI_PKG_ID_MICROCODE_REV	0x0004  /* CPU Microcode Update Revision */
>+#define  PECI_PKG_ID_MCA_ERROR_LOG	0x0005  /* Machine Check Status */
>+#define PECI_PCS_MODULE_TEMP		9  /* Per Core DTS Temperature Read */
>+#define PECI_PCS_THERMAL_MARGIN		10 /* DTS thermal margin */
>+#define PECI_PCS_DDR_DIMM_TEMP		14 /* DDR DIMM Temperature */
>+#define PECI_PCS_TEMP_TARGET		16 /* Temperature Target Read */
>+#define PECI_PCS_TDP_UNITS		30 /* Units for power/energy registers */
>+
>+struct peci_device;
>+
>+int peci_temp_read(struct peci_device *device, s16 *temp_raw);
>+
>+int peci_pcs_read(struct peci_device *device, u8 index,
>+		  u16 param, u32 *data);
>+
>+int peci_pci_local_read(struct peci_device *device, u8 bus, u8 dev,
>+			u8 func, u16 reg, u32 *data);
>+
>+int peci_ep_pci_local_read(struct peci_device *device, u8 seg,
>+			   u8 bus, u8 dev, u8 func, u16 reg, u32 *data);
>+
>+int peci_mmio_read(struct peci_device *device, u8 bar, u8 seg,
>+		   u8 bus, u8 dev, u8 func, u64 address, u32 *data);
>+
>+#endif /* __LINUX_PECI_CPU_H */
>diff --git a/include/linux/peci.h b/include/linux/peci.h
>index f9f37b874011..31f9e628fd11 100644
>--- a/include/linux/peci.h
>+++ b/include/linux/peci.h
>@@ -9,14 +9,6 @@
> #include <linux/mutex.h>
> #include <linux/types.h>
>
>-#define PECI_PCS_PKG_ID			0  /* Package Identifier Read */
>-#define  PECI_PKG_ID_CPU_ID		0x0000  /* CPUID Info */
>-#define  PECI_PKG_ID_PLATFORM_ID	0x0001  /* Platform ID */
>-#define  PECI_PKG_ID_DEVICE_ID		0x0002  /* Uncore Device ID */
>-#define  PECI_PKG_ID_MAX_THREAD_ID	0x0003  /* Max Thread ID */
>-#define  PECI_PKG_ID_MICROCODE_REV	0x0004  /* CPU Microcode Update Revision */
>-#define  PECI_PKG_ID_MCA_ERROR_LOG	0x0005  /* Machine Check Status */
>-
> struct peci_request;
>
> /**
>-- 
>2.31.1
>


More information about the linux-arm-kernel mailing list