diff options
author | Jason M. Bills <jason.m.bills@linux.intel.com> | 2020-01-07 21:40:08 +0300 |
---|---|---|
committer | Jason M. Bills <jason.m.bills@linux.intel.com> | 2020-01-07 21:43:56 +0300 |
commit | 820013481a115100d5f8f22dc01aac8cc0363a23 (patch) | |
tree | 99cd46b66d5b9b97d38265d553f4fb60fee0d6a2 /meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0018-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch | |
parent | 965a056096e5e043748da8766fa50cb7afedb608 (diff) | |
download | openbmc-820013481a115100d5f8f22dc01aac8cc0363a23.tar.xz |
Update to internal 2020-01-07
Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0018-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch')
-rw-r--r-- | meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0018-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch | 5611 |
1 files changed, 0 insertions, 5611 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0018-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0018-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch deleted file mode 100644 index d1da4c599..000000000 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0018-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch +++ /dev/null @@ -1,5611 +0,0 @@ -From edeea958f026102ce28c8b760f7a96b9ffd7f65a Mon Sep 17 00:00:00 2001 -From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> -Date: Mon, 7 Jan 2019 09:56:10 -0800 -Subject: [PATCH] Update PECI drivers to sync with linux upstreaming version - -Upstreaming is in holding. It's for adding DTS sensor with PECI -subsystem code update. - -Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> -Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com> ---- - Documentation/hwmon/peci-cputemp | 34 +- - drivers/hwmon/Kconfig | 4 +- - drivers/hwmon/peci-cputemp.c | 171 +++--- - drivers/hwmon/peci-dimmtemp.c | 184 +++++-- - drivers/hwmon/peci-hwmon.h | 9 +- - drivers/mfd/Kconfig | 5 +- - drivers/mfd/intel-peci-client.c | 51 +- - drivers/peci/Kconfig | 46 +- - drivers/peci/Makefile | 7 +- - drivers/peci/busses/Kconfig | 32 ++ - drivers/peci/busses/Makefile | 7 + - drivers/peci/busses/peci-aspeed.c | 492 +++++++++++++++++ - drivers/peci/busses/peci-npcm.c | 410 +++++++++++++++ - drivers/peci/peci-aspeed.c | 505 ------------------ - drivers/peci/peci-core.c | 959 +++++++++++++++++++--------------- - drivers/peci/peci-dev.c | 346 ++++++++++++ - drivers/peci/peci-npcm.c | 410 --------------- - include/linux/mfd/intel-peci-client.h | 31 +- - include/linux/peci.h | 30 +- - include/uapi/linux/peci-ioctl.h | 416 +++++++++------ - 20 files changed, 2446 insertions(+), 1703 deletions(-) - create mode 100644 drivers/peci/busses/Kconfig - create mode 100644 drivers/peci/busses/Makefile - create mode 100644 drivers/peci/busses/peci-aspeed.c - create mode 100644 drivers/peci/busses/peci-npcm.c - delete mode 100644 drivers/peci/peci-aspeed.c - create mode 100644 drivers/peci/peci-dev.c - delete mode 100644 drivers/peci/peci-npcm.c - -diff --git a/Documentation/hwmon/peci-cputemp b/Documentation/hwmon/peci-cputemp -index 821a925..a3a3e46 100644 ---- a/Documentation/hwmon/peci-cputemp -+++ b/Documentation/hwmon/peci-cputemp -@@ -51,28 +51,38 @@ temp1_crit Provides shutdown temperature of the CPU package which - temp1_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of - the CPU package. - --temp2_label "Tcontrol" --temp2_input Provides current Tcontrol temperature of the CPU -+temp2_label "DTS" -+temp2_input Provides current DTS temperature of the CPU package. -+temp2_max Provides thermal control temperature of the CPU package -+ which is also known as Tcontrol. -+temp2_crit Provides shutdown temperature of the CPU package which -+ is also known as the maximum processor junction -+ temperature, Tjmax or Tprochot. -+temp2_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of -+ the CPU package. -+ -+temp3_label "Tcontrol" -+temp3_input Provides current Tcontrol temperature of the CPU - package which is also known as Fan Temperature target. - Indicates the relative value from thermal monitor trip - temperature at which fans should be engaged. --temp2_crit Provides Tcontrol critical value of the CPU package -+temp3_crit Provides Tcontrol critical value of the CPU package - which is same to Tjmax. - --temp3_label "Tthrottle" --temp3_input Provides current Tthrottle temperature of the CPU -+temp4_label "Tthrottle" -+temp4_input Provides current Tthrottle temperature of the CPU - package. Used for throttling temperature. If this value - is allowed and lower than Tjmax - the throttle will - occur and reported at lower than Tjmax. - --temp4_label "Tjmax" --temp4_input Provides the maximum junction temperature, Tjmax of the -+temp5_label "Tjmax" -+temp5_input Provides the maximum junction temperature, Tjmax of the - CPU package. - --temp[5-*]_label Provides string "Core X", where X is resolved core -+temp[6-*]_label Provides string "Core X", where X is resolved core - number. --temp[5-*]_input Provides current temperature of each core. --temp[5-*]_max Provides thermal control temperature of the core. --temp[5-*]_crit Provides shutdown temperature of the core. --temp[5-*]_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of -+temp[6-*]_input Provides current temperature of each core. -+temp[6-*]_max Provides thermal control temperature of the core. -+temp[6-*]_crit Provides shutdown temperature of the core. -+temp[6-*]_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of - the core. -diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index c0623fa..7399c3c 100644 ---- a/drivers/hwmon/Kconfig -+++ b/drivers/hwmon/Kconfig -@@ -1333,7 +1333,7 @@ config SENSORS_PECI_CPUTEMP - the PECI Client Command Suite via the processor PECI client. - Check Documentation/hwmon/peci-cputemp for details. - -- This driver can also be built as a module. If so, the module -+ This driver can also be built as a module. If so, the module - will be called peci-cputemp. - - config SENSORS_PECI_DIMMTEMP -@@ -1347,7 +1347,7 @@ config SENSORS_PECI_DIMMTEMP - Suite via the processor PECI client. - Check Documentation/hwmon/peci-dimmtemp for details. - -- This driver can also be built as a module. If so, the module -+ This driver can also be built as a module. If so, the module - will be called peci-dimmtemp. - - source "drivers/hwmon/pmbus/Kconfig" -diff --git a/drivers/hwmon/peci-cputemp.c b/drivers/hwmon/peci-cputemp.c -index 11880c8..d0d68e8 100644 ---- a/drivers/hwmon/peci-cputemp.c -+++ b/drivers/hwmon/peci-cputemp.c -@@ -1,5 +1,5 @@ - // SPDX-License-Identifier: GPL-2.0 --// Copyright (c) 2018 Intel Corporation -+// Copyright (c) 2018-2019 Intel Corporation - - #include <linux/hwmon.h> - #include <linux/jiffies.h> -@@ -9,18 +9,13 @@ - #include <linux/platform_device.h> - #include "peci-hwmon.h" - --#define DEFAULT_CHANNEL_NUMS 4 -+#define DEFAULT_CHANNEL_NUMS 5 - #define CORETEMP_CHANNEL_NUMS CORE_NUMS_MAX - #define CPUTEMP_CHANNEL_NUMS (DEFAULT_CHANNEL_NUMS + CORETEMP_CHANNEL_NUMS) - --/* The RESOLVED_CORES register in PCU of a client CPU */ --#define REG_RESOLVED_CORES_BUS 1 --#define REG_RESOLVED_CORES_DEVICE 30 --#define REG_RESOLVED_CORES_FUNCTION 3 --#define REG_RESOLVED_CORES_OFFSET 0xB4 -- - struct temp_group { - struct temp_data die; -+ struct temp_data dts; - struct temp_data tcontrol; - struct temp_data tthrottle; - struct temp_data tjmax; -@@ -43,6 +38,7 @@ struct peci_cputemp { - - enum cputemp_channels { - channel_die, -+ channel_dts, - channel_tcontrol, - channel_tthrottle, - channel_tjmax, -@@ -54,6 +50,10 @@ static const u32 config_table[DEFAULT_CHANNEL_NUMS + 1] = { - HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | - HWMON_T_CRIT_HYST, - -+ /* DTS margin */ -+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | -+ HWMON_T_CRIT_HYST, -+ - /* Tcontrol temperature */ - HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_CRIT, - -@@ -70,6 +70,7 @@ static const u32 config_table[DEFAULT_CHANNEL_NUMS + 1] = { - - static const char *cputemp_label[CPUTEMP_CHANNEL_NUMS] = { - "Die", -+ "DTS", - "Tcontrol", - "Tthrottle", - "Tjmax", -@@ -92,19 +93,20 @@ static int get_temp_targets(struct peci_cputemp *priv) - s32 tthrottle_offset; - s32 tcontrol_margin; - u8 pkg_cfg[4]; -- int rc; -+ int ret; - -- /** -+ /* - * Just use only the tcontrol marker to determine if target values need - * update. - */ - if (!peci_temp_need_update(&priv->temp.tcontrol)) - return 0; - -- rc = peci_client_read_package_config(priv->mgr, -- MBX_INDEX_TEMP_TARGET, 0, pkg_cfg); -- if (rc) -- return rc; -+ ret = peci_client_read_package_config(priv->mgr, -+ PECI_MBX_INDEX_TEMP_TARGET, 0, -+ pkg_cfg); -+ if (ret) -+ return ret; - - priv->temp.tjmax.value = pkg_cfg[2] * 1000; - -@@ -123,17 +125,16 @@ static int get_temp_targets(struct peci_cputemp *priv) - static int get_die_temp(struct peci_cputemp *priv) - { - struct peci_get_temp_msg msg; -- int rc; -+ int ret; - - if (!peci_temp_need_update(&priv->temp.die)) - return 0; - - msg.addr = priv->mgr->client->addr; - -- rc = peci_command(priv->mgr->client->adapter, PECI_CMD_GET_TEMP, -- &msg); -- if (rc) -- return rc; -+ ret = peci_command(priv->mgr->client->adapter, PECI_CMD_GET_TEMP, &msg); -+ if (ret) -+ return ret; - - /* Note that the tjmax should be available before calling it */ - priv->temp.die.value = priv->temp.tjmax.value + -@@ -144,24 +145,64 @@ static int get_die_temp(struct peci_cputemp *priv) - return 0; - } - -+static int get_dts(struct peci_cputemp *priv) -+{ -+ s32 dts_margin; -+ u8 pkg_cfg[4]; -+ int ret; -+ -+ if (!peci_temp_need_update(&priv->temp.dts)) -+ return 0; -+ -+ ret = peci_client_read_package_config(priv->mgr, -+ PECI_MBX_INDEX_DTS_MARGIN, 0, -+ pkg_cfg); -+ -+ if (ret) -+ return ret; -+ -+ dts_margin = (pkg_cfg[1] << 8) | pkg_cfg[0]; -+ -+ /** -+ * Processors return a value of DTS reading in 10.6 format -+ * (10 bits signed decimal, 6 bits fractional). -+ * Error codes: -+ * 0x8000: General sensor error -+ * 0x8001: Reserved -+ * 0x8002: Underflow on reading value -+ * 0x8003-0x81ff: Reserved -+ */ -+ if (dts_margin >= 0x8000 && dts_margin <= 0x81ff) -+ return -EIO; -+ -+ dts_margin = ten_dot_six_to_millidegree(dts_margin); -+ -+ /* Note that the tcontrol should be available before calling it */ -+ priv->temp.dts.value = priv->temp.tcontrol.value - dts_margin; -+ -+ peci_temp_mark_updated(&priv->temp.dts); -+ -+ return 0; -+} -+ - static int get_core_temp(struct peci_cputemp *priv, int core_index) - { - s32 core_dts_margin; - u8 pkg_cfg[4]; -- int rc; -+ int ret; - - if (!peci_temp_need_update(&priv->temp.core[core_index])) - return 0; - -- rc = peci_client_read_package_config(priv->mgr, -- MBX_INDEX_PER_CORE_DTS_TEMP, -- core_index, pkg_cfg); -- if (rc) -- return rc; -+ ret = peci_client_read_package_config(priv->mgr, -+ PECI_MBX_INDEX_PER_CORE_DTS_TEMP, -+ core_index, pkg_cfg); -+ if (ret) -+ return ret; - - core_dts_margin = le16_to_cpup((__le16 *)pkg_cfg); - -- /** -+ /* - * Processors return a value of the core DTS reading in 10.6 format - * (10 bits signed decimal, 6 bits fractional). - * Error codes: -@@ -192,6 +233,7 @@ static int cputemp_read_string(struct device *dev, - return -EOPNOTSUPP; - - *str = cputemp_label[channel]; -+ - return 0; - } - -@@ -200,26 +242,33 @@ static int cputemp_read(struct device *dev, - u32 attr, int channel, long *val) - { - struct peci_cputemp *priv = dev_get_drvdata(dev); -- int rc, core_index; -+ int ret, core_index; - - if (channel >= CPUTEMP_CHANNEL_NUMS || - !(priv->temp_config[channel] & BIT(attr))) - return -EOPNOTSUPP; - -- rc = get_temp_targets(priv); -- if (rc) -- return rc; -+ ret = get_temp_targets(priv); -+ if (ret) -+ return ret; - - switch (attr) { - case hwmon_temp_input: - switch (channel) { - case channel_die: -- rc = get_die_temp(priv); -- if (rc) -+ ret = get_die_temp(priv); -+ if (ret) - break; - - *val = priv->temp.die.value; - break; -+ case channel_dts: -+ ret = get_dts(priv); -+ if (ret) -+ break; -+ -+ *val = priv->temp.dts.value; -+ break; - case channel_tcontrol: - *val = priv->temp.tcontrol.value; - break; -@@ -231,8 +280,8 @@ static int cputemp_read(struct device *dev, - break; - default: - core_index = channel - DEFAULT_CHANNEL_NUMS; -- rc = get_core_temp(priv, core_index); -- if (rc) -+ ret = get_core_temp(priv, core_index); -+ if (ret) - break; - - *val = priv->temp.core[core_index].value; -@@ -249,11 +298,11 @@ static int cputemp_read(struct device *dev, - *val = priv->temp.tjmax.value - priv->temp.tcontrol.value; - break; - default: -- rc = -EOPNOTSUPP; -+ ret = -EOPNOTSUPP; - break; - } - -- return rc; -+ return ret; - } - - static umode_t cputemp_is_visible(const void *data, -@@ -262,11 +311,11 @@ static umode_t cputemp_is_visible(const void *data, - { - const struct peci_cputemp *priv = data; - -- if (priv->temp_config[channel] & BIT(attr)) -- if (channel < DEFAULT_CHANNEL_NUMS || -- (channel >= DEFAULT_CHANNEL_NUMS && -- (priv->core_mask & BIT(channel - DEFAULT_CHANNEL_NUMS)))) -- return 0444; -+ if ((priv->temp_config[channel] & BIT(attr)) && -+ (channel < DEFAULT_CHANNEL_NUMS || -+ (channel >= DEFAULT_CHANNEL_NUMS && -+ (priv->core_mask & BIT(channel - DEFAULT_CHANNEL_NUMS))))) -+ return 0444; - - return 0; - } -@@ -280,40 +329,43 @@ static const struct hwmon_ops cputemp_ops = { - static int check_resolved_cores(struct peci_cputemp *priv) - { - struct peci_rd_pci_cfg_local_msg msg; -- int rc; -+ int ret; - - /* Get the RESOLVED_CORES register value */ - msg.addr = priv->mgr->client->addr; -- msg.bus = REG_RESOLVED_CORES_BUS; -- msg.device = REG_RESOLVED_CORES_DEVICE; -- msg.function = REG_RESOLVED_CORES_FUNCTION; -- msg.reg = REG_RESOLVED_CORES_OFFSET; -+ msg.bus = 1; -+ msg.device = 30; -+ msg.function = 3; -+ msg.reg = 0xb4; - msg.rx_len = 4; - -- rc = peci_command(priv->mgr->client->adapter, -- PECI_CMD_RD_PCI_CFG_LOCAL, &msg); -- if (rc) -- return rc; -+ ret = peci_command(priv->mgr->client->adapter, -+ PECI_CMD_RD_PCI_CFG_LOCAL, &msg); -+ if (msg.cc != PECI_DEV_CC_SUCCESS) -+ ret = -EAGAIN; -+ if (ret) -+ return ret; - - priv->core_mask = le32_to_cpup((__le32 *)msg.pci_config); - if (!priv->core_mask) - return -EAGAIN; - - dev_dbg(priv->dev, "Scanned resolved cores: 0x%x\n", priv->core_mask); -+ - return 0; - } - - static int create_core_temp_info(struct peci_cputemp *priv) - { -- int rc, i; -+ int ret, i; - -- rc = check_resolved_cores(priv); -- if (rc) -- return rc; -+ ret = check_resolved_cores(priv); -+ if (ret) -+ return ret; - - for (i = 0; i < priv->gen_info->core_max; i++) - if (priv->core_mask & BIT(i)) -- while (i + DEFAULT_CHANNEL_NUMS >= priv->config_idx) -+ while (priv->config_idx <= i + DEFAULT_CHANNEL_NUMS) - priv->temp_config[priv->config_idx++] = - config_table[channel_core]; - -@@ -326,7 +378,7 @@ static int peci_cputemp_probe(struct platform_device *pdev) - struct device *dev = &pdev->dev; - struct peci_cputemp *priv; - struct device *hwmon_dev; -- int rc; -+ int ret; - - if ((mgr->client->adapter->cmd_mask & - (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) != -@@ -346,12 +398,13 @@ static int peci_cputemp_probe(struct platform_device *pdev) - mgr->client->addr - PECI_BASE_ADDR); - - priv->temp_config[priv->config_idx++] = config_table[channel_die]; -+ priv->temp_config[priv->config_idx++] = config_table[channel_dts]; - priv->temp_config[priv->config_idx++] = config_table[channel_tcontrol]; - priv->temp_config[priv->config_idx++] = config_table[channel_tthrottle]; - priv->temp_config[priv->config_idx++] = config_table[channel_tjmax]; - -- rc = create_core_temp_info(priv); -- if (rc) -+ ret = create_core_temp_info(priv); -+ if (ret) - dev_dbg(dev, "Skipped creating core temp info\n"); - - priv->chip.ops = &cputemp_ops; -@@ -385,7 +438,7 @@ MODULE_DEVICE_TABLE(platform, peci_cputemp_ids); - static struct platform_driver peci_cputemp_driver = { - .probe = peci_cputemp_probe, - .id_table = peci_cputemp_ids, -- .driver = { .name = "peci-cputemp", }, -+ .driver = { .name = KBUILD_MODNAME, }, - }; - module_platform_driver(peci_cputemp_driver); - -diff --git a/drivers/hwmon/peci-dimmtemp.c b/drivers/hwmon/peci-dimmtemp.c -index 86a45a9..a404b6e 100644 ---- a/drivers/hwmon/peci-dimmtemp.c -+++ b/drivers/hwmon/peci-dimmtemp.c -@@ -1,5 +1,5 @@ - // SPDX-License-Identifier: GPL-2.0 --// Copyright (c) 2018 Intel Corporation -+// Copyright (c) 2018-2019 Intel Corporation - - #include <linux/hwmon.h> - #include <linux/jiffies.h> -@@ -21,6 +21,8 @@ struct peci_dimmtemp { - struct workqueue_struct *work_queue; - struct delayed_work work_handler; - struct temp_data temp[DIMM_NUMS_MAX]; -+ long temp_max[DIMM_NUMS_MAX]; -+ long temp_crit[DIMM_NUMS_MAX]; - u32 dimm_mask; - int retry_count; - u32 temp_config[DIMM_NUMS_MAX + 1]; -@@ -44,20 +46,106 @@ static int get_dimm_temp(struct peci_dimmtemp *priv, int dimm_no) - { - int dimm_order = dimm_no % priv->gen_info->dimm_idx_max; - int chan_rank = dimm_no / priv->gen_info->dimm_idx_max; -+ struct peci_rd_pci_cfg_local_msg rp_msg; - u8 cfg_data[4]; -- int rc; -+ int ret; - - if (!peci_temp_need_update(&priv->temp[dimm_no])) - return 0; - -- rc = peci_client_read_package_config(priv->mgr, -- MBX_INDEX_DDR_DIMM_TEMP, -- chan_rank, cfg_data); -- if (rc) -- return rc; -+ ret = peci_client_read_package_config(priv->mgr, -+ PECI_MBX_INDEX_DDR_DIMM_TEMP, -+ chan_rank, cfg_data); -+ if (ret) -+ return ret; - - priv->temp[dimm_no].value = cfg_data[dimm_order] * 1000; - -+ switch (priv->gen_info->model) { -+ case INTEL_FAM6_SKYLAKE_X: -+ rp_msg.addr = priv->mgr->client->addr; -+ rp_msg.bus = 2; -+ /* -+ * Device 10, Function 2: IMC 0 channel 0 -> rank 0 -+ * Device 10, Function 6: IMC 0 channel 1 -> rank 1 -+ * Device 11, Function 2: IMC 0 channel 2 -> rank 2 -+ * Device 12, Function 2: IMC 1 channel 0 -> rank 3 -+ * Device 12, Function 6: IMC 1 channel 1 -> rank 4 -+ * Device 13, Function 2: IMC 1 channel 2 -> rank 5 -+ */ -+ rp_msg.device = 10 + chan_rank / 3 * 2 + -+ (chan_rank % 3 == 2 ? 1 : 0); -+ rp_msg.function = chan_rank % 3 == 1 ? 6 : 2; -+ rp_msg.reg = 0x120 + dimm_order * 4; -+ rp_msg.rx_len = 4; -+ -+ ret = peci_command(priv->mgr->client->adapter, -+ PECI_CMD_RD_PCI_CFG_LOCAL, &rp_msg); -+ if (rp_msg.cc != PECI_DEV_CC_SUCCESS) -+ ret = -EAGAIN; -+ if (ret) -+ return ret; -+ -+ priv->temp_max[dimm_no] = rp_msg.pci_config[1] * 1000; -+ priv->temp_crit[dimm_no] = rp_msg.pci_config[2] * 1000; -+ break; -+ case INTEL_FAM6_SKYLAKE_XD: -+ rp_msg.addr = priv->mgr->client->addr; -+ rp_msg.bus = 2; -+ /* -+ * Device 10, Function 2: IMC 0 channel 0 -> rank 0 -+ * Device 10, Function 6: IMC 0 channel 1 -> rank 1 -+ * Device 12, Function 2: IMC 1 channel 0 -> rank 2 -+ * Device 12, Function 6: IMC 1 channel 1 -> rank 3 -+ */ -+ rp_msg.device = 10 + chan_rank / 2 * 2; -+ rp_msg.function = chan_rank % 2 ? 6 : 2; -+ rp_msg.reg = 0x120 + dimm_order * 4; -+ rp_msg.rx_len = 4; -+ -+ ret = peci_command(priv->mgr->client->adapter, -+ PECI_CMD_RD_PCI_CFG_LOCAL, &rp_msg); -+ if (rp_msg.cc != PECI_DEV_CC_SUCCESS) -+ ret = -EAGAIN; -+ if (ret) -+ return ret; -+ -+ priv->temp_max[dimm_no] = rp_msg.pci_config[1] * 1000; -+ priv->temp_crit[dimm_no] = rp_msg.pci_config[2] * 1000; -+ break; -+ case INTEL_FAM6_HASWELL_X: -+ case INTEL_FAM6_BROADWELL_X: -+ rp_msg.addr = priv->mgr->client->addr; -+ rp_msg.bus = 1; -+ /* -+ * Device 20, Function 0: IMC 0 channel 0 -> rank 0 -+ * Device 20, Function 1: IMC 0 channel 1 -> rank 1 -+ * Device 21, Function 0: IMC 0 channel 2 -> rank 2 -+ * Device 21, Function 1: IMC 0 channel 3 -> rank 3 -+ * Device 23, Function 0: IMC 1 channel 0 -> rank 4 -+ * Device 23, Function 1: IMC 1 channel 1 -> rank 5 -+ * Device 24, Function 0: IMC 1 channel 2 -> rank 6 -+ * Device 24, Function 1: IMC 1 channel 3 -> rank 7 -+ */ -+ rp_msg.device = 20 + chan_rank / 2 + chan_rank / 4; -+ rp_msg.function = chan_rank % 2; -+ rp_msg.reg = 0x120 + dimm_order * 4; -+ rp_msg.rx_len = 4; -+ -+ ret = peci_command(priv->mgr->client->adapter, -+ PECI_CMD_RD_PCI_CFG_LOCAL, &rp_msg); -+ if (rp_msg.cc != PECI_DEV_CC_SUCCESS) -+ ret = -EAGAIN; -+ if (ret) -+ return ret; -+ -+ priv->temp_max[dimm_no] = rp_msg.pci_config[1] * 1000; -+ priv->temp_crit[dimm_no] = rp_msg.pci_config[2] * 1000; -+ break; -+ default: -+ return -EOPNOTSUPP; -+ } -+ - peci_temp_mark_updated(&priv->temp[dimm_no]); - - return 0; -@@ -77,6 +165,7 @@ static int dimmtemp_read_string(struct device *dev, - chan_rank = channel / dimm_idx_max; - dimm_idx = channel % dimm_idx_max; - *str = dimmtemp_label[chan_rank][dimm_idx]; -+ - return 0; - } - -@@ -84,17 +173,28 @@ static int dimmtemp_read(struct device *dev, enum hwmon_sensor_types type, - u32 attr, int channel, long *val) - { - struct peci_dimmtemp *priv = dev_get_drvdata(dev); -- int rc; -- -- if (attr != hwmon_temp_input) -- return -EOPNOTSUPP; -- -- rc = get_dimm_temp(priv, channel); -- if (rc) -- return rc; -+ int ret; -+ -+ ret = get_dimm_temp(priv, channel); -+ if (ret) -+ return ret; -+ -+ switch (attr) { -+ case hwmon_temp_input: -+ *val = priv->temp[channel].value; -+ break; -+ case hwmon_temp_max: -+ *val = priv->temp_max[channel]; -+ break; -+ case hwmon_temp_crit: -+ *val = priv->temp_crit[channel]; -+ break; -+ default: -+ ret = -EOPNOTSUPP; -+ break; -+ } - -- *val = priv->temp[channel].value; -- return 0; -+ return ret; - } - - static umode_t dimmtemp_is_visible(const void *data, -@@ -120,16 +220,16 @@ static int check_populated_dimms(struct peci_dimmtemp *priv) - { - u32 chan_rank_max = priv->gen_info->chan_rank_max; - u32 dimm_idx_max = priv->gen_info->dimm_idx_max; -- int chan_rank, dimm_idx, rc; -+ int chan_rank, dimm_idx, ret; - u8 cfg_data[4]; - - for (chan_rank = 0; chan_rank < chan_rank_max; chan_rank++) { -- rc = peci_client_read_package_config(priv->mgr, -- MBX_INDEX_DDR_DIMM_TEMP, -- chan_rank, cfg_data); -- if (rc) { -+ ret = peci_client_read_package_config(priv->mgr, -+ PECI_MBX_INDEX_DDR_DIMM_TEMP, -+ chan_rank, cfg_data); -+ if (ret) { - priv->dimm_mask = 0; -- return rc; -+ return ret; - } - - for (dimm_idx = 0; dimm_idx < dimm_idx_max; dimm_idx++) -@@ -143,17 +243,18 @@ static int check_populated_dimms(struct peci_dimmtemp *priv) - return -EAGAIN; - - dev_dbg(priv->dev, "Scanned populated DIMMs: 0x%x\n", priv->dimm_mask); -+ - return 0; - } - - static int create_dimm_temp_info(struct peci_dimmtemp *priv) - { -- int rc, i, config_idx, channels; -+ int ret, i, config_idx, channels; - struct device *hwmon_dev; - -- rc = check_populated_dimms(priv); -- if (rc) { -- if (rc == -EAGAIN) { -+ ret = check_populated_dimms(priv); -+ if (ret) { -+ if (ret == -EAGAIN) { - if (priv->retry_count < DIMM_MASK_CHECK_RETRY_MAX) { - queue_delayed_work(priv->work_queue, - &priv->work_handler, -@@ -164,11 +265,11 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv) - } else { - dev_err(priv->dev, - "Timeout DIMM temp info creation\n"); -- rc = -ETIMEDOUT; -+ ret = -ETIMEDOUT; - } - } - -- return rc; -+ return ret; - } - - channels = priv->gen_info->chan_rank_max * -@@ -177,7 +278,8 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv) - if (priv->dimm_mask & BIT(i)) - while (i >= config_idx) - priv->temp_config[config_idx++] = -- HWMON_T_LABEL | HWMON_T_INPUT; -+ HWMON_T_LABEL | HWMON_T_INPUT | -+ HWMON_T_MAX | HWMON_T_CRIT; - - priv->chip.ops = &dimmtemp_ops; - priv->chip.info = priv->info; -@@ -192,12 +294,12 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv) - priv, - &priv->chip, - NULL); -- rc = PTR_ERR_OR_ZERO(hwmon_dev); -- if (!rc) -+ ret = PTR_ERR_OR_ZERO(hwmon_dev); -+ if (!ret) - dev_dbg(priv->dev, "%s: sensor '%s'\n", - dev_name(hwmon_dev), priv->name); - -- return rc; -+ return ret; - } - - static void create_dimm_temp_info_delayed(struct work_struct *work) -@@ -205,10 +307,10 @@ static void create_dimm_temp_info_delayed(struct work_struct *work) - struct delayed_work *dwork = to_delayed_work(work); - struct peci_dimmtemp *priv = container_of(dwork, struct peci_dimmtemp, - work_handler); -- int rc; -+ int ret; - -- rc = create_dimm_temp_info(priv); -- if (rc && rc != -EAGAIN) -+ ret = create_dimm_temp_info(priv); -+ if (ret && ret != -EAGAIN) - dev_dbg(priv->dev, "Failed to create DIMM temp info\n"); - } - -@@ -217,7 +319,7 @@ static int peci_dimmtemp_probe(struct platform_device *pdev) - struct peci_client_manager *mgr = dev_get_drvdata(pdev->dev.parent); - struct device *dev = &pdev->dev; - struct peci_dimmtemp *priv; -- int rc; -+ int ret; - - if ((mgr->client->adapter->cmd_mask & - (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) != -@@ -242,8 +344,8 @@ static int peci_dimmtemp_probe(struct platform_device *pdev) - - INIT_DELAYED_WORK(&priv->work_handler, create_dimm_temp_info_delayed); - -- rc = create_dimm_temp_info(priv); -- if (rc && rc != -EAGAIN) { -+ ret = create_dimm_temp_info(priv); -+ if (ret && ret != -EAGAIN) { - dev_err(dev, "Failed to create DIMM temp info\n"); - goto err_free_wq; - } -@@ -252,7 +354,7 @@ static int peci_dimmtemp_probe(struct platform_device *pdev) - - err_free_wq: - destroy_workqueue(priv->work_queue); -- return rc; -+ return ret; - } - - static int peci_dimmtemp_remove(struct platform_device *pdev) -@@ -275,7 +377,7 @@ static struct platform_driver peci_dimmtemp_driver = { - .probe = peci_dimmtemp_probe, - .remove = peci_dimmtemp_remove, - .id_table = peci_dimmtemp_ids, -- .driver = { .name = "peci-dimmtemp", }, -+ .driver = { .name = KBUILD_MODNAME, }, - }; - module_platform_driver(peci_dimmtemp_driver); - -diff --git a/drivers/hwmon/peci-hwmon.h b/drivers/hwmon/peci-hwmon.h -index 6ca1855..ce6b470 100644 ---- a/drivers/hwmon/peci-hwmon.h -+++ b/drivers/hwmon/peci-hwmon.h -@@ -1,5 +1,5 @@ - /* SPDX-License-Identifier: GPL-2.0 */ --/* Copyright (c) 2018 Intel Corporation */ -+/* Copyright (c) 2018-2019 Intel Corporation */ - - #ifndef __PECI_HWMON_H - #define __PECI_HWMON_H -@@ -29,11 +29,8 @@ struct temp_data { - */ - static inline bool peci_temp_need_update(struct temp_data *temp) - { -- if (temp->valid && -- time_before(jiffies, temp->last_updated + UPDATE_INTERVAL)) -- return false; -- -- return true; -+ return !temp->valid || -+ time_after(jiffies, temp->last_updated + UPDATE_INTERVAL); - } - - /** -diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig -index 5d89546..46f52a3 100644 ---- a/drivers/mfd/Kconfig -+++ b/drivers/mfd/Kconfig -@@ -630,7 +630,7 @@ config MFD_INTEL_MSIC - devices used in Intel Medfield platforms. - - config MFD_INTEL_PECI_CLIENT -- bool "Intel PECI client" -+ tristate "Intel PECI client" - depends on (PECI || COMPILE_TEST) - select MFD_CORE - help -@@ -643,6 +643,9 @@ config MFD_INTEL_PECI_CLIENT - 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 intel-peci-client. -+ - config MFD_IPAQ_MICRO - bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support" - depends on SA1100_H3100 || SA1100_H3600 -diff --git a/drivers/mfd/intel-peci-client.c b/drivers/mfd/intel-peci-client.c -index d53e4f1..18bf0af 100644 ---- a/drivers/mfd/intel-peci-client.c -+++ b/drivers/mfd/intel-peci-client.c -@@ -1,12 +1,12 @@ - // SPDX-License-Identifier: GPL-2.0 --// Copyright (c) 2018 Intel Corporation -+// Copyright (c) 2018-2019 Intel Corporation - - #include <linux/bitfield.h> - #include <linux/mfd/core.h> - #include <linux/mfd/intel-peci-client.h> - #include <linux/module.h> --#include <linux/peci.h> - #include <linux/of_device.h> -+#include <linux/peci.h> - - #define CPU_ID_MODEL_MASK GENMASK(7, 4) - #define CPU_ID_FAMILY_MASK GENMASK(11, 8) -@@ -18,12 +18,6 @@ - #define LOWER_BYTE_MASK GENMASK(7, 0) - #define UPPER_BYTE_MASK GENMASK(16, 8) - --enum cpu_gens { -- CPU_GEN_HSX = 0, /* Haswell Xeon */ -- CPU_GEN_BRX, /* Broadwell Xeon */ -- CPU_GEN_SKX, /* Skylake Xeon */ --}; -- - static struct mfd_cell peci_functions[] = { - { .name = "peci-cputemp", }, - { .name = "peci-dimmtemp", }, -@@ -31,38 +25,45 @@ static struct mfd_cell peci_functions[] = { - }; - - static const struct cpu_gen_info cpu_gen_info_table[] = { -- [CPU_GEN_HSX] = { -+ { /* Haswell Xeon */ - .family = 6, /* Family code */ - .model = INTEL_FAM6_HASWELL_X, - .core_max = CORE_MAX_ON_HSX, - .chan_rank_max = CHAN_RANK_MAX_ON_HSX, - .dimm_idx_max = DIMM_IDX_MAX_ON_HSX }, -- [CPU_GEN_BRX] = { -+ { /* Broadwell Xeon */ - .family = 6, /* Family code */ - .model = INTEL_FAM6_BROADWELL_X, - .core_max = CORE_MAX_ON_BDX, - .chan_rank_max = CHAN_RANK_MAX_ON_BDX, - .dimm_idx_max = DIMM_IDX_MAX_ON_BDX }, -- [CPU_GEN_SKX] = { -+ { /* Skylake Xeon */ - .family = 6, /* Family code */ - .model = INTEL_FAM6_SKYLAKE_X, - .core_max = CORE_MAX_ON_SKX, - .chan_rank_max = CHAN_RANK_MAX_ON_SKX, - .dimm_idx_max = DIMM_IDX_MAX_ON_SKX }, -+ { /* Skylake Xeon D */ -+ .family = 6, /* Family code */ -+ .model = INTEL_FAM6_SKYLAKE_XD, -+ .core_max = CORE_MAX_ON_SKXD, -+ .chan_rank_max = CHAN_RANK_MAX_ON_SKXD, -+ .dimm_idx_max = DIMM_IDX_MAX_ON_SKXD }, - }; - - static int peci_client_get_cpu_gen_info(struct peci_client_manager *priv) - { -+ struct device *dev = &priv->client->dev; - u32 cpu_id; - u16 family; - u8 model; -- int rc; -+ int ret; - int i; - -- rc = peci_get_cpu_id(priv->client->adapter, priv->client->addr, -- &cpu_id); -- if (rc) -- return rc; -+ ret = peci_get_cpu_id(priv->client->adapter, priv->client->addr, -+ &cpu_id); -+ if (ret) -+ return ret; - - family = FIELD_PREP(LOWER_BYTE_MASK, - FIELD_GET(CPU_ID_FAMILY_MASK, cpu_id)) | -@@ -83,11 +84,11 @@ static int peci_client_get_cpu_gen_info(struct peci_client_manager *priv) - } - - if (!priv->gen_info) { -- dev_err(priv->dev, "Can't support this CPU: 0x%x\n", cpu_id); -- rc = -ENODEV; -+ dev_err(dev, "Can't support this CPU: 0x%x\n", cpu_id); -+ ret = -ENODEV; - } - -- return rc; -+ return ret; - } - - static int peci_client_probe(struct peci_client *client) -@@ -103,31 +104,29 @@ static int peci_client_probe(struct peci_client *client) - - dev_set_drvdata(dev, priv); - priv->client = client; -- priv->dev = dev; - cpu_no = client->addr - PECI_BASE_ADDR; - - ret = peci_client_get_cpu_gen_info(priv); - if (ret) - return ret; - -- ret = devm_mfd_add_devices(priv->dev, cpu_no, peci_functions, -+ ret = devm_mfd_add_devices(dev, cpu_no, peci_functions, - ARRAY_SIZE(peci_functions), NULL, 0, NULL); - if (ret < 0) { -- dev_err(priv->dev, "Failed to register child devices: %d\n", -- ret); -+ dev_err(dev, "Failed to register child devices: %d\n", ret); - return ret; - } - - return 0; - } - --#ifdef CONFIG_OF -+#if IS_ENABLED(CONFIG_OF) - static const struct of_device_id peci_client_of_table[] = { - { .compatible = "intel,peci-client" }, - { } - }; - MODULE_DEVICE_TABLE(of, peci_client_of_table); --#endif -+#endif /* CONFIG_OF */ - - static const struct peci_device_id peci_client_ids[] = { - { .name = "peci-client" }, -@@ -139,7 +138,7 @@ static struct peci_driver peci_client_driver = { - .probe = peci_client_probe, - .id_table = peci_client_ids, - .driver = { -- .name = "peci-client", -+ .name = KBUILD_MODNAME, - .of_match_table = of_match_ptr(peci_client_of_table), - }, - }; -diff --git a/drivers/peci/Kconfig b/drivers/peci/Kconfig -index 7293108..9752fee 100644 ---- a/drivers/peci/Kconfig -+++ b/drivers/peci/Kconfig -@@ -2,10 +2,12 @@ - # Platform Environment Control Interface (PECI) subsystem configuration - # - -+menu "PECI support" -+ - config PECI -- bool "PECI support" -- select RT_MUTEXES -+ tristate "PECI support" - select CRC8 -+ default n - help - The Platform Environment Control Interface (PECI) is a one-wire bus - interface that provides a communication channel from Intel processors -@@ -14,37 +16,23 @@ config PECI - If you want PECI support, you should say Y here and also to the - specific driver for your bus adapter(s) below. - --if PECI -- --# --# PECI hardware bus configuration --# -- --menu "PECI Hardware Bus support" -- --config PECI_ASPEED -- tristate "ASPEED PECI support" -- select REGMAP_MMIO -- depends on OF -- depends on ARCH_ASPEED || COMPILE_TEST -- help -- Say Y here if you want support for the Platform Environment Control -- Interface (PECI) bus adapter driver on the ASPEED SoCs. -+ This support is also available as a module. If so, the module -+ will be called peci-core. - -- This support is also available as a module. If so, the module -- will be called peci-aspeed. -+if PECI - --config PECI_NPCM -- tristate "Nuvoton NPCM PECI support" -- select REGMAP_MMIO -- depends on OF -- depends on ARCH_NPCM || COMPILE_TEST -+config PECI_CHARDEV -+ tristate "PECI device interface" - help -- Say Y here if you want support for the Platform Environment Control -- Interface (PECI) bus adapter driver on the Nuvoton NPCM SoCs. -+ Say Y here to use peci-* device files, usually found in the /dev -+ directory on your system. They make it possible to have user-space -+ programs use the PECI bus. - - This support is also available as a module. If so, the module -- will be called peci-npcm. --endmenu -+ will be called peci-dev. -+ -+source "drivers/peci/busses/Kconfig" - - endif # PECI -+ -+endmenu -diff --git a/drivers/peci/Makefile b/drivers/peci/Makefile -index 3326da5..da8b0a3 100644 ---- a/drivers/peci/Makefile -+++ b/drivers/peci/Makefile -@@ -1,10 +1,11 @@ -+# SPDX-License-Identifier: GPL-2.0 - # --# Makefile for the PECI core and bus drivers. -+# Makefile for the PECI core drivers. - # - - # Core functionality - obj-$(CONFIG_PECI) += peci-core.o -+obj-$(CONFIG_PECI_CHARDEV) += peci-dev.o - - # Hardware specific bus drivers --obj-$(CONFIG_PECI_ASPEED) += peci-aspeed.o --obj-$(CONFIG_PECI_NPCM) += peci-npcm.o -+obj-y += busses/ -diff --git a/drivers/peci/busses/Kconfig b/drivers/peci/busses/Kconfig -new file mode 100644 -index 0000000..bfacafb ---- /dev/null -+++ b/drivers/peci/busses/Kconfig -@@ -0,0 +1,32 @@ -+# -+# PECI hardware bus configuration -+# -+ -+menu "PECI Hardware Bus support" -+ -+config PECI_ASPEED -+ tristate "ASPEED PECI support" -+ depends on ARCH_ASPEED || COMPILE_TEST -+ depends on OF -+ depends on PECI -+ help -+ Say Y here if you want support for the Platform Environment Control -+ Interface (PECI) bus adapter driver on the ASPEED SoCs. -+ -+ This support is also available as a module. If so, the module -+ will be called peci-aspeed. -+ -+config PECI_NPCM -+ tristate "Nuvoton NPCM PECI support" -+ select REGMAP_MMIO -+ depends on OF -+ depends on ARCH_NPCM || COMPILE_TEST -+ depends on PECI -+ help -+ Say Y here if you want support for the Platform Environment Control -+ Interface (PECI) bus adapter driver on the Nuvoton NPCM SoCs. -+ -+ This support is also available as a module. If so, the module -+ will be called peci-npcm. -+ -+endmenu -diff --git a/drivers/peci/busses/Makefile b/drivers/peci/busses/Makefile -new file mode 100644 -index 0000000..aa8ce3a ---- /dev/null -+++ b/drivers/peci/busses/Makefile -@@ -0,0 +1,7 @@ -+# SPDX-License-Identifier: GPL-2.0 -+# -+# Makefile for the PECI hardware bus drivers. -+# -+ -+obj-$(CONFIG_PECI_ASPEED) += peci-aspeed.o -+obj-$(CONFIG_PECI_NPCM) += peci-npcm.o -diff --git a/drivers/peci/busses/peci-aspeed.c b/drivers/peci/busses/peci-aspeed.c -new file mode 100644 -index 0000000..851b71e3 ---- /dev/null -+++ b/drivers/peci/busses/peci-aspeed.c -@@ -0,0 +1,492 @@ -+// SPDX-License-Identifier: GPL-2.0 -+// Copyright (C) 2012-2017 ASPEED Technology Inc. -+// Copyright (c) 2018-2019 Intel Corporation -+ -+#include <linux/bitfield.h> -+#include <linux/clk.h> -+#include <linux/delay.h> -+#include <linux/interrupt.h> -+#include <linux/io.h> -+#include <linux/jiffies.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/peci.h> -+#include <linux/platform_device.h> -+#include <linux/reset.h> -+ -+/* ASPEED PECI Registers */ -+/* Control Register */ -+#define ASPEED_PECI_CTRL 0x00 -+#define ASPEED_PECI_CTRL_SAMPLING_MASK GENMASK(19, 16) -+#define ASPEED_PECI_CTRL_READ_MODE_MASK GENMASK(13, 12) -+#define ASPEED_PECI_CTRL_READ_MODE_COUNT BIT(12) -+#define ASPEED_PECI_CTRL_READ_MODE_DBG BIT(13) -+#define ASPEED_PECI_CTRL_CLK_SOURCE_MASK BIT(11) -+#define ASPEED_PECI_CTRL_CLK_DIV_MASK GENMASK(10, 8) -+#define ASPEED_PECI_CTRL_INVERT_OUT BIT(7) -+#define ASPEED_PECI_CTRL_INVERT_IN BIT(6) -+#define ASPEED_PECI_CTRL_BUS_CONTENT_EN BIT(5) -+#define ASPEED_PECI_CTRL_PECI_EN BIT(4) -+#define ASPEED_PECI_CTRL_PECI_CLK_EN BIT(0) -+ -+/* Timing Negotiation Register */ -+#define ASPEED_PECI_TIMING_NEGOTIATION 0x04 -+#define ASPEED_PECI_TIMING_MESSAGE_MASK GENMASK(15, 8) -+#define ASPEED_PECI_TIMING_ADDRESS_MASK GENMASK(7, 0) -+ -+/* Command Register */ -+#define ASPEED_PECI_CMD 0x08 -+#define ASPEED_PECI_CMD_PIN_MON BIT(31) -+#define ASPEED_PECI_CMD_STS_MASK GENMASK(27, 24) -+#define ASPEED_PECI_CMD_IDLE_MASK (ASPEED_PECI_CMD_STS_MASK | \ -+ ASPEED_PECI_CMD_PIN_MON) -+#define ASPEED_PECI_CMD_FIRE BIT(0) -+ -+/* Read/Write Length Register */ -+#define ASPEED_PECI_RW_LENGTH 0x0c -+#define ASPEED_PECI_AW_FCS_EN BIT(31) -+#define ASPEED_PECI_READ_LEN_MASK GENMASK(23, 16) -+#define ASPEED_PECI_WRITE_LEN_MASK GENMASK(15, 8) -+#define ASPEED_PECI_TAGET_ADDR_MASK GENMASK(7, 0) -+ -+/* Expected FCS Data Register */ -+#define ASPEED_PECI_EXP_FCS 0x10 -+#define ASPEED_PECI_EXP_READ_FCS_MASK GENMASK(23, 16) -+#define ASPEED_PECI_EXP_AW_FCS_AUTO_MASK GENMASK(15, 8) -+#define ASPEED_PECI_EXP_WRITE_FCS_MASK GENMASK(7, 0) -+ -+/* Captured FCS Data Register */ -+#define ASPEED_PECI_CAP_FCS 0x14 -+#define ASPEED_PECI_CAP_READ_FCS_MASK GENMASK(23, 16) -+#define ASPEED_PECI_CAP_WRITE_FCS_MASK GENMASK(7, 0) -+ -+/* Interrupt Register */ -+#define ASPEED_PECI_INT_CTRL 0x18 -+#define ASPEED_PECI_TIMING_NEGO_SEL_MASK GENMASK(31, 30) -+#define ASPEED_PECI_1ST_BIT_OF_ADDR_NEGO 0 -+#define ASPEED_PECI_2ND_BIT_OF_ADDR_NEGO 1 -+#define ASPEED_PECI_MESSAGE_NEGO 2 -+#define ASPEED_PECI_INT_MASK GENMASK(4, 0) -+#define ASPEED_PECI_INT_BUS_TIMEOUT BIT(4) -+#define ASPEED_PECI_INT_BUS_CONNECT BIT(3) -+#define ASPEED_PECI_INT_W_FCS_BAD BIT(2) -+#define ASPEED_PECI_INT_W_FCS_ABORT BIT(1) -+#define ASPEED_PECI_INT_CMD_DONE BIT(0) -+ -+/* Interrupt Status Register */ -+#define ASPEED_PECI_INT_STS 0x1c -+#define ASPEED_PECI_INT_TIMING_RESULT_MASK GENMASK(29, 16) -+ /* bits[4..0]: Same bit fields in the 'Interrupt Register' */ -+ -+/* Rx/Tx Data Buffer Registers */ -+#define ASPEED_PECI_W_DATA0 0x20 -+#define ASPEED_PECI_W_DATA1 0x24 -+#define ASPEED_PECI_W_DATA2 0x28 -+#define ASPEED_PECI_W_DATA3 0x2c -+#define ASPEED_PECI_R_DATA0 0x30 -+#define ASPEED_PECI_R_DATA1 0x34 -+#define ASPEED_PECI_R_DATA2 0x38 -+#define ASPEED_PECI_R_DATA3 0x3c -+#define ASPEED_PECI_W_DATA4 0x40 -+#define ASPEED_PECI_W_DATA5 0x44 -+#define ASPEED_PECI_W_DATA6 0x48 -+#define ASPEED_PECI_W_DATA7 0x4c -+#define ASPEED_PECI_R_DATA4 0x50 -+#define ASPEED_PECI_R_DATA5 0x54 -+#define ASPEED_PECI_R_DATA6 0x58 -+#define ASPEED_PECI_R_DATA7 0x5c -+#define ASPEED_PECI_DATA_BUF_SIZE_MAX 32 -+ -+/* Timing Negotiation */ -+#define ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT 8 -+#define ASPEED_PECI_RD_SAMPLING_POINT_MAX 15 -+#define ASPEED_PECI_CLK_DIV_DEFAULT 0 -+#define ASPEED_PECI_CLK_DIV_MAX 7 -+#define ASPEED_PECI_MSG_TIMING_DEFAULT 1 -+#define ASPEED_PECI_MSG_TIMING_MAX 255 -+#define ASPEED_PECI_ADDR_TIMING_DEFAULT 1 -+#define ASPEED_PECI_ADDR_TIMING_MAX 255 -+ -+/* Timeout */ -+#define ASPEED_PECI_IDLE_CHECK_TIMEOUT_USEC 50000 -+#define ASPEED_PECI_IDLE_CHECK_INTERVAL_USEC 10000 -+#define ASPEED_PECI_CMD_TIMEOUT_MS_DEFAULT 1000 -+#define ASPEED_PECI_CMD_TIMEOUT_MS_MAX 60000 -+ -+struct aspeed_peci { -+ struct peci_adapter *adapter; -+ struct device *dev; -+ void __iomem *base; -+ struct clk *clk; -+ struct reset_control *rst; -+ int irq; -+ spinlock_t lock; /* to sync completion status handling */ -+ struct completion xfer_complete; -+ u32 status; -+ u32 cmd_timeout_ms; -+}; -+ -+static int aspeed_peci_check_idle(struct aspeed_peci *priv) -+{ -+ ulong timeout = jiffies + usecs_to_jiffies(ASPEED_PECI_IDLE_CHECK_TIMEOUT_USEC); -+ u32 cmd_sts; -+ -+ for (;;) { -+ cmd_sts = readl(priv->base + ASPEED_PECI_CMD); -+ if (!(cmd_sts & ASPEED_PECI_CMD_IDLE_MASK)) -+ break; -+ if (time_after(jiffies, timeout)) { -+ cmd_sts = readl(priv->base + ASPEED_PECI_CMD); -+ break; -+ } -+ usleep_range((ASPEED_PECI_IDLE_CHECK_INTERVAL_USEC >> 2) + 1, -+ ASPEED_PECI_IDLE_CHECK_INTERVAL_USEC); -+ } -+ -+ return !(cmd_sts & ASPEED_PECI_CMD_IDLE_MASK) ? 0 : -ETIMEDOUT; -+} -+ -+static int aspeed_peci_xfer(struct peci_adapter *adapter, -+ struct peci_xfer_msg *msg) -+{ -+ struct aspeed_peci *priv = peci_get_adapdata(adapter); -+ long err, timeout = msecs_to_jiffies(priv->cmd_timeout_ms); -+ u32 peci_head, peci_state, rx_data = 0; -+ ulong flags; -+ int i, ret; -+ uint reg; -+ -+ if (msg->tx_len > ASPEED_PECI_DATA_BUF_SIZE_MAX || -+ msg->rx_len > ASPEED_PECI_DATA_BUF_SIZE_MAX) -+ return -EINVAL; -+ -+ /* Check command sts and bus idle state */ -+ ret = aspeed_peci_check_idle(priv); -+ if (ret) -+ return ret; /* -ETIMEDOUT */ -+ -+ spin_lock_irqsave(&priv->lock, flags); -+ reinit_completion(&priv->xfer_complete); -+ -+ peci_head = FIELD_PREP(ASPEED_PECI_TAGET_ADDR_MASK, msg->addr) | -+ FIELD_PREP(ASPEED_PECI_WRITE_LEN_MASK, msg->tx_len) | -+ FIELD_PREP(ASPEED_PECI_READ_LEN_MASK, msg->rx_len); -+ -+ writel(peci_head, priv->base + ASPEED_PECI_RW_LENGTH); -+ -+ for (i = 0; i < msg->tx_len; i += 4) { -+ reg = i < 16 ? ASPEED_PECI_W_DATA0 + i % 16 : -+ ASPEED_PECI_W_DATA4 + i % 16; -+ writel(le32_to_cpup((__le32 *)&msg->tx_buf[i]), -+ priv->base + reg); -+ } -+ -+ dev_dbg(priv->dev, "HEAD : 0x%08x\n", peci_head); -+ print_hex_dump_debug("TX : ", DUMP_PREFIX_NONE, 16, 1, -+ msg->tx_buf, msg->tx_len, true); -+ -+ priv->status = 0; -+ writel(ASPEED_PECI_CMD_FIRE, priv->base + ASPEED_PECI_CMD); -+ spin_unlock_irqrestore(&priv->lock, flags); -+ -+ err = wait_for_completion_interruptible_timeout(&priv->xfer_complete, -+ timeout); -+ -+ spin_lock_irqsave(&priv->lock, flags); -+ dev_dbg(priv->dev, "INT_STS : 0x%08x\n", priv->status); -+ peci_state = readl(priv->base + ASPEED_PECI_CMD); -+ dev_dbg(priv->dev, "PECI_STATE : 0x%lx\n", -+ FIELD_GET(ASPEED_PECI_CMD_STS_MASK, peci_state)); -+ -+ writel(0, priv->base + ASPEED_PECI_CMD); -+ -+ if (err <= 0 || priv->status != ASPEED_PECI_INT_CMD_DONE) { -+ if (err < 0) { /* -ERESTARTSYS */ -+ ret = (int)err; -+ goto err_irqrestore; -+ } else if (err == 0) { -+ dev_dbg(priv->dev, "Timeout waiting for a response!\n"); -+ ret = -ETIMEDOUT; -+ goto err_irqrestore; -+ } -+ -+ dev_dbg(priv->dev, "No valid response!\n"); -+ ret = -EIO; -+ goto err_irqrestore; -+ } -+ -+ /* -+ * Note that rx_len and rx_buf size can be an odd number. -+ * Byte handling is more efficient. -+ */ -+ for (i = 0; i < msg->rx_len; i++) { -+ u8 byte_offset = i % 4; -+ -+ if (byte_offset == 0) { -+ reg = i < 16 ? ASPEED_PECI_R_DATA0 + i % 16 : -+ ASPEED_PECI_R_DATA4 + i % 16; -+ rx_data = readl(priv->base + reg); -+ } -+ -+ msg->rx_buf[i] = (u8)(rx_data >> (byte_offset << 3)); -+ } -+ -+ print_hex_dump_debug("RX : ", DUMP_PREFIX_NONE, 16, 1, -+ msg->rx_buf, msg->rx_len, true); -+ -+ peci_state = readl(priv->base + ASPEED_PECI_CMD); -+ dev_dbg(priv->dev, "PECI_STATE : 0x%lx\n", -+ FIELD_GET(ASPEED_PECI_CMD_STS_MASK, peci_state)); -+ dev_dbg(priv->dev, "------------------------\n"); -+ -+err_irqrestore: -+ spin_unlock_irqrestore(&priv->lock, flags); -+ return ret; -+} -+ -+static irqreturn_t aspeed_peci_irq_handler(int irq, void *arg) -+{ -+ struct aspeed_peci *priv = arg; -+ u32 status; -+ -+ spin_lock(&priv->lock); -+ status = readl(priv->base + ASPEED_PECI_INT_STS); -+ writel(status, priv->base + ASPEED_PECI_INT_STS); -+ priv->status |= (status & ASPEED_PECI_INT_MASK); -+ -+ /* -+ * In most cases, interrupt bits will be set one by one but also note -+ * that multiple interrupt bits could be set at the same time. -+ */ -+ if (status & ASPEED_PECI_INT_BUS_TIMEOUT) { -+ dev_dbg(priv->dev, "ASPEED_PECI_INT_BUS_TIMEOUT\n"); -+ } -+ -+ if (status & ASPEED_PECI_INT_BUS_CONNECT) { -+ dev_dbg(priv->dev, "ASPEED_PECI_INT_BUS_CONNECT\n"); -+ } -+ -+ if (status & ASPEED_PECI_INT_W_FCS_BAD) { -+ dev_dbg(priv->dev, "ASPEED_PECI_INT_W_FCS_BAD\n"); -+ } -+ -+ if (status & ASPEED_PECI_INT_W_FCS_ABORT) { -+ dev_dbg(priv->dev, "ASPEED_PECI_INT_W_FCS_ABORT\n"); -+ } -+ -+ /* -+ * All commands should be ended up with a ASPEED_PECI_INT_CMD_DONE bit -+ * set even in an error case. -+ */ -+ if (status & ASPEED_PECI_INT_CMD_DONE) { -+ dev_dbg(priv->dev, "ASPEED_PECI_INT_CMD_DONE\n"); -+ complete(&priv->xfer_complete); -+ } -+ -+ spin_unlock(&priv->lock); -+ return IRQ_HANDLED; -+} -+ -+static int aspeed_peci_init_ctrl(struct aspeed_peci *priv) -+{ -+ u32 msg_timing, addr_timing, rd_sampling_point; -+ u32 clk_freq, clk_divisor, clk_div_val = 0; -+ int ret; -+ -+ priv->clk = devm_clk_get(priv->dev, NULL); -+ if (IS_ERR(priv->clk)) { -+ dev_err(priv->dev, "Failed to get clk source.\n"); -+ return PTR_ERR(priv->clk); -+ } -+ -+ ret = clk_prepare_enable(priv->clk); -+ if (ret) { -+ dev_err(priv->dev, "Failed to enable clock.\n"); -+ return ret; -+ } -+ -+ ret = device_property_read_u32(priv->dev, "clock-frequency", &clk_freq); -+ if (ret) { -+ dev_err(priv->dev, -+ "Could not read clock-frequency property.\n"); -+ clk_disable_unprepare(priv->clk); -+ return ret; -+ } -+ -+ clk_divisor = clk_get_rate(priv->clk) / clk_freq; -+ -+ while ((clk_divisor >> 1) && (clk_div_val < ASPEED_PECI_CLK_DIV_MAX)) -+ clk_div_val++; -+ -+ ret = device_property_read_u32(priv->dev, "msg-timing", &msg_timing); -+ if (ret || msg_timing > ASPEED_PECI_MSG_TIMING_MAX) { -+ if (!ret) -+ dev_warn(priv->dev, -+ "Invalid msg-timing : %u, Use default : %u\n", -+ msg_timing, ASPEED_PECI_MSG_TIMING_DEFAULT); -+ msg_timing = ASPEED_PECI_MSG_TIMING_DEFAULT; -+ } -+ -+ ret = device_property_read_u32(priv->dev, "addr-timing", &addr_timing); -+ if (ret || addr_timing > ASPEED_PECI_ADDR_TIMING_MAX) { -+ if (!ret) -+ dev_warn(priv->dev, -+ "Invalid addr-timing : %u, Use default : %u\n", -+ addr_timing, ASPEED_PECI_ADDR_TIMING_DEFAULT); -+ addr_timing = ASPEED_PECI_ADDR_TIMING_DEFAULT; -+ } -+ -+ ret = device_property_read_u32(priv->dev, "rd-sampling-point", -+ &rd_sampling_point); -+ if (ret || rd_sampling_point > ASPEED_PECI_RD_SAMPLING_POINT_MAX) { -+ if (!ret) -+ dev_warn(priv->dev, -+ "Invalid rd-sampling-point : %u. Use default : %u\n", -+ rd_sampling_point, -+ ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT); -+ rd_sampling_point = ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT; -+ } -+ -+ ret = device_property_read_u32(priv->dev, "cmd-timeout-ms", -+ &priv->cmd_timeout_ms); -+ if (ret || priv->cmd_timeout_ms > ASPEED_PECI_CMD_TIMEOUT_MS_MAX || -+ priv->cmd_timeout_ms == 0) { -+ if (!ret) -+ dev_warn(priv->dev, -+ "Invalid cmd-timeout-ms : %u. Use default : %u\n", -+ priv->cmd_timeout_ms, -+ ASPEED_PECI_CMD_TIMEOUT_MS_DEFAULT); -+ priv->cmd_timeout_ms = ASPEED_PECI_CMD_TIMEOUT_MS_DEFAULT; -+ } -+ -+ writel(FIELD_PREP(ASPEED_PECI_CTRL_CLK_DIV_MASK, -+ ASPEED_PECI_CLK_DIV_DEFAULT) | -+ ASPEED_PECI_CTRL_PECI_CLK_EN, priv->base + ASPEED_PECI_CTRL); -+ -+ /* -+ * Timing negotiation period setting. -+ * The unit of the programmed value is 4 times of PECI clock period. -+ */ -+ writel(FIELD_PREP(ASPEED_PECI_TIMING_MESSAGE_MASK, msg_timing) | -+ FIELD_PREP(ASPEED_PECI_TIMING_ADDRESS_MASK, addr_timing), -+ priv->base + ASPEED_PECI_TIMING_NEGOTIATION); -+ -+ /* Clear interrupts */ -+ writel(readl(priv->base + ASPEED_PECI_INT_STS) | ASPEED_PECI_INT_MASK, -+ priv->base + ASPEED_PECI_INT_STS); -+ -+ /* Set timing negotiation mode and enable interrupts */ -+ writel(FIELD_PREP(ASPEED_PECI_TIMING_NEGO_SEL_MASK, -+ ASPEED_PECI_1ST_BIT_OF_ADDR_NEGO) | -+ ASPEED_PECI_INT_MASK, priv->base + ASPEED_PECI_INT_CTRL); -+ -+ /* Read sampling point and clock speed setting */ -+ writel(FIELD_PREP(ASPEED_PECI_CTRL_SAMPLING_MASK, rd_sampling_point) | -+ FIELD_PREP(ASPEED_PECI_CTRL_CLK_DIV_MASK, clk_div_val) | -+ ASPEED_PECI_CTRL_PECI_EN | ASPEED_PECI_CTRL_PECI_CLK_EN, -+ priv->base + ASPEED_PECI_CTRL); -+ -+ return 0; -+} -+ -+static int aspeed_peci_probe(struct platform_device *pdev) -+{ -+ struct peci_adapter *adapter; -+ struct aspeed_peci *priv; -+ int ret; -+ -+ adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv)); -+ if (!adapter) -+ return -ENOMEM; -+ -+ priv = peci_get_adapdata(adapter); -+ priv->adapter = adapter; -+ priv->dev = &pdev->dev; -+ dev_set_drvdata(&pdev->dev, priv); -+ -+ priv->base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(priv->base)) { -+ ret = PTR_ERR(priv->base); -+ goto err_put_adapter_dev; -+ } -+ -+ priv->irq = platform_get_irq(pdev, 0); -+ if (!priv->irq) { -+ ret = -ENODEV; -+ goto err_put_adapter_dev; -+ } -+ -+ ret = devm_request_irq(&pdev->dev, priv->irq, aspeed_peci_irq_handler, -+ 0, "peci-aspeed-irq", priv); -+ if (ret) -+ goto err_put_adapter_dev; -+ -+ init_completion(&priv->xfer_complete); -+ spin_lock_init(&priv->lock); -+ -+ priv->adapter->owner = THIS_MODULE; -+ priv->adapter->dev.of_node = of_node_get(dev_of_node(priv->dev)); -+ strlcpy(priv->adapter->name, pdev->name, sizeof(priv->adapter->name)); -+ priv->adapter->xfer = aspeed_peci_xfer; -+ priv->adapter->use_dma = false; -+ -+ priv->rst = devm_reset_control_get(&pdev->dev, NULL); -+ if (IS_ERR(priv->rst)) { -+ dev_err(&pdev->dev, -+ "missing or invalid reset controller entry\n"); -+ ret = PTR_ERR(priv->rst); -+ goto err_put_adapter_dev; -+ } -+ reset_control_deassert(priv->rst); -+ -+ ret = aspeed_peci_init_ctrl(priv); -+ if (ret) -+ goto err_put_adapter_dev; -+ -+ ret = peci_add_adapter(priv->adapter); -+ if (ret) -+ goto err_put_adapter_dev; -+ -+ dev_info(&pdev->dev, "peci bus %d registered, irq %d\n", -+ priv->adapter->nr, priv->irq); -+ -+ return 0; -+ -+err_put_adapter_dev: -+ put_device(&adapter->dev); -+ return ret; -+} -+ -+static int aspeed_peci_remove(struct platform_device *pdev) -+{ -+ struct aspeed_peci *priv = dev_get_drvdata(&pdev->dev); -+ -+ clk_disable_unprepare(priv->clk); -+ reset_control_assert(priv->rst); -+ peci_del_adapter(priv->adapter); -+ of_node_put(priv->adapter->dev.of_node); -+ -+ return 0; -+} -+ -+static const struct of_device_id aspeed_peci_of_table[] = { -+ { .compatible = "aspeed,ast2400-peci", }, -+ { .compatible = "aspeed,ast2500-peci", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, aspeed_peci_of_table); -+ -+static struct platform_driver aspeed_peci_driver = { -+ .probe = aspeed_peci_probe, -+ .remove = aspeed_peci_remove, -+ .driver = { -+ .name = KBUILD_MODNAME, -+ .of_match_table = of_match_ptr(aspeed_peci_of_table), -+ }, -+}; -+module_platform_driver(aspeed_peci_driver); -+ -+MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>"); -+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>"); -+MODULE_DESCRIPTION("ASPEED PECI driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/peci/busses/peci-npcm.c b/drivers/peci/busses/peci-npcm.c -new file mode 100644 -index 0000000..f632365 ---- /dev/null -+++ b/drivers/peci/busses/peci-npcm.c -@@ -0,0 +1,410 @@ -+// SPDX-License-Identifier: GPL-2.0 -+// Copyright (c) 2019 Nuvoton Technology corporation. -+ -+#include <linux/bitfield.h> -+#include <linux/clk.h> -+#include <linux/interrupt.h> -+#include <linux/jiffies.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/peci.h> -+#include <linux/platform_device.h> -+#include <linux/regmap.h> -+#include <linux/mfd/syscon.h> -+#include <linux/reset.h> -+ -+/* NPCM7xx GCR module */ -+#define NPCM7XX_INTCR3_OFFSET 0x9C -+#define NPCM7XX_INTCR3_PECIVSEL BIT(19) -+ -+/* NPCM PECI Registers */ -+#define NPCM_PECI_CTL_STS 0x00 -+#define NPCM_PECI_RD_LENGTH 0x04 -+#define NPCM_PECI_ADDR 0x08 -+#define NPCM_PECI_CMD 0x0C -+#define NPCM_PECI_CTL2 0x10 -+#define NPCM_PECI_WR_LENGTH 0x1C -+#define NPCM_PECI_PDDR 0x2C -+#define NPCM_PECI_DAT_INOUT(n) (0x100 + ((n) * 4)) -+ -+#define NPCM_PECI_MAX_REG 0x200 -+ -+/* NPCM_PECI_CTL_STS - 0x00 : Control Register */ -+#define NPCM_PECI_CTRL_DONE_INT_EN BIT(6) -+#define NPCM_PECI_CTRL_ABRT_ERR BIT(4) -+#define NPCM_PECI_CTRL_CRC_ERR BIT(3) -+#define NPCM_PECI_CTRL_DONE BIT(1) -+#define NPCM_PECI_CTRL_START_BUSY BIT(0) -+ -+/* NPCM_PECI_RD_LENGTH - 0x04 : Command Register */ -+#define NPCM_PECI_RD_LEN_MASK GENMASK(6, 0) -+ -+/* NPCM_PECI_CMD - 0x10 : Command Register */ -+#define NPCM_PECI_CTL2_MASK GENMASK(7, 6) -+ -+/* NPCM_PECI_WR_LENGTH - 0x1C : Command Register */ -+#define NPCM_PECI_WR_LEN_MASK GENMASK(6, 0) -+ -+/* NPCM_PECI_PDDR - 0x2C : Command Register */ -+#define NPCM_PECI_PDDR_MASK GENMASK(4, 0) -+ -+#define NPCM_PECI_INT_MASK (NPCM_PECI_CTRL_ABRT_ERR | \ -+ NPCM_PECI_CTRL_CRC_ERR | \ -+ NPCM_PECI_CTRL_DONE) -+ -+#define NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC 50000 -+#define NPCM_PECI_IDLE_CHECK_INTERVAL_USEC 10000 -+#define NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT 1000 -+#define NPCM_PECI_CMD_TIMEOUT_MS_MAX 60000 -+#define NPCM_PECI_HOST_NEG_BIT_RATE_MAX 31 -+#define NPCM_PECI_HOST_NEG_BIT_RATE_MIN 7 -+#define NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT 15 -+#define NPCM_PECI_PULL_DOWN_DEFAULT 0 -+#define NPCM_PECI_PULL_DOWN_MAX 2 -+ -+struct npcm_peci { -+ u32 cmd_timeout_ms; -+ u32 host_bit_rate; -+ struct completion xfer_complete; -+ struct regmap *gcr_regmap; -+ struct peci_adapter *adapter; -+ struct regmap *regmap; -+ u32 status; -+ spinlock_t lock; /* to sync completion status handling */ -+ struct device *dev; -+ struct clk *clk; -+ int irq; -+}; -+ -+static int npcm_peci_xfer_native(struct npcm_peci *priv, -+ struct peci_xfer_msg *msg) -+{ -+ long err, timeout = msecs_to_jiffies(priv->cmd_timeout_ms); -+ unsigned long flags; -+ unsigned int msg_rd; -+ u32 cmd_sts; -+ int i, rc; -+ -+ /* Check command sts and bus idle state */ -+ rc = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts, -+ !(cmd_sts & NPCM_PECI_CTRL_START_BUSY), -+ NPCM_PECI_IDLE_CHECK_INTERVAL_USEC, -+ NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC); -+ if (rc) -+ return rc; /* -ETIMEDOUT */ -+ -+ spin_lock_irqsave(&priv->lock, flags); -+ reinit_completion(&priv->xfer_complete); -+ -+ regmap_write(priv->regmap, NPCM_PECI_ADDR, msg->addr); -+ regmap_write(priv->regmap, NPCM_PECI_RD_LENGTH, -+ NPCM_PECI_WR_LEN_MASK & msg->rx_len); -+ regmap_write(priv->regmap, NPCM_PECI_WR_LENGTH, -+ NPCM_PECI_WR_LEN_MASK & msg->tx_len); -+ -+ if (msg->tx_len) { -+ regmap_write(priv->regmap, NPCM_PECI_CMD, msg->tx_buf[0]); -+ -+ for (i = 0; i < (msg->tx_len - 1); i++) -+ regmap_write(priv->regmap, NPCM_PECI_DAT_INOUT(i), -+ msg->tx_buf[i + 1]); -+ } -+ -+ priv->status = 0; -+ regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS, -+ NPCM_PECI_CTRL_START_BUSY, -+ NPCM_PECI_CTRL_START_BUSY); -+ -+ spin_unlock_irqrestore(&priv->lock, flags); -+ -+ err = wait_for_completion_interruptible_timeout(&priv->xfer_complete, -+ timeout); -+ -+ spin_lock_irqsave(&priv->lock, flags); -+ -+ regmap_write(priv->regmap, NPCM_PECI_CMD, 0); -+ -+ if (err <= 0 || priv->status != NPCM_PECI_CTRL_DONE) { -+ if (err < 0) { /* -ERESTARTSYS */ -+ rc = (int)err; -+ goto err_irqrestore; -+ } else if (err == 0) { -+ dev_dbg(priv->dev, "Timeout waiting for a response!\n"); -+ rc = -ETIMEDOUT; -+ goto err_irqrestore; -+ } -+ -+ dev_dbg(priv->dev, "No valid response!\n"); -+ rc = -EIO; -+ goto err_irqrestore; -+ } -+ -+ for (i = 0; i < msg->rx_len; i++) { -+ regmap_read(priv->regmap, NPCM_PECI_DAT_INOUT(i), &msg_rd); -+ msg->rx_buf[i] = (u8)msg_rd; -+ } -+ -+err_irqrestore: -+ spin_unlock_irqrestore(&priv->lock, flags); -+ return rc; -+} -+ -+static irqreturn_t npcm_peci_irq_handler(int irq, void *arg) -+{ -+ struct npcm_peci *priv = arg; -+ u32 status_ack = 0; -+ u32 status; -+ -+ spin_lock(&priv->lock); -+ regmap_read(priv->regmap, NPCM_PECI_CTL_STS, &status); -+ priv->status |= (status & NPCM_PECI_INT_MASK); -+ -+ if (status & NPCM_PECI_CTRL_CRC_ERR) { -+ dev_dbg(priv->dev, "PECI_INT_W_FCS_BAD\n"); -+ status_ack |= NPCM_PECI_CTRL_CRC_ERR; -+ } -+ -+ if (status & NPCM_PECI_CTRL_ABRT_ERR) { -+ dev_dbg(priv->dev, "NPCM_PECI_CTRL_ABRT_ERR\n"); -+ status_ack |= NPCM_PECI_CTRL_ABRT_ERR; -+ } -+ -+ /* -+ * All commands should be ended up with a NPCM_PECI_CTRL_DONE -+ * bit set even in an error case. -+ */ -+ if (status & NPCM_PECI_CTRL_DONE) { -+ dev_dbg(priv->dev, "NPCM_PECI_CTRL_DONE\n"); -+ status_ack |= NPCM_PECI_CTRL_DONE; -+ complete(&priv->xfer_complete); -+ } -+ -+ regmap_write_bits(priv->regmap, NPCM_PECI_CTL_STS, -+ NPCM_PECI_INT_MASK, status_ack); -+ -+ spin_unlock(&priv->lock); -+ return IRQ_HANDLED; -+} -+ -+static int npcm_peci_init_ctrl(struct npcm_peci *priv) -+{ -+ u32 cmd_sts, host_neg_bit_rate = 0, pull_down = 0; -+ int ret; -+ bool volt; -+ -+ priv->clk = devm_clk_get(priv->dev, NULL); -+ if (IS_ERR(priv->clk)) { -+ dev_err(priv->dev, "Failed to get clk source.\n"); -+ return PTR_ERR(priv->clk); -+ } -+ -+ ret = clk_prepare_enable(priv->clk); -+ if (ret) { -+ dev_err(priv->dev, "Failed to enable clock.\n"); -+ return ret; -+ } -+ -+ ret = of_property_read_u32(priv->dev->of_node, "cmd-timeout-ms", -+ &priv->cmd_timeout_ms); -+ if (ret || priv->cmd_timeout_ms > NPCM_PECI_CMD_TIMEOUT_MS_MAX || -+ priv->cmd_timeout_ms == 0) { -+ if (ret) -+ dev_warn(priv->dev, -+ "cmd-timeout-ms not found, use default : %u\n", -+ NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT); -+ else -+ dev_warn(priv->dev, -+ "Invalid cmd-timeout-ms : %u. Use default : %u\n", -+ priv->cmd_timeout_ms, -+ NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT); -+ -+ priv->cmd_timeout_ms = NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT; -+ } -+ -+ if (of_device_is_compatible(priv->dev->of_node, -+ "nuvoton,npcm750-peci")) { -+ priv->gcr_regmap = syscon_regmap_lookup_by_compatible -+ ("nuvoton,npcm750-gcr"); -+ if (!IS_ERR(priv->gcr_regmap)) { -+ volt = of_property_read_bool(priv->dev->of_node, -+ "high-volt-range"); -+ if (volt) -+ regmap_update_bits(priv->gcr_regmap, -+ NPCM7XX_INTCR3_OFFSET, -+ NPCM7XX_INTCR3_PECIVSEL, -+ NPCM7XX_INTCR3_PECIVSEL); -+ else -+ regmap_update_bits(priv->gcr_regmap, -+ NPCM7XX_INTCR3_OFFSET, -+ NPCM7XX_INTCR3_PECIVSEL, 0); -+ } -+ } -+ -+ ret = of_property_read_u32(priv->dev->of_node, "pull-down", -+ &pull_down); -+ if (ret || pull_down > NPCM_PECI_PULL_DOWN_MAX) { -+ if (ret) -+ dev_warn(priv->dev, -+ "pull-down not found, use default : %u\n", -+ NPCM_PECI_PULL_DOWN_DEFAULT); -+ else -+ dev_warn(priv->dev, -+ "Invalid pull-down : %u. Use default : %u\n", -+ pull_down, -+ NPCM_PECI_PULL_DOWN_DEFAULT); -+ pull_down = NPCM_PECI_PULL_DOWN_DEFAULT; -+ } -+ -+ regmap_update_bits(priv->regmap, NPCM_PECI_CTL2, NPCM_PECI_CTL2_MASK, -+ pull_down << 6); -+ -+ ret = of_property_read_u32(priv->dev->of_node, "host-neg-bit-rate", -+ &host_neg_bit_rate); -+ if (ret || host_neg_bit_rate > NPCM_PECI_HOST_NEG_BIT_RATE_MAX || -+ host_neg_bit_rate < NPCM_PECI_HOST_NEG_BIT_RATE_MIN) { -+ if (ret) -+ dev_warn(priv->dev, -+ "host-neg-bit-rate not found, use default : %u\n", -+ NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT); -+ else -+ dev_warn(priv->dev, -+ "Invalid host-neg-bit-rate : %u. Use default : %u\n", -+ host_neg_bit_rate, -+ NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT); -+ host_neg_bit_rate = NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT; -+ } -+ -+ regmap_update_bits(priv->regmap, NPCM_PECI_PDDR, NPCM_PECI_PDDR_MASK, -+ host_neg_bit_rate); -+ -+ priv->host_bit_rate = clk_get_rate(priv->clk) / -+ (4 * (host_neg_bit_rate + 1)); -+ -+ ret = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts, -+ !(cmd_sts & NPCM_PECI_CTRL_START_BUSY), -+ NPCM_PECI_IDLE_CHECK_INTERVAL_USEC, -+ NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC); -+ if (ret) -+ return ret; /* -ETIMEDOUT */ -+ -+ /* PECI interrupt enable */ -+ regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS, -+ NPCM_PECI_CTRL_DONE_INT_EN, -+ NPCM_PECI_CTRL_DONE_INT_EN); -+ -+ return 0; -+} -+ -+static const struct regmap_config npcm_peci_regmap_config = { -+ .reg_bits = 8, -+ .val_bits = 8, -+ .max_register = NPCM_PECI_MAX_REG, -+ .fast_io = true, -+}; -+ -+static int npcm_peci_xfer(struct peci_adapter *adapter, -+ struct peci_xfer_msg *msg) -+{ -+ struct npcm_peci *priv = peci_get_adapdata(adapter); -+ -+ return npcm_peci_xfer_native(priv, msg); -+} -+ -+static int npcm_peci_probe(struct platform_device *pdev) -+{ -+ struct peci_adapter *adapter; -+ struct npcm_peci *priv; -+ struct resource *res; -+ void __iomem *base; -+ int ret; -+ -+ adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv)); -+ if (!adapter) -+ return -ENOMEM; -+ -+ priv = peci_get_adapdata(adapter); -+ priv->adapter = adapter; -+ priv->dev = &pdev->dev; -+ dev_set_drvdata(&pdev->dev, priv); -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(base)) { -+ ret = PTR_ERR(base); -+ goto err_put_adapter_dev; -+ } -+ -+ priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, -+ &npcm_peci_regmap_config); -+ if (IS_ERR(priv->regmap)) { -+ ret = PTR_ERR(priv->regmap); -+ goto err_put_adapter_dev; -+ } -+ -+ priv->irq = platform_get_irq(pdev, 0); -+ if (!priv->irq) { -+ ret = -ENODEV; -+ goto err_put_adapter_dev; -+ } -+ -+ ret = devm_request_irq(&pdev->dev, priv->irq, npcm_peci_irq_handler, -+ 0, "peci-npcm-irq", priv); -+ if (ret) -+ goto err_put_adapter_dev; -+ -+ init_completion(&priv->xfer_complete); -+ spin_lock_init(&priv->lock); -+ -+ priv->adapter->owner = THIS_MODULE; -+ priv->adapter->dev.of_node = of_node_get(dev_of_node(priv->dev)); -+ strlcpy(priv->adapter->name, pdev->name, sizeof(priv->adapter->name)); -+ priv->adapter->xfer = npcm_peci_xfer; -+ -+ ret = npcm_peci_init_ctrl(priv); -+ if (ret) -+ goto err_put_adapter_dev; -+ -+ ret = peci_add_adapter(priv->adapter); -+ if (ret) -+ goto err_put_adapter_dev; -+ -+ dev_info(&pdev->dev, "peci bus %d registered, host negotiation bit rate %dHz", -+ priv->adapter->nr, priv->host_bit_rate); -+ -+ return 0; -+ -+err_put_adapter_dev: -+ put_device(&adapter->dev); -+ return ret; -+} -+ -+static int npcm_peci_remove(struct platform_device *pdev) -+{ -+ struct npcm_peci *priv = dev_get_drvdata(&pdev->dev); -+ -+ clk_disable_unprepare(priv->clk); -+ peci_del_adapter(priv->adapter); -+ of_node_put(priv->adapter->dev.of_node); -+ -+ return 0; -+} -+ -+static const struct of_device_id npcm_peci_of_table[] = { -+ { .compatible = "nuvoton,npcm750-peci", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, npcm_peci_of_table); -+ -+static struct platform_driver npcm_peci_driver = { -+ .probe = npcm_peci_probe, -+ .remove = npcm_peci_remove, -+ .driver = { -+ .name = "peci-npcm", -+ .of_match_table = of_match_ptr(npcm_peci_of_table), -+ }, -+}; -+module_platform_driver(npcm_peci_driver); -+ -+MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>"); -+MODULE_DESCRIPTION("NPCM Platform Environment Control Interface (PECI) driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/peci/peci-aspeed.c b/drivers/peci/peci-aspeed.c -deleted file mode 100644 -index 51cb256..0000000 ---- a/drivers/peci/peci-aspeed.c -+++ /dev/null -@@ -1,505 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0 --// Copyright (C) 2012-2017 ASPEED Technology Inc. --// Copyright (c) 2018 Intel Corporation -- --#include <linux/bitfield.h> --#include <linux/clk.h> --#include <linux/interrupt.h> --#include <linux/jiffies.h> --#include <linux/module.h> --#include <linux/of.h> --#include <linux/peci.h> --#include <linux/platform_device.h> --#include <linux/regmap.h> --#include <linux/reset.h> -- --/* ASPEED PECI Registers */ --#define ASPEED_PECI_CTRL 0x00 --#define ASPEED_PECI_TIMING 0x04 --#define ASPEED_PECI_CMD 0x08 --#define ASPEED_PECI_CMD_CTRL 0x0c --#define ASPEED_PECI_EXP_FCS 0x10 --#define ASPEED_PECI_CAP_FCS 0x14 --#define ASPEED_PECI_INT_CTRL 0x18 --#define ASPEED_PECI_INT_STS 0x1c --#define ASPEED_PECI_W_DATA0 0x20 --#define ASPEED_PECI_W_DATA1 0x24 --#define ASPEED_PECI_W_DATA2 0x28 --#define ASPEED_PECI_W_DATA3 0x2c --#define ASPEED_PECI_R_DATA0 0x30 --#define ASPEED_PECI_R_DATA1 0x34 --#define ASPEED_PECI_R_DATA2 0x38 --#define ASPEED_PECI_R_DATA3 0x3c --#define ASPEED_PECI_W_DATA4 0x40 --#define ASPEED_PECI_W_DATA5 0x44 --#define ASPEED_PECI_W_DATA6 0x48 --#define ASPEED_PECI_W_DATA7 0x4c --#define ASPEED_PECI_R_DATA4 0x50 --#define ASPEED_PECI_R_DATA5 0x54 --#define ASPEED_PECI_R_DATA6 0x58 --#define ASPEED_PECI_R_DATA7 0x5c -- --/* ASPEED_PECI_CTRL - 0x00 : Control Register */ --#define PECI_CTRL_SAMPLING_MASK GENMASK(19, 16) --#define PECI_CTRL_READ_MODE_MASK GENMASK(13, 12) --#define PECI_CTRL_READ_MODE_COUNT BIT(12) --#define PECI_CTRL_READ_MODE_DBG BIT(13) --#define PECI_CTRL_CLK_SOURCE_MASK BIT(11) --#define PECI_CTRL_CLK_DIV_MASK GENMASK(10, 8) --#define PECI_CTRL_INVERT_OUT BIT(7) --#define PECI_CTRL_INVERT_IN BIT(6) --#define PECI_CTRL_BUS_CONTENT_EN BIT(5) --#define PECI_CTRL_PECI_EN BIT(4) --#define PECI_CTRL_PECI_CLK_EN BIT(0) -- --/* ASPEED_PECI_TIMING - 0x04 : Timing Negotiation Register */ --#define PECI_TIMING_MESSAGE_MASK GENMASK(15, 8) --#define PECI_TIMING_ADDRESS_MASK GENMASK(7, 0) -- --/* ASPEED_PECI_CMD - 0x08 : Command Register */ --#define PECI_CMD_PIN_MON BIT(31) --#define PECI_CMD_STS_MASK GENMASK(27, 24) --#define PECI_CMD_IDLE_MASK (PECI_CMD_STS_MASK | PECI_CMD_PIN_MON) --#define PECI_CMD_FIRE BIT(0) -- --/* ASPEED_PECI_LEN - 0x0C : Read/Write Length Register */ --#define PECI_AW_FCS_EN BIT(31) --#define PECI_READ_LEN_MASK GENMASK(23, 16) --#define PECI_WRITE_LEN_MASK GENMASK(15, 8) --#define PECI_TAGET_ADDR_MASK GENMASK(7, 0) -- --/* ASPEED_PECI_EXP_FCS - 0x10 : Expected FCS Data Register */ --#define PECI_EXPECT_READ_FCS_MASK GENMASK(23, 16) --#define PECI_EXPECT_AW_FCS_AUTO_MASK GENMASK(15, 8) --#define PECI_EXPECT_WRITE_FCS_MASK GENMASK(7, 0) -- --/* ASPEED_PECI_CAP_FCS - 0x14 : Captured FCS Data Register */ --#define PECI_CAPTURE_READ_FCS_MASK GENMASK(23, 16) --#define PECI_CAPTURE_WRITE_FCS_MASK GENMASK(7, 0) -- --/* ASPEED_PECI_INT_CTRL/STS - 0x18/0x1c : Interrupt Register */ --#define PECI_INT_TIMING_RESULT_MASK GENMASK(31, 30) --#define PECI_INT_TIMEOUT BIT(4) --#define PECI_INT_CONNECT BIT(3) --#define PECI_INT_W_FCS_BAD BIT(2) --#define PECI_INT_W_FCS_ABORT BIT(1) --#define PECI_INT_CMD_DONE BIT(0) -- --#define PECI_INT_MASK (PECI_INT_TIMEOUT | PECI_INT_CONNECT | \ -- PECI_INT_W_FCS_BAD | PECI_INT_W_FCS_ABORT | \ -- PECI_INT_CMD_DONE) -- --#define PECI_IDLE_CHECK_TIMEOUT_USEC 50000 --#define PECI_IDLE_CHECK_INTERVAL_USEC 10000 -- --#define PECI_RD_SAMPLING_POINT_DEFAULT 8 --#define PECI_RD_SAMPLING_POINT_MAX 15 --#define PECI_CLK_DIV_DEFAULT 0 --#define PECI_CLK_DIV_MAX 7 --#define PECI_MSG_TIMING_DEFAULT 1 --#define PECI_MSG_TIMING_MAX 255 --#define PECI_ADDR_TIMING_DEFAULT 1 --#define PECI_ADDR_TIMING_MAX 255 --#define PECI_CMD_TIMEOUT_MS_DEFAULT 1000 --#define PECI_CMD_TIMEOUT_MS_MAX 60000 -- --struct aspeed_peci { -- struct peci_adapter *adapter; -- struct device *dev; -- struct regmap *regmap; -- struct clk *clk; -- struct reset_control *rst; -- int irq; -- spinlock_t lock; /* to sync completion status handling */ -- struct completion xfer_complete; -- u32 status; -- u32 cmd_timeout_ms; --}; -- --static int aspeed_peci_xfer_native(struct aspeed_peci *priv, -- struct peci_xfer_msg *msg) --{ -- long err, timeout = msecs_to_jiffies(priv->cmd_timeout_ms); -- u32 peci_head, peci_state, rx_data, cmd_sts; -- unsigned long flags; -- int i, rc; -- uint reg; -- -- /* Check command sts and bus idle state */ -- rc = regmap_read_poll_timeout(priv->regmap, ASPEED_PECI_CMD, cmd_sts, -- !(cmd_sts & PECI_CMD_IDLE_MASK), -- PECI_IDLE_CHECK_INTERVAL_USEC, -- PECI_IDLE_CHECK_TIMEOUT_USEC); -- if (rc) -- return rc; /* -ETIMEDOUT */ -- -- spin_lock_irqsave(&priv->lock, flags); -- reinit_completion(&priv->xfer_complete); -- -- peci_head = FIELD_PREP(PECI_TAGET_ADDR_MASK, msg->addr) | -- FIELD_PREP(PECI_WRITE_LEN_MASK, msg->tx_len) | -- FIELD_PREP(PECI_READ_LEN_MASK, msg->rx_len); -- -- regmap_write(priv->regmap, ASPEED_PECI_CMD_CTRL, peci_head); -- -- for (i = 0; i < msg->tx_len; i += 4) { -- reg = i < 16 ? ASPEED_PECI_W_DATA0 + i % 16 : -- ASPEED_PECI_W_DATA4 + i % 16; -- regmap_write(priv->regmap, reg, -- le32_to_cpup((__le32 *)&msg->tx_buf[i])); -- } -- -- dev_dbg(priv->dev, "HEAD : 0x%08x\n", peci_head); -- print_hex_dump_debug("TX : ", DUMP_PREFIX_NONE, 16, 1, -- msg->tx_buf, msg->tx_len, true); -- -- priv->status = 0; -- regmap_write(priv->regmap, ASPEED_PECI_CMD, PECI_CMD_FIRE); -- spin_unlock_irqrestore(&priv->lock, flags); -- -- err = wait_for_completion_interruptible_timeout(&priv->xfer_complete, -- timeout); -- -- spin_lock_irqsave(&priv->lock, flags); -- dev_dbg(priv->dev, "INT_STS : 0x%08x\n", priv->status); -- regmap_read(priv->regmap, ASPEED_PECI_CMD, &peci_state); -- dev_dbg(priv->dev, "PECI_STATE : 0x%lx\n", -- FIELD_GET(PECI_CMD_STS_MASK, peci_state)); -- -- regmap_write(priv->regmap, ASPEED_PECI_CMD, 0); -- -- if (err <= 0 || priv->status != PECI_INT_CMD_DONE) { -- if (err < 0) { /* -ERESTARTSYS */ -- rc = (int)err; -- goto err_irqrestore; -- } else if (err == 0) { -- dev_dbg(priv->dev, "Timeout waiting for a response!\n"); -- rc = -ETIMEDOUT; -- goto err_irqrestore; -- } -- -- dev_dbg(priv->dev, "No valid response!\n"); -- rc = -EIO; -- goto err_irqrestore; -- } -- -- /** -- * Note that rx_len and rx_buf size can be an odd number. -- * Byte handling is more efficient. -- */ -- for (i = 0; i < msg->rx_len; i++) { -- u8 byte_offset = i % 4; -- -- if (byte_offset == 0) { -- reg = i < 16 ? ASPEED_PECI_R_DATA0 + i % 16 : -- ASPEED_PECI_R_DATA4 + i % 16; -- regmap_read(priv->regmap, reg, &rx_data); -- } -- -- msg->rx_buf[i] = (u8)(rx_data >> (byte_offset << 3)); -- } -- -- print_hex_dump_debug("RX : ", DUMP_PREFIX_NONE, 16, 1, -- msg->rx_buf, msg->rx_len, true); -- -- regmap_read(priv->regmap, ASPEED_PECI_CMD, &peci_state); -- dev_dbg(priv->dev, "PECI_STATE : 0x%lx\n", -- FIELD_GET(PECI_CMD_STS_MASK, peci_state)); -- dev_dbg(priv->dev, "------------------------\n"); -- --err_irqrestore: -- spin_unlock_irqrestore(&priv->lock, flags); -- return rc; --} -- --static irqreturn_t aspeed_peci_irq_handler(int irq, void *arg) --{ -- struct aspeed_peci *priv = arg; -- u32 status_ack = 0; -- u32 status; -- -- spin_lock(&priv->lock); -- regmap_read(priv->regmap, ASPEED_PECI_INT_STS, &status); -- priv->status |= (status & PECI_INT_MASK); -- -- /** -- * In most cases, interrupt bits will be set one by one but also note -- * that multiple interrupt bits could be set at the same time. -- */ -- if (status & PECI_INT_TIMEOUT) { -- dev_dbg(priv->dev, "PECI_INT_TIMEOUT\n"); -- status_ack |= PECI_INT_TIMEOUT; -- } -- -- if (status & PECI_INT_CONNECT) { -- dev_dbg(priv->dev, "PECI_INT_CONNECT\n"); -- status_ack |= PECI_INT_CONNECT; -- } -- -- if (status & PECI_INT_W_FCS_BAD) { -- dev_dbg(priv->dev, "PECI_INT_W_FCS_BAD\n"); -- status_ack |= PECI_INT_W_FCS_BAD; -- } -- -- if (status & PECI_INT_W_FCS_ABORT) { -- dev_dbg(priv->dev, "PECI_INT_W_FCS_ABORT\n"); -- status_ack |= PECI_INT_W_FCS_ABORT; -- } -- -- /** -- * All commands should be ended up with a PECI_INT_CMD_DONE bit set -- * even in an error case. -- */ -- if (status & PECI_INT_CMD_DONE) { -- dev_dbg(priv->dev, "PECI_INT_CMD_DONE\n"); -- status_ack |= PECI_INT_CMD_DONE; -- complete(&priv->xfer_complete); -- } -- -- regmap_write(priv->regmap, ASPEED_PECI_INT_STS, status_ack); -- spin_unlock(&priv->lock); -- return IRQ_HANDLED; --} -- --static int aspeed_peci_init_ctrl(struct aspeed_peci *priv) --{ -- u32 msg_timing, addr_timing, rd_sampling_point; -- u32 clk_freq, clk_divisor, clk_div_val = 0; -- int ret; -- -- priv->clk = devm_clk_get(priv->dev, NULL); -- if (IS_ERR(priv->clk)) { -- dev_err(priv->dev, "Failed to get clk source.\n"); -- return PTR_ERR(priv->clk); -- } -- -- ret = clk_prepare_enable(priv->clk); -- if (ret) { -- dev_err(priv->dev, "Failed to enable clock.\n"); -- return ret; -- } -- -- ret = of_property_read_u32(priv->dev->of_node, "clock-frequency", -- &clk_freq); -- if (ret) { -- dev_err(priv->dev, -- "Could not read clock-frequency property.\n"); -- clk_disable_unprepare(priv->clk); -- return ret; -- } -- -- clk_divisor = clk_get_rate(priv->clk) / clk_freq; -- -- while ((clk_divisor >> 1) && (clk_div_val < PECI_CLK_DIV_MAX)) -- clk_div_val++; -- -- ret = of_property_read_u32(priv->dev->of_node, "msg-timing", -- &msg_timing); -- if (ret || msg_timing > PECI_MSG_TIMING_MAX) { -- if (!ret) -- dev_warn(priv->dev, -- "Invalid msg-timing : %u, Use default : %u\n", -- msg_timing, PECI_MSG_TIMING_DEFAULT); -- msg_timing = PECI_MSG_TIMING_DEFAULT; -- } -- -- ret = of_property_read_u32(priv->dev->of_node, "addr-timing", -- &addr_timing); -- if (ret || addr_timing > PECI_ADDR_TIMING_MAX) { -- if (!ret) -- dev_warn(priv->dev, -- "Invalid addr-timing : %u, Use default : %u\n", -- addr_timing, PECI_ADDR_TIMING_DEFAULT); -- addr_timing = PECI_ADDR_TIMING_DEFAULT; -- } -- -- ret = of_property_read_u32(priv->dev->of_node, "rd-sampling-point", -- &rd_sampling_point); -- if (ret || rd_sampling_point > PECI_RD_SAMPLING_POINT_MAX) { -- if (!ret) -- dev_warn(priv->dev, -- "Invalid rd-sampling-point : %u. Use default : %u\n", -- rd_sampling_point, -- PECI_RD_SAMPLING_POINT_DEFAULT); -- rd_sampling_point = PECI_RD_SAMPLING_POINT_DEFAULT; -- } -- -- ret = of_property_read_u32(priv->dev->of_node, "cmd-timeout-ms", -- &priv->cmd_timeout_ms); -- if (ret || priv->cmd_timeout_ms > PECI_CMD_TIMEOUT_MS_MAX || -- priv->cmd_timeout_ms == 0) { -- if (!ret) -- dev_warn(priv->dev, -- "Invalid cmd-timeout-ms : %u. Use default : %u\n", -- priv->cmd_timeout_ms, -- PECI_CMD_TIMEOUT_MS_DEFAULT); -- priv->cmd_timeout_ms = PECI_CMD_TIMEOUT_MS_DEFAULT; -- } -- -- regmap_write(priv->regmap, ASPEED_PECI_CTRL, -- FIELD_PREP(PECI_CTRL_CLK_DIV_MASK, PECI_CLK_DIV_DEFAULT) | -- PECI_CTRL_PECI_CLK_EN); -- -- /** -- * Timing negotiation period setting. -- * The unit of the programmed value is 4 times of PECI clock period. -- */ -- regmap_write(priv->regmap, ASPEED_PECI_TIMING, -- FIELD_PREP(PECI_TIMING_MESSAGE_MASK, msg_timing) | -- FIELD_PREP(PECI_TIMING_ADDRESS_MASK, addr_timing)); -- -- /* Clear interrupts */ -- regmap_write(priv->regmap, ASPEED_PECI_INT_STS, PECI_INT_MASK); -- -- /* Enable interrupts */ -- regmap_write(priv->regmap, ASPEED_PECI_INT_CTRL, PECI_INT_MASK); -- -- /* Read sampling point and clock speed setting */ -- regmap_write(priv->regmap, ASPEED_PECI_CTRL, -- FIELD_PREP(PECI_CTRL_SAMPLING_MASK, rd_sampling_point) | -- FIELD_PREP(PECI_CTRL_CLK_DIV_MASK, clk_div_val) | -- PECI_CTRL_PECI_EN | PECI_CTRL_PECI_CLK_EN); -- -- return 0; --} -- --static const struct regmap_config aspeed_peci_regmap_config = { -- .reg_bits = 32, -- .val_bits = 32, -- .reg_stride = 4, -- .max_register = ASPEED_PECI_R_DATA7, -- .val_format_endian = REGMAP_ENDIAN_LITTLE, -- .fast_io = true, --}; -- --static int aspeed_peci_xfer(struct peci_adapter *adapter, -- struct peci_xfer_msg *msg) --{ -- struct aspeed_peci *priv = peci_get_adapdata(adapter); -- -- return aspeed_peci_xfer_native(priv, msg); --} -- --static int aspeed_peci_probe(struct platform_device *pdev) --{ -- struct peci_adapter *adapter; -- struct aspeed_peci *priv; -- struct resource *res; -- void __iomem *base; -- u32 cmd_sts; -- int ret; -- -- adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv)); -- if (!adapter) -- return -ENOMEM; -- -- priv = peci_get_adapdata(adapter); -- priv->adapter = adapter; -- priv->dev = &pdev->dev; -- dev_set_drvdata(&pdev->dev, priv); -- -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- base = devm_ioremap_resource(&pdev->dev, res); -- if (IS_ERR(base)) { -- ret = PTR_ERR(base); -- goto err_put_adapter_dev; -- } -- -- priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, -- &aspeed_peci_regmap_config); -- if (IS_ERR(priv->regmap)) { -- ret = PTR_ERR(priv->regmap); -- goto err_put_adapter_dev; -- } -- -- /** -- * We check that the regmap works on this very first access, -- * but as this is an MMIO-backed regmap, subsequent regmap -- * access is not going to fail and we skip error checks from -- * this point. -- */ -- ret = regmap_read(priv->regmap, ASPEED_PECI_CMD, &cmd_sts); -- if (ret) { -- ret = -EIO; -- goto err_put_adapter_dev; -- } -- -- priv->irq = platform_get_irq(pdev, 0); -- if (!priv->irq) { -- ret = -ENODEV; -- goto err_put_adapter_dev; -- } -- -- ret = devm_request_irq(&pdev->dev, priv->irq, aspeed_peci_irq_handler, -- 0, "peci-aspeed-irq", priv); -- if (ret) -- goto err_put_adapter_dev; -- -- init_completion(&priv->xfer_complete); -- spin_lock_init(&priv->lock); -- -- priv->adapter->owner = THIS_MODULE; -- priv->adapter->dev.of_node = of_node_get(dev_of_node(priv->dev)); -- strlcpy(priv->adapter->name, pdev->name, sizeof(priv->adapter->name)); -- priv->adapter->xfer = aspeed_peci_xfer; -- -- priv->rst = devm_reset_control_get(&pdev->dev, NULL); -- if (IS_ERR(priv->rst)) { -- dev_err(&pdev->dev, -- "missing or invalid reset controller entry"); -- ret = PTR_ERR(priv->rst); -- goto err_put_adapter_dev; -- } -- reset_control_deassert(priv->rst); -- -- ret = aspeed_peci_init_ctrl(priv); -- if (ret) -- goto err_put_adapter_dev; -- -- ret = peci_add_adapter(priv->adapter); -- if (ret) -- goto err_put_adapter_dev; -- -- dev_info(&pdev->dev, "peci bus %d registered, irq %d\n", -- priv->adapter->nr, priv->irq); -- -- return 0; -- --err_put_adapter_dev: -- put_device(&adapter->dev); -- return ret; --} -- --static int aspeed_peci_remove(struct platform_device *pdev) --{ -- struct aspeed_peci *priv = dev_get_drvdata(&pdev->dev); -- -- clk_disable_unprepare(priv->clk); -- reset_control_assert(priv->rst); -- peci_del_adapter(priv->adapter); -- of_node_put(priv->adapter->dev.of_node); -- -- return 0; --} -- --static const struct of_device_id aspeed_peci_of_table[] = { -- { .compatible = "aspeed,ast2400-peci", }, -- { .compatible = "aspeed,ast2500-peci", }, -- { } --}; --MODULE_DEVICE_TABLE(of, aspeed_peci_of_table); -- --static struct platform_driver aspeed_peci_driver = { -- .probe = aspeed_peci_probe, -- .remove = aspeed_peci_remove, -- .driver = { -- .name = "peci-aspeed", -- .of_match_table = of_match_ptr(aspeed_peci_of_table), -- }, --}; --module_platform_driver(aspeed_peci_driver); -- --MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>"); --MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>"); --MODULE_DESCRIPTION("ASPEED PECI driver"); --MODULE_LICENSE("GPL v2"); -diff --git a/drivers/peci/peci-core.c b/drivers/peci/peci-core.c -index 6f24146..2a6be04 100644 ---- a/drivers/peci/peci-core.c -+++ b/drivers/peci/peci-core.c -@@ -1,38 +1,31 @@ - // SPDX-License-Identifier: GPL-2.0 --// Copyright (c) 2018 Intel Corporation -+// Copyright (c) 2018-2019 Intel Corporation - - #include <linux/bitfield.h> - #include <linux/crc8.h> - #include <linux/delay.h> --#include <linux/fs.h> -+#include <linux/mm.h> - #include <linux/module.h> - #include <linux/of_device.h> - #include <linux/peci.h> - #include <linux/pm_domain.h> - #include <linux/pm_runtime.h> -+#include <linux/sched/task_stack.h> - #include <linux/slab.h> --#include <linux/uaccess.h> - - /* Mask for getting minor revision number from DIB */ - #define REVISION_NUM_MASK GENMASK(15, 8) - --/* CRC8 table for Assure Write Frame Check */ -+/* CRC8 table for Assured Write Frame Check */ - #define PECI_CRC8_POLYNOMIAL 0x07 - DECLARE_CRC8_TABLE(peci_crc8_table); - --static struct device_type peci_adapter_type; --static struct device_type peci_client_type; -- --/* Max number of peci cdev */ --#define PECI_CDEV_MAX 16 -- --static dev_t peci_devt; - static bool is_registered; - - static DEFINE_MUTEX(core_lock); - static DEFINE_IDR(peci_adapter_idr); - --static struct peci_adapter *peci_get_adapter(int nr) -+struct peci_adapter *peci_get_adapter(int nr) - { - struct peci_adapter *adapter; - -@@ -48,10 +41,12 @@ static struct peci_adapter *peci_get_adapter(int nr) - - out_unlock: - mutex_unlock(&core_lock); -+ - return adapter; - } -+EXPORT_SYMBOL_GPL(peci_get_adapter); - --static void peci_put_adapter(struct peci_adapter *adapter) -+void peci_put_adapter(struct peci_adapter *adapter) - { - if (!adapter) - return; -@@ -59,6 +54,7 @@ static void peci_put_adapter(struct peci_adapter *adapter) - put_device(&adapter->dev); - module_put(adapter->owner); - } -+EXPORT_SYMBOL_GPL(peci_put_adapter); - - static ssize_t name_show(struct device *dev, - struct device_attribute *attr, -@@ -84,10 +80,11 @@ static struct attribute *peci_device_attrs[] = { - }; - ATTRIBUTE_GROUPS(peci_device); - --static struct device_type peci_client_type = { -+struct device_type peci_client_type = { - .groups = peci_device_groups, - .release = peci_client_dev_release, - }; -+EXPORT_SYMBOL_GPL(peci_client_type); - - /** - * peci_verify_client - return parameter as peci_client, or NULL -@@ -103,19 +100,120 @@ struct peci_client *peci_verify_client(struct device *dev) - } - EXPORT_SYMBOL_GPL(peci_verify_client); - --static u8 peci_aw_fcs(u8 *data, int len) -+/** -+ * peci_get_xfer_msg() - get a DMA safe peci_xfer_msg for the given tx and rx -+ * length -+ * @tx_len: the length of tx_buf. May be 0 if tx_buf isn't needed. -+ * @rx_len: the length of rx_buf. May be 0 if rx_buf isn't needed. -+ * -+ * Return: NULL if a DMA safe buffer was not obtained. -+ * Or a valid pointer to be used with DMA. After use, release it by -+ * calling peci_put_xfer_msg(). -+ * -+ * This function must only be called from process context! -+ */ -+struct peci_xfer_msg *peci_get_xfer_msg(u8 tx_len, u8 rx_len) -+{ -+ struct peci_xfer_msg *msg; -+ u8 *tx_buf, *rx_buf; -+ -+ if (tx_len) { -+ tx_buf = kzalloc(tx_len, GFP_KERNEL); -+ if (!tx_buf) -+ return NULL; -+ } else { -+ tx_buf = NULL; -+ } -+ -+ if (rx_len) { -+ rx_buf = kzalloc(rx_len, GFP_KERNEL); -+ if (!rx_buf) -+ goto err_free_tx_buf; -+ } else { -+ rx_buf = NULL; -+ } -+ -+ msg = kzalloc(sizeof(struct peci_xfer_msg), GFP_KERNEL); -+ if (!msg) -+ goto err_free_tx_rx_buf; -+ -+ msg->tx_len = tx_len; -+ msg->tx_buf = tx_buf; -+ msg->rx_len = rx_len; -+ msg->rx_buf = rx_buf; -+ -+ return msg; -+ -+err_free_tx_rx_buf: -+ kfree(rx_buf); -+err_free_tx_buf: -+ kfree(tx_buf); -+ -+ return NULL; -+} -+EXPORT_SYMBOL_GPL(peci_get_xfer_msg); -+ -+/** -+ * peci_put_xfer_msg - release a DMA safe peci_xfer_msg -+ * @msg: the message obtained from peci_get_xfer_msg(). May be NULL. -+ */ -+void peci_put_xfer_msg(struct peci_xfer_msg *msg) -+{ -+ if (!msg) -+ return; -+ -+ kfree(msg->rx_buf); -+ kfree(msg->tx_buf); -+ kfree(msg); -+} -+EXPORT_SYMBOL_GPL(peci_put_xfer_msg); -+ -+/* Calculate an Assured Write Frame Check Sequence byte */ -+static int peci_aw_fcs(struct peci_xfer_msg *msg, int len, u8 *aw_fcs) - { -- return crc8(peci_crc8_table, data, (size_t)len, 0); -+ u8 *tmp_buf; -+ -+ /* Allocate a temporary buffer to use a contiguous byte array */ -+ tmp_buf = kmalloc(len, GFP_KERNEL); -+ if (!tmp_buf) -+ return -ENOMEM; -+ -+ tmp_buf[0] = msg->addr; -+ tmp_buf[1] = msg->tx_len; -+ tmp_buf[2] = msg->rx_len; -+ memcpy(&tmp_buf[3], msg->tx_buf, len - 3); -+ -+ *aw_fcs = crc8(peci_crc8_table, tmp_buf, (size_t)len, 0); -+ -+ kfree(tmp_buf); -+ -+ return 0; - } - - static int __peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg, - bool do_retry, bool has_aw_fcs) - { -- ktime_t start, end; -- s64 elapsed_ms; -- int rc = 0; -+ ulong timeout = jiffies; -+ u8 aw_fcs; -+ int ret; -+ -+ /* -+ * In case if adapter uses DMA, check at here whether tx and rx buffers -+ * are DMA capable or not. -+ */ -+ if (IS_ENABLED(CONFIG_HAS_DMA) && adapter->use_dma) { -+ if (is_vmalloc_addr(msg->tx_buf) || -+ is_vmalloc_addr(msg->rx_buf)) { -+ WARN_ONCE(1, "xfer msg is not dma capable\n"); -+ return -EAGAIN; -+ } else if (object_is_on_stack(msg->tx_buf) || -+ object_is_on_stack(msg->rx_buf)) { -+ WARN_ONCE(1, "xfer msg is on stack\n"); -+ return -EAGAIN; -+ } -+ } - -- /** -+ /* - * For some commands, the PECI originator may need to retry a command if - * the processor PECI client responds with a 0x8x completion code. In - * each instance, the processor PECI client may have started the -@@ -125,55 +223,51 @@ static int __peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg, - */ - - if (do_retry) -- start = ktime_get(); -+ timeout += msecs_to_jiffies(PECI_DEV_RETRY_TIME_MS); - -- do { -- rc = adapter->xfer(adapter, msg); -+ for (;;) { -+ ret = adapter->xfer(adapter, msg); - -- if (!do_retry || rc) -- break; -- -- if (msg->rx_buf[0] == DEV_PECI_CC_SUCCESS) -+ if (!do_retry || ret || !msg->rx_buf) - break; - - /* Retry is needed when completion code is 0x8x */ -- if ((msg->rx_buf[0] & DEV_PECI_CC_RETRY_CHECK_MASK) != -- DEV_PECI_CC_NEED_RETRY) { -- rc = -EIO; -+ if ((msg->rx_buf[0] & PECI_DEV_CC_RETRY_CHECK_MASK) != -+ PECI_DEV_CC_NEED_RETRY) - break; -- } - - /* Set the retry bit to indicate a retry attempt */ -- msg->tx_buf[1] |= DEV_PECI_RETRY_BIT; -+ msg->tx_buf[1] |= PECI_DEV_RETRY_BIT; - - /* Recalculate the AW FCS if it has one */ -- if (has_aw_fcs) -- msg->tx_buf[msg->tx_len - 1] = 0x80 ^ -- peci_aw_fcs((u8 *)msg, -- 2 + msg->tx_len); -+ if (has_aw_fcs) { -+ ret = peci_aw_fcs(msg, 2 + msg->tx_len, &aw_fcs); -+ if (ret) -+ break; - -- /** -+ msg->tx_buf[msg->tx_len - 1] = 0x80 ^ aw_fcs; -+ } -+ -+ /* - * Retry for at least 250ms before returning an error. - * Retry interval guideline: - * No minimum < Retry Interval < No maximum - * (recommend 10ms) - */ -- end = ktime_get(); -- elapsed_ms = ktime_to_ms(ktime_sub(end, start)); -- if (elapsed_ms >= DEV_PECI_RETRY_TIME_MS) { -+ if (time_after(jiffies, timeout)) { - dev_dbg(&adapter->dev, "Timeout retrying xfer!\n"); -- rc = -ETIMEDOUT; -+ ret = -ETIMEDOUT; - break; - } - -- usleep_range((DEV_PECI_RETRY_INTERVAL_USEC >> 2) + 1, -- DEV_PECI_RETRY_INTERVAL_USEC); -- } while (true); -+ usleep_range((PECI_DEV_RETRY_INTERVAL_USEC >> 2) + 1, -+ PECI_DEV_RETRY_INTERVAL_USEC); -+ } - -- if (rc) -- dev_dbg(&adapter->dev, "xfer error, rc: %d\n", rc); -+ if (ret) -+ dev_dbg(&adapter->dev, "xfer error: %d\n", ret); - -- return rc; -+ return ret; - } - - static int peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg) -@@ -190,34 +284,37 @@ static int peci_xfer_with_retries(struct peci_adapter *adapter, - - static int peci_scan_cmd_mask(struct peci_adapter *adapter) - { -- struct peci_xfer_msg msg; -+ struct peci_xfer_msg *msg; - u8 revision; -- int rc = 0; -+ int ret; - u64 dib; - - /* Update command mask just once */ - if (adapter->cmd_mask & BIT(PECI_CMD_XFER)) - return 0; - -- msg.addr = PECI_BASE_ADDR; -- msg.tx_len = GET_DIB_WR_LEN; -- msg.rx_len = GET_DIB_RD_LEN; -- msg.tx_buf[0] = GET_DIB_PECI_CMD; -+ msg = peci_get_xfer_msg(PECI_GET_DIB_WR_LEN, PECI_GET_DIB_RD_LEN); -+ if (!msg) -+ return -ENOMEM; -+ -+ msg->addr = PECI_BASE_ADDR; -+ msg->tx_buf[0] = PECI_GET_DIB_CMD; - -- rc = peci_xfer(adapter, &msg); -- if (rc) -- return rc; -+ ret = peci_xfer(adapter, msg); -+ if (ret) -+ return ret; - -- dib = le64_to_cpup((__le64 *)msg.rx_buf); -+ dib = le64_to_cpup((__le64 *)msg->rx_buf); - - /* Check special case for Get DIB command */ - if (dib == 0) { - dev_dbg(&adapter->dev, "DIB read as 0\n"); -- return -EIO; -+ ret = -EIO; -+ goto out; - } - -- /** -- * Setting up the supporting commands based on minor revision number. -+ /* -+ * Setting up the supporting commands based on revision number. - * See PECI Spec Table 3-1. - */ - revision = FIELD_GET(REVISION_NUM_MASK, dib); -@@ -243,10 +340,14 @@ static int peci_scan_cmd_mask(struct peci_adapter *adapter) - adapter->cmd_mask |= BIT(PECI_CMD_GET_DIB); - adapter->cmd_mask |= BIT(PECI_CMD_PING); - -- return rc; -+out: -+ peci_put_xfer_msg(msg); -+ -+ return ret; - } - --static int peci_cmd_support(struct peci_adapter *adapter, enum peci_cmd cmd) -+static int peci_check_cmd_support(struct peci_adapter *adapter, -+ enum peci_cmd cmd) - { - if (!(adapter->cmd_mask & BIT(PECI_CMD_PING)) && - peci_scan_cmd_mask(adapter) < 0) { -@@ -262,70 +363,130 @@ static int peci_cmd_support(struct peci_adapter *adapter, enum peci_cmd cmd) - return 0; - } - --static int peci_ioctl_xfer(struct peci_adapter *adapter, void *vmsg) -+static int peci_cmd_xfer(struct peci_adapter *adapter, void *vmsg) - { - struct peci_xfer_msg *msg = vmsg; -+ u8 aw_fcs; -+ int ret; -+ -+ if (!msg->tx_len) { -+ ret = peci_xfer(adapter, msg); -+ } else { -+ switch (msg->tx_buf[0]) { -+ case PECI_RDPKGCFG_CMD: -+ case PECI_RDIAMSR_CMD: -+ case PECI_RDPCICFG_CMD: -+ case PECI_RDPCICFGLOCAL_CMD: -+ ret = peci_xfer_with_retries(adapter, msg, false); -+ break; -+ case PECI_WRPKGCFG_CMD: -+ case PECI_WRIAMSR_CMD: -+ case PECI_WRPCICFG_CMD: -+ case PECI_WRPCICFGLOCAL_CMD: -+ /* Check if the AW FCS byte is already provided */ -+ ret = peci_aw_fcs(msg, 2 + msg->tx_len, &aw_fcs); -+ if (ret) -+ break; -+ -+ if (msg->tx_buf[msg->tx_len - 1] != (0x80 ^ aw_fcs)) { -+ /* Add an Assured Write Frame Check Sequence byte */ -+ /* Increment the tx_len to include the new byte */ -+ msg->tx_len++; -+ ret = peci_aw_fcs(msg, 2 + msg->tx_len, -+ &aw_fcs); -+ if (ret) -+ break; -+ -+ msg->tx_buf[msg->tx_len - 1] = 0x80 ^ aw_fcs; -+ } -+ -+ ret = peci_xfer_with_retries(adapter, msg, true); -+ break; -+ case PECI_GET_DIB_CMD: -+ case PECI_GET_TEMP_CMD: -+ default: -+ ret = peci_xfer(adapter, msg); -+ break; -+ } -+ } - -- return peci_xfer(adapter, msg); -+ return ret; - } - --static int peci_ioctl_ping(struct peci_adapter *adapter, void *vmsg) -+static int peci_cmd_ping(struct peci_adapter *adapter, void *vmsg) - { - struct peci_ping_msg *umsg = vmsg; -- struct peci_xfer_msg msg; -+ struct peci_xfer_msg *msg; -+ int ret; -+ -+ msg = peci_get_xfer_msg(0, 0); -+ if (!msg) -+ return -ENOMEM; - -- msg.addr = umsg->addr; -- msg.tx_len = 0; -- msg.rx_len = 0; -+ msg->addr = umsg->addr; - -- return peci_xfer(adapter, &msg); -+ ret = peci_xfer(adapter, msg); -+ -+ peci_put_xfer_msg(msg); -+ -+ return ret; - } - --static int peci_ioctl_get_dib(struct peci_adapter *adapter, void *vmsg) -+static int peci_cmd_get_dib(struct peci_adapter *adapter, void *vmsg) - { - struct peci_get_dib_msg *umsg = vmsg; -- struct peci_xfer_msg msg; -- int rc; -+ struct peci_xfer_msg *msg; -+ int ret; - -- msg.addr = umsg->addr; -- msg.tx_len = GET_DIB_WR_LEN; -- msg.rx_len = GET_DIB_RD_LEN; -- msg.tx_buf[0] = GET_DIB_PECI_CMD; -+ msg = peci_get_xfer_msg(PECI_GET_DIB_WR_LEN, PECI_GET_DIB_RD_LEN); -+ if (!msg) -+ return -ENOMEM; - -- rc = peci_xfer(adapter, &msg); -- if (rc) -- return rc; -+ msg->addr = umsg->addr; -+ msg->tx_buf[0] = PECI_GET_DIB_CMD; - -- umsg->dib = le64_to_cpup((__le64 *)msg.rx_buf); -+ ret = peci_xfer(adapter, msg); -+ if (ret) -+ goto out; - -- return 0; -+ umsg->dib = le64_to_cpup((__le64 *)msg->rx_buf); -+ -+out: -+ peci_put_xfer_msg(msg); -+ -+ return ret; - } - --static int peci_ioctl_get_temp(struct peci_adapter *adapter, void *vmsg) -+static int peci_cmd_get_temp(struct peci_adapter *adapter, void *vmsg) - { - struct peci_get_temp_msg *umsg = vmsg; -- struct peci_xfer_msg msg; -- int rc; -+ struct peci_xfer_msg *msg; -+ int ret; - -- msg.addr = umsg->addr; -- msg.tx_len = GET_TEMP_WR_LEN; -- msg.rx_len = GET_TEMP_RD_LEN; -- msg.tx_buf[0] = GET_TEMP_PECI_CMD; -+ msg = peci_get_xfer_msg(PECI_GET_TEMP_WR_LEN, PECI_GET_TEMP_RD_LEN); -+ if (!msg) -+ return -ENOMEM; - -- rc = peci_xfer(adapter, &msg); -- if (rc) -- return rc; -+ msg->addr = umsg->addr; -+ msg->tx_buf[0] = PECI_GET_TEMP_CMD; - -- umsg->temp_raw = le16_to_cpup((__le16 *)msg.rx_buf); -+ ret = peci_xfer(adapter, msg); -+ if (ret) -+ goto out; - -- return 0; -+ umsg->temp_raw = le16_to_cpup((__le16 *)msg->rx_buf); -+ -+out: -+ peci_put_xfer_msg(msg); -+ -+ return ret; - } - --static int peci_ioctl_rd_pkg_cfg(struct peci_adapter *adapter, void *vmsg) -+static int peci_cmd_rd_pkg_cfg(struct peci_adapter *adapter, void *vmsg) - { - struct peci_rd_pkg_cfg_msg *umsg = vmsg; -- struct peci_xfer_msg msg; -- int rc = 0; -+ struct peci_xfer_msg *msg; -+ int ret; - - /* Per the PECI spec, the read length must be a byte, word, or dword */ - if (umsg->rx_len != 1 && umsg->rx_len != 2 && umsg->rx_len != 4) { -@@ -334,29 +495,35 @@ static int peci_ioctl_rd_pkg_cfg(struct peci_adapter *adapter, void *vmsg) - return -EINVAL; - } - -- msg.addr = umsg->addr; -- msg.tx_len = RDPKGCFG_WRITE_LEN; -- /* read lengths of 1 and 2 result in an error, so only use 4 for now */ -- msg.rx_len = RDPKGCFG_READ_LEN_BASE + umsg->rx_len; -- msg.tx_buf[0] = RDPKGCFG_PECI_CMD; -- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ -- /* Host ID is 0 for PECI 3.0 */ -- msg.tx_buf[2] = umsg->index; /* RdPkgConfig index */ -- msg.tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */ -- msg.tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */ -+ msg = peci_get_xfer_msg(PECI_RDPKGCFG_WRITE_LEN, -+ PECI_RDPKGCFG_READ_LEN_BASE + umsg->rx_len); -+ if (!msg) -+ return -ENOMEM; -+ -+ msg->addr = umsg->addr; -+ msg->tx_buf[0] = PECI_RDPKGCFG_CMD; -+ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ -+ /* Host ID is 0 for PECI 3.0 */ -+ msg->tx_buf[2] = umsg->index; /* RdPkgConfig index */ -+ msg->tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */ -+ msg->tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */ -+ -+ ret = peci_xfer_with_retries(adapter, msg, false); -+ if (!ret) -+ memcpy(umsg->pkg_config, &msg->rx_buf[1], umsg->rx_len); - -- rc = peci_xfer_with_retries(adapter, &msg, false); -- if (!rc) -- memcpy(umsg->pkg_config, &msg.rx_buf[1], umsg->rx_len); -+ umsg->cc = msg->rx_buf[0]; -+ peci_put_xfer_msg(msg); - -- return rc; -+ return ret; - } - --static int peci_ioctl_wr_pkg_cfg(struct peci_adapter *adapter, void *vmsg) -+static int peci_cmd_wr_pkg_cfg(struct peci_adapter *adapter, void *vmsg) - { - struct peci_wr_pkg_cfg_msg *umsg = vmsg; -- struct peci_xfer_msg msg; -- int rc = 0, i; -+ struct peci_xfer_msg *msg; -+ int ret, i; -+ u8 aw_fcs; - - /* Per the PECI spec, the write length must be a dword */ - if (umsg->tx_len != 4) { -@@ -365,86 +532,116 @@ static int peci_ioctl_wr_pkg_cfg(struct peci_adapter *adapter, void *vmsg) - return -EINVAL; - } - -- msg.addr = umsg->addr; -- msg.tx_len = WRPKGCFG_WRITE_LEN_BASE + umsg->tx_len; -- /* read lengths of 1 and 2 result in an error, so only use 4 for now */ -- msg.rx_len = WRPKGCFG_READ_LEN; -- msg.tx_buf[0] = WRPKGCFG_PECI_CMD; -- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ -+ msg = peci_get_xfer_msg(PECI_WRPKGCFG_WRITE_LEN_BASE + umsg->tx_len, -+ PECI_WRPKGCFG_READ_LEN); -+ if (!msg) -+ return -ENOMEM; -+ -+ msg->addr = umsg->addr; -+ msg->tx_buf[0] = PECI_WRPKGCFG_CMD; -+ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ - /* Host ID is 0 for PECI 3.0 */ -- msg.tx_buf[2] = umsg->index; /* RdPkgConfig index */ -- msg.tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */ -- msg.tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */ -+ msg->tx_buf[2] = umsg->index; /* RdPkgConfig index */ -+ msg->tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */ -+ msg->tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */ - for (i = 0; i < umsg->tx_len; i++) -- msg.tx_buf[5 + i] = (u8)(umsg->value >> (i << 3)); -+ msg->tx_buf[5 + i] = (u8)(umsg->value >> (i << 3)); -+ -+ /* Add an Assured Write Frame Check Sequence byte */ -+ ret = peci_aw_fcs(msg, 8 + umsg->tx_len, &aw_fcs); -+ if (ret) -+ goto out; -+ -+ msg->tx_buf[5 + i] = 0x80 ^ aw_fcs; - -- /* Add an Assure Write Frame Check Sequence byte */ -- msg.tx_buf[5 + i] = 0x80 ^ -- peci_aw_fcs((u8 *)&msg, 8 + umsg->tx_len); -+ ret = peci_xfer_with_retries(adapter, msg, true); - -- rc = peci_xfer_with_retries(adapter, &msg, true); -+out: -+ umsg->cc = msg->rx_buf[0]; -+ peci_put_xfer_msg(msg); - -- return rc; -+ return ret; - } - --static int peci_ioctl_rd_ia_msr(struct peci_adapter *adapter, void *vmsg) -+static int peci_cmd_rd_ia_msr(struct peci_adapter *adapter, void *vmsg) - { - struct peci_rd_ia_msr_msg *umsg = vmsg; -- struct peci_xfer_msg msg; -- int rc = 0; -- -- msg.addr = umsg->addr; -- msg.tx_len = RDIAMSR_WRITE_LEN; -- msg.rx_len = RDIAMSR_READ_LEN; -- msg.tx_buf[0] = RDIAMSR_PECI_CMD; -- msg.tx_buf[1] = 0; -- msg.tx_buf[2] = umsg->thread_id; -- msg.tx_buf[3] = (u8)umsg->address; -- msg.tx_buf[4] = (u8)(umsg->address >> 8); -- -- rc = peci_xfer_with_retries(adapter, &msg, false); -- if (!rc) -- memcpy(&umsg->value, &msg.rx_buf[1], sizeof(uint64_t)); -- -- return rc; -+ struct peci_xfer_msg *msg; -+ int ret; -+ -+ msg = peci_get_xfer_msg(PECI_RDIAMSR_WRITE_LEN, PECI_RDIAMSR_READ_LEN); -+ if (!msg) -+ return -ENOMEM; -+ -+ msg->addr = umsg->addr; -+ msg->tx_buf[0] = PECI_RDIAMSR_CMD; -+ msg->tx_buf[1] = 0; -+ msg->tx_buf[2] = umsg->thread_id; -+ msg->tx_buf[3] = (u8)umsg->address; -+ msg->tx_buf[4] = (u8)(umsg->address >> 8); -+ -+ ret = peci_xfer_with_retries(adapter, msg, false); -+ if (!ret) -+ memcpy(&umsg->value, &msg->rx_buf[1], sizeof(uint64_t)); -+ -+ umsg->cc = msg->rx_buf[0]; -+ peci_put_xfer_msg(msg); -+ -+ return ret; - } - --static int peci_ioctl_rd_pci_cfg(struct peci_adapter *adapter, void *vmsg) -+static int peci_cmd_wr_ia_msr(struct peci_adapter *adapter, void *vmsg) -+{ -+ return -ENOSYS; /* Not implemented yet */ -+} -+ -+static int peci_cmd_rd_pci_cfg(struct peci_adapter *adapter, void *vmsg) - { - struct peci_rd_pci_cfg_msg *umsg = vmsg; -- struct peci_xfer_msg msg; -+ struct peci_xfer_msg *msg; - u32 address; -- int rc = 0; -+ int ret; -+ -+ msg = peci_get_xfer_msg(PECI_RDPCICFG_WRITE_LEN, -+ PECI_RDPCICFG_READ_LEN); -+ if (!msg) -+ return -ENOMEM; - - address = umsg->reg; /* [11:0] - Register */ - address |= (u32)umsg->function << 12; /* [14:12] - Function */ - address |= (u32)umsg->device << 15; /* [19:15] - Device */ - address |= (u32)umsg->bus << 20; /* [27:20] - Bus */ - /* [31:28] - Reserved */ -- msg.addr = umsg->addr; -- msg.tx_len = RDPCICFG_WRITE_LEN; -- msg.rx_len = RDPCICFG_READ_LEN; -- msg.tx_buf[0] = RDPCICFG_PECI_CMD; -- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ -+ msg->addr = umsg->addr; -+ msg->tx_buf[0] = PECI_RDPCICFG_CMD; -+ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ - /* Host ID is 0 for PECI 3.0 */ -- msg.tx_buf[2] = (u8)address; /* LSB - PCI Config Address */ -- msg.tx_buf[3] = (u8)(address >> 8); /* PCI Config Address */ -- msg.tx_buf[4] = (u8)(address >> 16); /* PCI Config Address */ -- msg.tx_buf[5] = (u8)(address >> 24); /* MSB - PCI Config Address */ -+ msg->tx_buf[2] = (u8)address; /* LSB - PCI Config Address */ -+ msg->tx_buf[3] = (u8)(address >> 8); /* PCI Config Address */ -+ msg->tx_buf[4] = (u8)(address >> 16); /* PCI Config Address */ -+ msg->tx_buf[5] = (u8)(address >> 24); /* MSB - PCI Config Address */ -+ -+ ret = peci_xfer_with_retries(adapter, msg, false); -+ if (!ret) -+ memcpy(umsg->pci_config, &msg->rx_buf[1], 4); -+ -+ umsg->cc = msg->rx_buf[0]; -+ peci_put_xfer_msg(msg); - -- rc = peci_xfer_with_retries(adapter, &msg, false); -- if (!rc) -- memcpy(umsg->pci_config, &msg.rx_buf[1], 4); -+ return ret; -+} - -- return rc; -+static int peci_cmd_wr_pci_cfg(struct peci_adapter *adapter, void *vmsg) -+{ -+ return -ENOSYS; /* Not implemented yet */ - } - --static int peci_ioctl_rd_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) -+static int peci_cmd_rd_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) - { - struct peci_rd_pci_cfg_local_msg *umsg = vmsg; -- struct peci_xfer_msg msg; -+ struct peci_xfer_msg *msg; - u32 address; -- int rc = 0; -+ int ret; - - /* Per the PECI spec, the read length must be a byte, word, or dword */ - if (umsg->rx_len != 1 && umsg->rx_len != 2 && umsg->rx_len != 4) { -@@ -453,34 +650,42 @@ static int peci_ioctl_rd_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) - return -EINVAL; - } - -+ msg = peci_get_xfer_msg(PECI_RDPCICFGLOCAL_WRITE_LEN, -+ PECI_RDPCICFGLOCAL_READ_LEN_BASE + -+ umsg->rx_len); -+ if (!msg) -+ return -ENOMEM; -+ - address = umsg->reg; /* [11:0] - Register */ - address |= (u32)umsg->function << 12; /* [14:12] - Function */ - address |= (u32)umsg->device << 15; /* [19:15] - Device */ - address |= (u32)umsg->bus << 20; /* [23:20] - Bus */ - -- msg.addr = umsg->addr; -- msg.tx_len = RDPCICFGLOCAL_WRITE_LEN; -- msg.rx_len = RDPCICFGLOCAL_READ_LEN_BASE + umsg->rx_len; -- msg.tx_buf[0] = RDPCICFGLOCAL_PECI_CMD; -- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ -- /* Host ID is 0 for PECI 3.0 */ -- msg.tx_buf[2] = (u8)address; /* LSB - PCI Configuration Address */ -- msg.tx_buf[3] = (u8)(address >> 8); /* PCI Configuration Address */ -- msg.tx_buf[4] = (u8)(address >> 16); /* PCI Configuration Address */ -+ msg->addr = umsg->addr; -+ msg->tx_buf[0] = PECI_RDPCICFGLOCAL_CMD; -+ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ -+ /* Host ID is 0 for PECI 3.0 */ -+ msg->tx_buf[2] = (u8)address; /* LSB - PCI Configuration Address */ -+ msg->tx_buf[3] = (u8)(address >> 8); /* PCI Configuration Address */ -+ msg->tx_buf[4] = (u8)(address >> 16); /* PCI Configuration Address */ -+ -+ ret = peci_xfer_with_retries(adapter, msg, false); -+ if (!ret) -+ memcpy(umsg->pci_config, &msg->rx_buf[1], umsg->rx_len); - -- rc = peci_xfer_with_retries(adapter, &msg, false); -- if (!rc) -- memcpy(umsg->pci_config, &msg.rx_buf[1], umsg->rx_len); -+ umsg->cc = msg->rx_buf[0]; -+ peci_put_xfer_msg(msg); - -- return rc; -+ return ret; - } - --static int peci_ioctl_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) -+static int peci_cmd_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) - { - struct peci_wr_pci_cfg_local_msg *umsg = vmsg; -- struct peci_xfer_msg msg; -- int rc = 0, i; -+ struct peci_xfer_msg *msg; - u32 address; -+ int ret, i; -+ u8 aw_fcs; - - /* Per the PECI spec, the write length must be a byte, word, or dword */ - if (umsg->tx_len != 1 && umsg->tx_len != 2 && umsg->tx_len != 4) { -@@ -489,47 +694,57 @@ static int peci_ioctl_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) - return -EINVAL; - } - -+ msg = peci_get_xfer_msg(PECI_WRPCICFGLOCAL_WRITE_LEN_BASE + -+ umsg->tx_len, PECI_WRPCICFGLOCAL_READ_LEN); -+ if (!msg) -+ return -ENOMEM; -+ - address = umsg->reg; /* [11:0] - Register */ - address |= (u32)umsg->function << 12; /* [14:12] - Function */ - address |= (u32)umsg->device << 15; /* [19:15] - Device */ - address |= (u32)umsg->bus << 20; /* [23:20] - Bus */ - -- msg.addr = umsg->addr; -- msg.tx_len = WRPCICFGLOCAL_WRITE_LEN_BASE + umsg->tx_len; -- msg.rx_len = WRPCICFGLOCAL_READ_LEN; -- msg.tx_buf[0] = WRPCICFGLOCAL_PECI_CMD; -- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ -- /* Host ID is 0 for PECI 3.0 */ -- msg.tx_buf[2] = (u8)address; /* LSB - PCI Configuration Address */ -- msg.tx_buf[3] = (u8)(address >> 8); /* PCI Configuration Address */ -- msg.tx_buf[4] = (u8)(address >> 16); /* PCI Configuration Address */ -+ msg->addr = umsg->addr; -+ msg->tx_buf[0] = PECI_WRPCICFGLOCAL_CMD; -+ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ -+ /* Host ID is 0 for PECI 3.0 */ -+ msg->tx_buf[2] = (u8)address; /* LSB - PCI Configuration Address */ -+ msg->tx_buf[3] = (u8)(address >> 8); /* PCI Configuration Address */ -+ msg->tx_buf[4] = (u8)(address >> 16); /* PCI Configuration Address */ - for (i = 0; i < umsg->tx_len; i++) -- msg.tx_buf[5 + i] = (u8)(umsg->value >> (i << 3)); -+ msg->tx_buf[5 + i] = (u8)(umsg->value >> (i << 3)); -+ -+ /* Add an Assured Write Frame Check Sequence byte */ -+ ret = peci_aw_fcs(msg, 8 + umsg->tx_len, &aw_fcs); -+ if (ret) -+ goto out; - -- /* Add an Assure Write Frame Check Sequence byte */ -- msg.tx_buf[5 + i] = 0x80 ^ -- peci_aw_fcs((u8 *)&msg, 8 + umsg->tx_len); -+ msg->tx_buf[5 + i] = 0x80 ^ aw_fcs; - -- rc = peci_xfer_with_retries(adapter, &msg, true); -+ ret = peci_xfer_with_retries(adapter, msg, true); - -- return rc; -+out: -+ umsg->cc = msg->rx_buf[0]; -+ peci_put_xfer_msg(msg); -+ -+ return ret; - } - --typedef int (*peci_ioctl_fn_type)(struct peci_adapter *, void *); -- --static const peci_ioctl_fn_type peci_ioctl_fn[PECI_CMD_MAX] = { -- peci_ioctl_xfer, -- peci_ioctl_ping, -- peci_ioctl_get_dib, -- peci_ioctl_get_temp, -- peci_ioctl_rd_pkg_cfg, -- peci_ioctl_wr_pkg_cfg, -- peci_ioctl_rd_ia_msr, -- NULL, /* Reserved */ -- peci_ioctl_rd_pci_cfg, -- NULL, /* Reserved */ -- peci_ioctl_rd_pci_cfg_local, -- peci_ioctl_wr_pci_cfg_local, -+typedef int (*peci_cmd_fn_type)(struct peci_adapter *, void *); -+ -+static const peci_cmd_fn_type peci_cmd_fn[PECI_CMD_MAX] = { -+ peci_cmd_xfer, -+ peci_cmd_ping, -+ peci_cmd_get_dib, -+ peci_cmd_get_temp, -+ peci_cmd_rd_pkg_cfg, -+ peci_cmd_wr_pkg_cfg, -+ peci_cmd_rd_ia_msr, -+ peci_cmd_wr_ia_msr, -+ peci_cmd_rd_pci_cfg, -+ peci_cmd_wr_pci_cfg, -+ peci_cmd_rd_pci_cfg_local, -+ peci_cmd_wr_pci_cfg_local, - }; - - /** -@@ -545,109 +760,28 @@ static const peci_ioctl_fn_type peci_ioctl_fn[PECI_CMD_MAX] = { - */ - int peci_command(struct peci_adapter *adapter, enum peci_cmd cmd, void *vmsg) - { -- int rc = 0; -+ int ret; - - if (cmd >= PECI_CMD_MAX || cmd < PECI_CMD_XFER) -- return -EINVAL; -+ return -ENOTTY; - - dev_dbg(&adapter->dev, "%s, cmd=0x%02x\n", __func__, cmd); - -- if (!peci_ioctl_fn[cmd]) -+ if (!peci_cmd_fn[cmd]) - return -EINVAL; - -- rt_mutex_lock(&adapter->bus_lock); -+ mutex_lock(&adapter->bus_lock); - -- rc = peci_cmd_support(adapter, cmd); -- if (!rc) -- rc = peci_ioctl_fn[cmd](adapter, vmsg); -+ ret = peci_check_cmd_support(adapter, cmd); -+ if (!ret) -+ ret = peci_cmd_fn[cmd](adapter, vmsg); - -- rt_mutex_unlock(&adapter->bus_lock); -+ mutex_unlock(&adapter->bus_lock); - -- return rc; -+ return ret; - } - EXPORT_SYMBOL_GPL(peci_command); - --static long peci_ioctl(struct file *file, unsigned int iocmd, unsigned long arg) --{ -- struct peci_adapter *adapter = file->private_data; -- void __user *argp = (void __user *)arg; -- unsigned int msg_len; -- enum peci_cmd cmd; -- int rc = 0; -- u8 *msg; -- -- if (!capable(CAP_SYS_ADMIN)) -- return -EPERM; -- -- dev_dbg(&adapter->dev, "ioctl, cmd=0x%x, arg=0x%lx\n", iocmd, arg); -- -- switch (iocmd) { -- case PECI_IOC_XFER: -- case PECI_IOC_PING: -- case PECI_IOC_GET_DIB: -- case PECI_IOC_GET_TEMP: -- case PECI_IOC_RD_PKG_CFG: -- case PECI_IOC_WR_PKG_CFG: -- case PECI_IOC_RD_IA_MSR: -- case PECI_IOC_RD_PCI_CFG: -- case PECI_IOC_RD_PCI_CFG_LOCAL: -- case PECI_IOC_WR_PCI_CFG_LOCAL: -- cmd = _IOC_NR(iocmd); -- msg_len = _IOC_SIZE(iocmd); -- break; -- -- default: -- dev_dbg(&adapter->dev, "Invalid ioctl cmd : 0x%x\n", iocmd); -- return -ENOTTY; -- } -- -- if (!access_ok(argp, msg_len)) -- return -EFAULT; -- -- msg = memdup_user(argp, msg_len); -- if (IS_ERR(msg)) -- return PTR_ERR(msg); -- -- rc = peci_command(adapter, cmd, msg); -- -- if (!rc && copy_to_user(argp, msg, msg_len)) -- rc = -EFAULT; -- -- kfree(msg); -- return (long)rc; --} -- --static int peci_open(struct inode *inode, struct file *file) --{ -- unsigned int minor = iminor(inode); -- struct peci_adapter *adapter; -- -- adapter = peci_get_adapter(minor); -- if (!adapter) -- return -ENODEV; -- -- file->private_data = adapter; -- -- return 0; --} -- --static int peci_release(struct inode *inode, struct file *file) --{ -- struct peci_adapter *adapter = file->private_data; -- -- peci_put_adapter(adapter); -- file->private_data = NULL; -- -- return 0; --} -- --static const struct file_operations peci_fops = { -- .owner = THIS_MODULE, -- .unlocked_ioctl = peci_ioctl, -- .open = peci_open, -- .release = peci_release, --}; -- - static int peci_detect(struct peci_adapter *adapter, u8 addr) - { - struct peci_ping_msg msg; -@@ -666,9 +800,9 @@ peci_of_match_device(const struct of_device_id *matches, - return NULL; - - return of_match_device(matches, &client->dev); --#else -+#else /* CONFIG_OF */ - return NULL; --#endif -+#endif /* CONFIG_OF */ - } - - static const struct peci_device_id * -@@ -737,6 +871,7 @@ static int peci_device_probe(struct device *dev) - - err_detach_pm_domain: - dev_pm_domain_detach(&client->dev, true); -+ - return status; - } - -@@ -775,13 +910,14 @@ static void peci_device_shutdown(struct device *dev) - driver->shutdown(client); - } - --static struct bus_type peci_bus_type = { -+struct bus_type peci_bus_type = { - .name = "peci", - .match = peci_device_match, - .probe = peci_device_probe, - .remove = peci_device_remove, - .shutdown = peci_device_shutdown, - }; -+EXPORT_SYMBOL_GPL(peci_bus_type); - - static int peci_check_addr_validity(u8 addr) - { -@@ -814,18 +950,22 @@ static int peci_check_client_busy(struct device *dev, void *client_new_p) - int peci_get_cpu_id(struct peci_adapter *adapter, u8 addr, u32 *cpu_id) - { - struct peci_rd_pkg_cfg_msg msg; -- int rc; -+ int ret; - - msg.addr = addr; -- msg.index = MBX_INDEX_CPU_ID; -- msg.param = PKG_ID_CPU_ID; -+ msg.index = PECI_MBX_INDEX_CPU_ID; -+ msg.param = PECI_PKG_ID_CPU_ID; - msg.rx_len = 4; - -- rc = peci_command(adapter, PECI_CMD_RD_PKG_CFG, &msg); -- if (!rc) -- *cpu_id = le32_to_cpup((__le32 *)msg.pkg_config); -+ ret = peci_command(adapter, PECI_CMD_RD_PKG_CFG, &msg); -+ if (msg.cc != PECI_DEV_CC_SUCCESS) -+ ret = -EAGAIN; -+ if (ret) -+ return ret; -+ -+ *cpu_id = le32_to_cpup((__le32 *)msg.pkg_config); - -- return rc; -+ return 0; - } - EXPORT_SYMBOL_GPL(peci_get_cpu_id); - -@@ -833,7 +973,7 @@ static struct peci_client *peci_new_device(struct peci_adapter *adapter, - struct peci_board_info const *info) - { - struct peci_client *client; -- int rc; -+ int ret; - - /* Increase reference count for the adapter assigned */ - if (!peci_get_adapter(adapter->nr)) -@@ -847,46 +987,49 @@ static struct peci_client *peci_new_device(struct peci_adapter *adapter, - client->addr = info->addr; - strlcpy(client->name, info->type, sizeof(client->name)); - -- rc = peci_check_addr_validity(client->addr); -- if (rc) { -+ ret = peci_check_addr_validity(client->addr); -+ if (ret) { - dev_err(&adapter->dev, "Invalid PECI CPU address 0x%02hx\n", - client->addr); - goto err_free_client_silent; - } - - /* Check online status of client */ -- rc = peci_detect(adapter, client->addr); -- if (rc) -+ ret = peci_detect(adapter, client->addr); -+ if (ret) - goto err_free_client; - -- rc = device_for_each_child(&adapter->dev, client, -- peci_check_client_busy); -- if (rc) -+ ret = device_for_each_child(&adapter->dev, client, -+ peci_check_client_busy); -+ if (ret) - goto err_free_client; - - client->dev.parent = &client->adapter->dev; - client->dev.bus = &peci_bus_type; - client->dev.type = &peci_client_type; -- client->dev.of_node = info->of_node; -+ client->dev.of_node = of_node_get(info->of_node); - dev_set_name(&client->dev, "%d-%02x", adapter->nr, client->addr); - -- rc = device_register(&client->dev); -- if (rc) -- goto err_free_client; -+ ret = device_register(&client->dev); -+ if (ret) -+ goto err_put_of_node; - - dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", - client->name, dev_name(&client->dev)); - - return client; - -+err_put_of_node: -+ of_node_put(info->of_node); - err_free_client: - dev_err(&adapter->dev, - "Failed to register peci client %s at 0x%02x (%d)\n", -- client->name, client->addr, rc); -+ client->name, client->addr, ret); - err_free_client_silent: - kfree(client); - err_put_adapter: - peci_put_adapter(adapter); -+ - return NULL; - } - -@@ -895,8 +1038,10 @@ static void peci_unregister_device(struct peci_client *client) - if (!client) - return; - -- if (client->dev.of_node) -+ if (client->dev.of_node) { - of_node_clear_flag(client->dev.of_node, OF_POPULATED); -+ of_node_put(client->dev.of_node); -+ } - - device_unregister(&client->dev); - } -@@ -916,7 +1061,7 @@ static void peci_adapter_dev_release(struct device *dev) - - dev_dbg(dev, "%s: %s\n", __func__, adapter->name); - mutex_destroy(&adapter->userspace_clients_lock); -- rt_mutex_destroy(&adapter->bus_lock); -+ mutex_destroy(&adapter->bus_lock); - kfree(adapter); - } - -@@ -928,7 +1073,8 @@ static ssize_t peci_sysfs_new_device(struct device *dev, - struct peci_board_info info = {}; - struct peci_client *client; - char *blank, end; -- int rc; -+ short addr; -+ int ret; - - /* Parse device type */ - blank = strchr(buf, ' '); -@@ -943,16 +1089,17 @@ static ssize_t peci_sysfs_new_device(struct device *dev, - memcpy(info.type, buf, blank - buf); - - /* Parse remaining parameters, reject extra parameters */ -- rc = sscanf(++blank, "%hi%c", &info.addr, &end); -- if (rc < 1) { -+ ret = sscanf(++blank, "%hi%c", &addr, &end); -+ if (ret < 1) { - dev_err(dev, "%s: Can't parse client address\n", "new_device"); - return -EINVAL; - } -- if (rc > 1 && end != '\n') { -+ if (ret > 1 && end != '\n') { - dev_err(dev, "%s: Extra parameters\n", "new_device"); - return -EINVAL; - } - -+ info.addr = (u8)addr; - client = peci_new_device(adapter, &info); - if (!client) - return -EINVAL; -@@ -961,8 +1108,8 @@ static ssize_t peci_sysfs_new_device(struct device *dev, - mutex_lock(&adapter->userspace_clients_lock); - list_add_tail(&client->detected, &adapter->userspace_clients); - mutex_unlock(&adapter->userspace_clients_lock); -- dev_info(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device", -- info.type, info.addr); -+ dev_dbg(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device", -+ info.type, info.addr); - - return count; - } -@@ -975,9 +1122,9 @@ static ssize_t peci_sysfs_delete_device(struct device *dev, - struct peci_adapter *adapter = to_peci_adapter(dev); - struct peci_client *client, *next; - struct peci_board_info info = {}; -- struct peci_driver *driver; - char *blank, end; -- int rc; -+ short addr; -+ int ret; - - /* Parse device type */ - blank = strchr(buf, ' '); -@@ -992,41 +1139,41 @@ static ssize_t peci_sysfs_delete_device(struct device *dev, - memcpy(info.type, buf, blank - buf); - - /* Parse remaining parameters, reject extra parameters */ -- rc = sscanf(++blank, "%hi%c", &info.addr, &end); -- if (rc < 1) { -+ ret = sscanf(++blank, "%hi%c", &addr, &end); -+ if (ret < 1) { - dev_err(dev, "%s: Can't parse client address\n", - "delete_device"); - return -EINVAL; - } -- if (rc > 1 && end != '\n') { -+ if (ret > 1 && end != '\n') { - dev_err(dev, "%s: Extra parameters\n", "delete_device"); - return -EINVAL; - } - -+ info.addr = (u8)addr; -+ - /* Make sure the device was added through sysfs */ -- rc = -ENOENT; -+ ret = -ENOENT; - mutex_lock(&adapter->userspace_clients_lock); - list_for_each_entry_safe(client, next, &adapter->userspace_clients, - detected) { -- driver = to_peci_driver(client->dev.driver); -- - if (client->addr == info.addr && - !strncmp(client->name, info.type, PECI_NAME_SIZE)) { -- dev_info(dev, "%s: Deleting device %s at 0x%02hx\n", -- "delete_device", client->name, client->addr); -+ dev_dbg(dev, "%s: Deleting device %s at 0x%02hx\n", -+ "delete_device", client->name, client->addr); - list_del(&client->detected); - peci_unregister_device(client); -- rc = count; -+ ret = count; - break; - } - } - mutex_unlock(&adapter->userspace_clients_lock); - -- if (rc < 0) -- dev_err(dev, "%s: Can't find device in list\n", -+ if (ret < 0) -+ dev_dbg(dev, "%s: Can't find device in list\n", - "delete_device"); - -- return rc; -+ return ret; - } - static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, 0200, NULL, - peci_sysfs_delete_device); -@@ -1039,10 +1186,11 @@ static struct attribute *peci_adapter_attrs[] = { - }; - ATTRIBUTE_GROUPS(peci_adapter); - --static struct device_type peci_adapter_type = { -+struct device_type peci_adapter_type = { - .groups = peci_adapter_groups, - .release = peci_adapter_dev_release, - }; -+EXPORT_SYMBOL_GPL(peci_adapter_type); - - /** - * peci_verify_adapter - return parameter as peci_adapter, or NULL -@@ -1063,32 +1211,26 @@ static struct peci_client *peci_of_register_device(struct peci_adapter *adapter, - struct device_node *node) - { - struct peci_board_info info = {}; -- struct peci_client *result; -- const __be32 *addr_be; -- int len; -+ struct peci_client *client; -+ u32 addr; -+ int ret; - - dev_dbg(&adapter->dev, "register %pOF\n", node); - -- if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) { -- dev_err(&adapter->dev, "modalias failure on %pOF\n", node); -- return ERR_PTR(-EINVAL); -- } -- -- addr_be = of_get_property(node, "reg", &len); -- if (!addr_be || len < sizeof(*addr_be)) { -+ ret = of_property_read_u32(node, "reg", &addr); -+ if (ret) { - dev_err(&adapter->dev, "invalid reg on %pOF\n", node); -- return ERR_PTR(-EINVAL); -+ return ERR_PTR(ret); - } - -- info.addr = be32_to_cpup(addr_be); -- info.of_node = of_node_get(node); -+ info.addr = addr; -+ info.of_node = node; - -- result = peci_new_device(adapter, &info); -- if (!result) -- result = ERR_PTR(-EINVAL); -+ client = peci_new_device(adapter, &info); -+ if (!client) -+ client = ERR_PTR(-EINVAL); - -- of_node_put(node); -- return result; -+ return client; - } - - static void peci_of_register_devices(struct peci_adapter *adapter) -@@ -1119,7 +1261,7 @@ static void peci_of_register_devices(struct peci_adapter *adapter) - - of_node_put(bus); - } --#else -+#else /* CONFIG_OF */ - static void peci_of_register_devices(struct peci_adapter *adapter) { } - #endif /* CONFIG_OF */ - -@@ -1163,9 +1305,7 @@ static struct peci_adapter *peci_of_find_adapter(struct device_node *node) - return adapter; - } - --static int peci_of_notify(struct notifier_block *nb, -- unsigned long action, -- void *arg) -+static int peci_of_notify(struct notifier_block *nb, ulong action, void *arg) - { - struct of_reconfig_data *rd = arg; - struct peci_adapter *adapter; -@@ -1216,7 +1356,7 @@ static int peci_of_notify(struct notifier_block *nb, - static struct notifier_block peci_of_notifier = { - .notifier_call = peci_of_notify, - }; --#else -+#else /* CONFIG_OF_DYNAMIC */ - extern struct notifier_block peci_of_notifier; - #endif /* CONFIG_OF_DYNAMIC */ - -@@ -1240,7 +1380,7 @@ extern struct notifier_block peci_of_notifier; - * - * Return: the peci_adapter structure on success, else NULL. - */ --struct peci_adapter *peci_alloc_adapter(struct device *dev, unsigned int size) -+struct peci_adapter *peci_alloc_adapter(struct device *dev, uint size) - { - struct peci_adapter *adapter; - -@@ -1263,7 +1403,7 @@ EXPORT_SYMBOL_GPL(peci_alloc_adapter); - - static int peci_register_adapter(struct peci_adapter *adapter) - { -- int rc = -EINVAL; -+ int ret = -EINVAL; - - /* Can't register until after driver model init */ - if (WARN_ON(!is_registered)) -@@ -1275,27 +1415,17 @@ static int peci_register_adapter(struct peci_adapter *adapter) - if (WARN(!adapter->xfer, "peci adapter has no xfer function\n")) - goto err_free_idr; - -- rt_mutex_init(&adapter->bus_lock); -+ mutex_init(&adapter->bus_lock); - mutex_init(&adapter->userspace_clients_lock); - INIT_LIST_HEAD(&adapter->userspace_clients); - - dev_set_name(&adapter->dev, "peci-%d", adapter->nr); - -- /* cdev */ -- cdev_init(&adapter->cdev, &peci_fops); -- adapter->cdev.owner = THIS_MODULE; -- adapter->dev.devt = MKDEV(MAJOR(peci_devt), adapter->nr); -- rc = cdev_add(&adapter->cdev, adapter->dev.devt, 1); -- if (rc) { -- pr_err("adapter '%s': can't add cdev (%d)\n", -- adapter->name, rc); -- goto err_free_idr; -- } -- rc = device_add(&adapter->dev); -- if (rc) { -+ ret = device_add(&adapter->dev); -+ if (ret) { - pr_err("adapter '%s': can't add device (%d)\n", -- adapter->name, rc); -- goto err_del_cdev; -+ adapter->name, ret); -+ goto err_free_idr; - } - - dev_dbg(&adapter->dev, "adapter [%s] registered\n", adapter->name); -@@ -1309,13 +1439,11 @@ static int peci_register_adapter(struct peci_adapter *adapter) - - return 0; - --err_del_cdev: -- cdev_del(&adapter->cdev); - err_free_idr: - mutex_lock(&core_lock); - idr_remove(&peci_adapter_idr, adapter->nr); - mutex_unlock(&core_lock); -- return rc; -+ return ret; - } - - static int peci_add_numbered_adapter(struct peci_adapter *adapter) -@@ -1354,12 +1482,10 @@ int peci_add_adapter(struct peci_adapter *adapter) - struct device *dev = &adapter->dev; - int id; - -- if (dev->of_node) { -- id = of_alias_get_id(dev->of_node, "peci"); -- if (id >= 0) { -- adapter->nr = id; -- return peci_add_numbered_adapter(adapter); -- } -+ id = of_alias_get_id(dev->of_node, "peci"); -+ if (id >= 0) { -+ adapter->nr = id; -+ return peci_add_numbered_adapter(adapter); - } - - mutex_lock(&core_lock); -@@ -1411,7 +1537,7 @@ void peci_del_adapter(struct peci_adapter *adapter) - } - mutex_unlock(&adapter->userspace_clients_lock); - -- /** -+ /* - * Detach any active clients. This can't fail, thus we do not - * check the returned value. - */ -@@ -1420,13 +1546,8 @@ void peci_del_adapter(struct peci_adapter *adapter) - /* device name is gone after device_unregister */ - dev_dbg(&adapter->dev, "adapter [%s] unregistered\n", adapter->name); - -- /* free cdev */ -- cdev_del(&adapter->cdev); -- - pm_runtime_disable(&adapter->dev); -- - nr = adapter->nr; -- - device_unregister(&adapter->dev); - - /* free bus id */ -@@ -1436,6 +1557,18 @@ void peci_del_adapter(struct peci_adapter *adapter) - } - EXPORT_SYMBOL_GPL(peci_del_adapter); - -+int peci_for_each_dev(void *data, int (*fn)(struct device *, void *)) -+{ -+ int ret; -+ -+ mutex_lock(&core_lock); -+ ret = bus_for_each_dev(&peci_bus_type, NULL, data, fn); -+ mutex_unlock(&core_lock); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(peci_for_each_dev); -+ - /** - * peci_register_driver - register a PECI driver - * @owner: owner module of the driver being registered -@@ -1446,7 +1579,7 @@ EXPORT_SYMBOL_GPL(peci_del_adapter); - */ - int peci_register_driver(struct module *owner, struct peci_driver *driver) - { -- int rc; -+ int ret; - - /* Can't register until after driver model init */ - if (WARN_ON(!is_registered)) -@@ -1456,13 +1589,13 @@ int peci_register_driver(struct module *owner, struct peci_driver *driver) - driver->driver.owner = owner; - driver->driver.bus = &peci_bus_type; - -- /** -+ /* - * When registration returns, the driver core - * will have called probe() for all matching-but-unbound devices. - */ -- rc = driver_register(&driver->driver); -- if (rc) -- return rc; -+ ret = driver_register(&driver->driver); -+ if (ret) -+ return ret; - - pr_debug("driver [%s] registered\n", driver->driver.name); - -@@ -1492,13 +1625,6 @@ static int __init peci_init(void) - return ret; - } - -- ret = alloc_chrdev_region(&peci_devt, 0, PECI_CDEV_MAX, "peci"); -- if (ret < 0) { -- pr_err("peci: Failed to allocate chr dev region!\n"); -- bus_unregister(&peci_bus_type); -- return ret; -- } -- - crc8_populate_msb(peci_crc8_table, PECI_CRC8_POLYNOMIAL); - - if (IS_ENABLED(CONFIG_OF_DYNAMIC)) -@@ -1514,11 +1640,10 @@ static void __exit peci_exit(void) - if (IS_ENABLED(CONFIG_OF_DYNAMIC)) - WARN_ON(of_reconfig_notifier_unregister(&peci_of_notifier)); - -- unregister_chrdev_region(peci_devt, PECI_CDEV_MAX); - bus_unregister(&peci_bus_type); - } - --postcore_initcall(peci_init); -+subsys_initcall(peci_init); - module_exit(peci_exit); - - MODULE_AUTHOR("Jason M Biils <jason.m.bills@linux.intel.com>"); -diff --git a/drivers/peci/peci-dev.c b/drivers/peci/peci-dev.c -new file mode 100644 -index 0000000..ac9cba0 ---- /dev/null -+++ b/drivers/peci/peci-dev.c -@@ -0,0 +1,346 @@ -+// SPDX-License-Identifier: GPL-2.0 -+// Copyright (c) 2018-2019 Intel Corporation -+ -+#include <linux/cdev.h> -+#include <linux/fs.h> -+#include <linux/list.h> -+#include <linux/module.h> -+#include <linux/notifier.h> -+#include <linux/peci.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+ -+/* -+ * A peci_dev represents an peci_adapter ... an PECI or SMBus master, not a -+ * slave (peci_client) with which messages will be exchanged. It's coupled -+ * with a character special file which is accessed by user mode drivers. -+ * -+ * The list of peci_dev structures is parallel to the peci_adapter lists -+ * maintained by the driver model, and is updated using bus notifications. -+ */ -+struct peci_dev { -+ struct list_head list; -+ struct peci_adapter *adapter; -+ struct device *dev; -+ struct cdev cdev; -+}; -+ -+#define PECI_MINORS MINORMASK -+ -+static dev_t peci_devt; -+static LIST_HEAD(peci_dev_list); -+static DEFINE_SPINLOCK(peci_dev_list_lock); -+ -+static struct peci_dev *peci_dev_get_by_minor(uint index) -+{ -+ struct peci_dev *peci_dev; -+ -+ spin_lock(&peci_dev_list_lock); -+ list_for_each_entry(peci_dev, &peci_dev_list, list) { -+ if (peci_dev->adapter->nr == index) -+ goto found; -+ } -+ peci_dev = NULL; -+found: -+ spin_unlock(&peci_dev_list_lock); -+ -+ return peci_dev; -+} -+ -+static struct peci_dev *peci_dev_alloc(struct peci_adapter *adapter) -+{ -+ struct peci_dev *peci_dev; -+ -+ if (adapter->nr >= PECI_MINORS) { -+ printk(KERN_ERR "peci-dev: Out of device minors (%d)\n", -+ adapter->nr); -+ return ERR_PTR(-ENODEV); -+ } -+ -+ peci_dev = kzalloc(sizeof(*peci_dev), GFP_KERNEL); -+ if (!peci_dev) -+ return ERR_PTR(-ENOMEM); -+ peci_dev->adapter = adapter; -+ -+ spin_lock(&peci_dev_list_lock); -+ list_add_tail(&peci_dev->list, &peci_dev_list); -+ spin_unlock(&peci_dev_list_lock); -+ -+ return peci_dev; -+} -+ -+static void peci_dev_put(struct peci_dev *peci_dev) -+{ -+ spin_lock(&peci_dev_list_lock); -+ list_del(&peci_dev->list); -+ spin_unlock(&peci_dev_list_lock); -+ kfree(peci_dev); -+} -+ -+static ssize_t name_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct peci_dev *peci_dev = peci_dev_get_by_minor(MINOR(dev->devt)); -+ -+ if (!peci_dev) -+ return -ENODEV; -+ -+ return sprintf(buf, "%s\n", peci_dev->adapter->name); -+} -+static DEVICE_ATTR_RO(name); -+ -+static struct attribute *peci_dev_attrs[] = { -+ &dev_attr_name.attr, -+ NULL, -+}; -+ATTRIBUTE_GROUPS(peci_dev); -+ -+static long peci_dev_ioctl(struct file *file, uint iocmd, ulong arg) -+{ -+ struct peci_dev *peci_dev = file->private_data; -+ void __user *umsg = (void __user *)arg; -+ struct peci_xfer_msg *xmsg = NULL; -+ struct peci_xfer_msg uxmsg; -+ enum peci_cmd cmd; -+ u8 *msg = NULL; -+ uint msg_len; -+ int ret; -+ -+ cmd = _IOC_NR(iocmd); -+ msg_len = _IOC_SIZE(iocmd); -+ -+ switch (cmd) { -+ case PECI_CMD_XFER: -+ if (msg_len != sizeof(struct peci_xfer_msg)) { -+ ret = -EFAULT; -+ break; -+ } -+ -+ if (copy_from_user(&uxmsg, umsg, msg_len)) { -+ ret = -EFAULT; -+ break; -+ } -+ -+ xmsg = peci_get_xfer_msg(uxmsg.tx_len, uxmsg.rx_len); -+ if (IS_ERR(xmsg)) { -+ ret = PTR_ERR(xmsg); -+ break; -+ } -+ -+ if (uxmsg.tx_len && -+ copy_from_user(xmsg->tx_buf, uxmsg.tx_buf, uxmsg.tx_len)) { -+ ret = -EFAULT; -+ break; -+ } -+ -+ xmsg->addr = uxmsg.addr; -+ xmsg->tx_len = uxmsg.tx_len; -+ xmsg->rx_len = uxmsg.rx_len; -+ -+ ret = peci_command(peci_dev->adapter, cmd, xmsg); -+ if (!ret && xmsg->rx_len && -+ copy_to_user(uxmsg.rx_buf, xmsg->rx_buf, xmsg->rx_len)) -+ ret = -EFAULT; -+ -+ break; -+ -+ default: -+ msg = memdup_user(umsg, msg_len); -+ if (IS_ERR(msg)) { -+ ret = PTR_ERR(msg); -+ break; -+ } -+ -+ ret = peci_command(peci_dev->adapter, cmd, msg); -+ if ((!ret || ret == -ETIMEDOUT) && -+ copy_to_user(umsg, msg, msg_len)) -+ ret = -EFAULT; -+ -+ break; -+ } -+ -+ peci_put_xfer_msg(xmsg); -+ kfree(msg); -+ -+ return (long)ret; -+} -+ -+static int peci_dev_open(struct inode *inode, struct file *file) -+{ -+ struct peci_adapter *adapter; -+ struct peci_dev *peci_dev; -+ -+ peci_dev = peci_dev_get_by_minor(iminor(inode)); -+ if (!peci_dev) -+ return -ENODEV; -+ -+ adapter = peci_get_adapter(peci_dev->adapter->nr); -+ if (!adapter) -+ return -ENODEV; -+ -+ file->private_data = peci_dev; -+ -+ return 0; -+} -+ -+static int peci_dev_release(struct inode *inode, struct file *file) -+{ -+ struct peci_dev *peci_dev = file->private_data; -+ -+ peci_put_adapter(peci_dev->adapter); -+ file->private_data = NULL; -+ -+ return 0; -+} -+ -+static const struct file_operations peci_dev_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = peci_dev_ioctl, -+ .open = peci_dev_open, -+ .release = peci_dev_release, -+ .llseek = no_llseek, -+}; -+ -+static struct class *peci_dev_class; -+ -+static int peci_dev_attach_adapter(struct device *dev, void *dummy) -+{ -+ struct peci_adapter *adapter; -+ struct peci_dev *peci_dev; -+ dev_t devt; -+ int ret; -+ -+ if (dev->type != &peci_adapter_type) -+ return 0; -+ -+ adapter = to_peci_adapter(dev); -+ peci_dev = peci_dev_alloc(adapter); -+ if (IS_ERR(peci_dev)) -+ return PTR_ERR(peci_dev); -+ -+ cdev_init(&peci_dev->cdev, &peci_dev_fops); -+ peci_dev->cdev.owner = THIS_MODULE; -+ devt = MKDEV(MAJOR(peci_devt), adapter->nr); -+ -+ ret = cdev_add(&peci_dev->cdev, devt, 1); -+ if (ret) -+ goto err_put_dev; -+ -+ /* register this peci device with the driver core */ -+ peci_dev->dev = device_create(peci_dev_class, &adapter->dev, devt, NULL, -+ "peci-%d", adapter->nr); -+ if (IS_ERR(peci_dev->dev)) { -+ ret = PTR_ERR(peci_dev->dev); -+ goto err_del_cdev; -+ } -+ -+ pr_info("peci-dev: adapter [%s] registered as minor %d\n", -+ adapter->name, adapter->nr); -+ -+ return 0; -+ -+err_del_cdev: -+ cdev_del(&peci_dev->cdev); -+err_put_dev: -+ peci_dev_put(peci_dev); -+ -+ return ret; -+} -+ -+static int peci_dev_detach_adapter(struct device *dev, void *dummy) -+{ -+ struct peci_adapter *adapter; -+ struct peci_dev *peci_dev; -+ dev_t devt; -+ -+ if (dev->type != &peci_adapter_type) -+ return 0; -+ -+ adapter = to_peci_adapter(dev); -+ peci_dev = peci_dev_get_by_minor(adapter->nr); -+ if (!peci_dev) -+ return 0; -+ -+ cdev_del(&peci_dev->cdev); -+ devt = peci_dev->dev->devt; -+ peci_dev_put(peci_dev); -+ device_destroy(peci_dev_class, devt); -+ -+ pr_info("peci-dev: adapter [%s] unregistered\n", adapter->name); -+ -+ return 0; -+} -+ -+static int peci_dev_notifier_call(struct notifier_block *nb, ulong action, -+ void *data) -+{ -+ struct device *dev = data; -+ -+ switch (action) { -+ case BUS_NOTIFY_ADD_DEVICE: -+ return peci_dev_attach_adapter(dev, NULL); -+ case BUS_NOTIFY_DEL_DEVICE: -+ return peci_dev_detach_adapter(dev, NULL); -+ } -+ -+ return 0; -+} -+ -+static struct notifier_block peci_dev_notifier = { -+ .notifier_call = peci_dev_notifier_call, -+}; -+ -+static int __init peci_dev_init(void) -+{ -+ int ret; -+ -+ printk(KERN_INFO "peci /dev entries driver\n"); -+ -+ ret = alloc_chrdev_region(&peci_devt, 0, PECI_MINORS, "peci"); -+ if (ret < 0) { -+ pr_err("peci: Failed to allocate chr dev region!\n"); -+ bus_unregister(&peci_bus_type); -+ goto err; -+ } -+ -+ peci_dev_class = class_create(THIS_MODULE, "peci-dev"); -+ if (IS_ERR(peci_dev_class)) { -+ ret = PTR_ERR(peci_dev_class); -+ goto err_unreg_chrdev; -+ } -+ peci_dev_class->dev_groups = peci_dev_groups; -+ -+ /* Keep track of adapters which will be added or removed later */ -+ ret = bus_register_notifier(&peci_bus_type, &peci_dev_notifier); -+ if (ret) -+ goto err_destroy_class; -+ -+ /* Bind to already existing adapters right away */ -+ peci_for_each_dev(NULL, peci_dev_attach_adapter); -+ -+ return 0; -+ -+err_destroy_class: -+ class_destroy(peci_dev_class); -+err_unreg_chrdev: -+ unregister_chrdev_region(peci_devt, PECI_MINORS); -+err: -+ printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__); -+ -+ return ret; -+} -+ -+static void __exit peci_dev_exit(void) -+{ -+ bus_unregister_notifier(&peci_bus_type, &peci_dev_notifier); -+ peci_for_each_dev(NULL, peci_dev_detach_adapter); -+ class_destroy(peci_dev_class); -+ unregister_chrdev_region(peci_devt, PECI_MINORS); -+} -+ -+module_init(peci_dev_init); -+module_exit(peci_dev_exit); -+ -+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>"); -+MODULE_DESCRIPTION("PECI /dev entries driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/peci/peci-npcm.c b/drivers/peci/peci-npcm.c -deleted file mode 100644 -index f632365..0000000 ---- a/drivers/peci/peci-npcm.c -+++ /dev/null -@@ -1,410 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0 --// Copyright (c) 2019 Nuvoton Technology corporation. -- --#include <linux/bitfield.h> --#include <linux/clk.h> --#include <linux/interrupt.h> --#include <linux/jiffies.h> --#include <linux/module.h> --#include <linux/of.h> --#include <linux/peci.h> --#include <linux/platform_device.h> --#include <linux/regmap.h> --#include <linux/mfd/syscon.h> --#include <linux/reset.h> -- --/* NPCM7xx GCR module */ --#define NPCM7XX_INTCR3_OFFSET 0x9C --#define NPCM7XX_INTCR3_PECIVSEL BIT(19) -- --/* NPCM PECI Registers */ --#define NPCM_PECI_CTL_STS 0x00 --#define NPCM_PECI_RD_LENGTH 0x04 --#define NPCM_PECI_ADDR 0x08 --#define NPCM_PECI_CMD 0x0C --#define NPCM_PECI_CTL2 0x10 --#define NPCM_PECI_WR_LENGTH 0x1C --#define NPCM_PECI_PDDR 0x2C --#define NPCM_PECI_DAT_INOUT(n) (0x100 + ((n) * 4)) -- --#define NPCM_PECI_MAX_REG 0x200 -- --/* NPCM_PECI_CTL_STS - 0x00 : Control Register */ --#define NPCM_PECI_CTRL_DONE_INT_EN BIT(6) --#define NPCM_PECI_CTRL_ABRT_ERR BIT(4) --#define NPCM_PECI_CTRL_CRC_ERR BIT(3) --#define NPCM_PECI_CTRL_DONE BIT(1) --#define NPCM_PECI_CTRL_START_BUSY BIT(0) -- --/* NPCM_PECI_RD_LENGTH - 0x04 : Command Register */ --#define NPCM_PECI_RD_LEN_MASK GENMASK(6, 0) -- --/* NPCM_PECI_CMD - 0x10 : Command Register */ --#define NPCM_PECI_CTL2_MASK GENMASK(7, 6) -- --/* NPCM_PECI_WR_LENGTH - 0x1C : Command Register */ --#define NPCM_PECI_WR_LEN_MASK GENMASK(6, 0) -- --/* NPCM_PECI_PDDR - 0x2C : Command Register */ --#define NPCM_PECI_PDDR_MASK GENMASK(4, 0) -- --#define NPCM_PECI_INT_MASK (NPCM_PECI_CTRL_ABRT_ERR | \ -- NPCM_PECI_CTRL_CRC_ERR | \ -- NPCM_PECI_CTRL_DONE) -- --#define NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC 50000 --#define NPCM_PECI_IDLE_CHECK_INTERVAL_USEC 10000 --#define NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT 1000 --#define NPCM_PECI_CMD_TIMEOUT_MS_MAX 60000 --#define NPCM_PECI_HOST_NEG_BIT_RATE_MAX 31 --#define NPCM_PECI_HOST_NEG_BIT_RATE_MIN 7 --#define NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT 15 --#define NPCM_PECI_PULL_DOWN_DEFAULT 0 --#define NPCM_PECI_PULL_DOWN_MAX 2 -- --struct npcm_peci { -- u32 cmd_timeout_ms; -- u32 host_bit_rate; -- struct completion xfer_complete; -- struct regmap *gcr_regmap; -- struct peci_adapter *adapter; -- struct regmap *regmap; -- u32 status; -- spinlock_t lock; /* to sync completion status handling */ -- struct device *dev; -- struct clk *clk; -- int irq; --}; -- --static int npcm_peci_xfer_native(struct npcm_peci *priv, -- struct peci_xfer_msg *msg) --{ -- long err, timeout = msecs_to_jiffies(priv->cmd_timeout_ms); -- unsigned long flags; -- unsigned int msg_rd; -- u32 cmd_sts; -- int i, rc; -- -- /* Check command sts and bus idle state */ -- rc = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts, -- !(cmd_sts & NPCM_PECI_CTRL_START_BUSY), -- NPCM_PECI_IDLE_CHECK_INTERVAL_USEC, -- NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC); -- if (rc) -- return rc; /* -ETIMEDOUT */ -- -- spin_lock_irqsave(&priv->lock, flags); -- reinit_completion(&priv->xfer_complete); -- -- regmap_write(priv->regmap, NPCM_PECI_ADDR, msg->addr); -- regmap_write(priv->regmap, NPCM_PECI_RD_LENGTH, -- NPCM_PECI_WR_LEN_MASK & msg->rx_len); -- regmap_write(priv->regmap, NPCM_PECI_WR_LENGTH, -- NPCM_PECI_WR_LEN_MASK & msg->tx_len); -- -- if (msg->tx_len) { -- regmap_write(priv->regmap, NPCM_PECI_CMD, msg->tx_buf[0]); -- -- for (i = 0; i < (msg->tx_len - 1); i++) -- regmap_write(priv->regmap, NPCM_PECI_DAT_INOUT(i), -- msg->tx_buf[i + 1]); -- } -- -- priv->status = 0; -- regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS, -- NPCM_PECI_CTRL_START_BUSY, -- NPCM_PECI_CTRL_START_BUSY); -- -- spin_unlock_irqrestore(&priv->lock, flags); -- -- err = wait_for_completion_interruptible_timeout(&priv->xfer_complete, -- timeout); -- -- spin_lock_irqsave(&priv->lock, flags); -- -- regmap_write(priv->regmap, NPCM_PECI_CMD, 0); -- -- if (err <= 0 || priv->status != NPCM_PECI_CTRL_DONE) { -- if (err < 0) { /* -ERESTARTSYS */ -- rc = (int)err; -- goto err_irqrestore; -- } else if (err == 0) { -- dev_dbg(priv->dev, "Timeout waiting for a response!\n"); -- rc = -ETIMEDOUT; -- goto err_irqrestore; -- } -- -- dev_dbg(priv->dev, "No valid response!\n"); -- rc = -EIO; -- goto err_irqrestore; -- } -- -- for (i = 0; i < msg->rx_len; i++) { -- regmap_read(priv->regmap, NPCM_PECI_DAT_INOUT(i), &msg_rd); -- msg->rx_buf[i] = (u8)msg_rd; -- } -- --err_irqrestore: -- spin_unlock_irqrestore(&priv->lock, flags); -- return rc; --} -- --static irqreturn_t npcm_peci_irq_handler(int irq, void *arg) --{ -- struct npcm_peci *priv = arg; -- u32 status_ack = 0; -- u32 status; -- -- spin_lock(&priv->lock); -- regmap_read(priv->regmap, NPCM_PECI_CTL_STS, &status); -- priv->status |= (status & NPCM_PECI_INT_MASK); -- -- if (status & NPCM_PECI_CTRL_CRC_ERR) { -- dev_dbg(priv->dev, "PECI_INT_W_FCS_BAD\n"); -- status_ack |= NPCM_PECI_CTRL_CRC_ERR; -- } -- -- if (status & NPCM_PECI_CTRL_ABRT_ERR) { -- dev_dbg(priv->dev, "NPCM_PECI_CTRL_ABRT_ERR\n"); -- status_ack |= NPCM_PECI_CTRL_ABRT_ERR; -- } -- -- /* -- * All commands should be ended up with a NPCM_PECI_CTRL_DONE -- * bit set even in an error case. -- */ -- if (status & NPCM_PECI_CTRL_DONE) { -- dev_dbg(priv->dev, "NPCM_PECI_CTRL_DONE\n"); -- status_ack |= NPCM_PECI_CTRL_DONE; -- complete(&priv->xfer_complete); -- } -- -- regmap_write_bits(priv->regmap, NPCM_PECI_CTL_STS, -- NPCM_PECI_INT_MASK, status_ack); -- -- spin_unlock(&priv->lock); -- return IRQ_HANDLED; --} -- --static int npcm_peci_init_ctrl(struct npcm_peci *priv) --{ -- u32 cmd_sts, host_neg_bit_rate = 0, pull_down = 0; -- int ret; -- bool volt; -- -- priv->clk = devm_clk_get(priv->dev, NULL); -- if (IS_ERR(priv->clk)) { -- dev_err(priv->dev, "Failed to get clk source.\n"); -- return PTR_ERR(priv->clk); -- } -- -- ret = clk_prepare_enable(priv->clk); -- if (ret) { -- dev_err(priv->dev, "Failed to enable clock.\n"); -- return ret; -- } -- -- ret = of_property_read_u32(priv->dev->of_node, "cmd-timeout-ms", -- &priv->cmd_timeout_ms); -- if (ret || priv->cmd_timeout_ms > NPCM_PECI_CMD_TIMEOUT_MS_MAX || -- priv->cmd_timeout_ms == 0) { -- if (ret) -- dev_warn(priv->dev, -- "cmd-timeout-ms not found, use default : %u\n", -- NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT); -- else -- dev_warn(priv->dev, -- "Invalid cmd-timeout-ms : %u. Use default : %u\n", -- priv->cmd_timeout_ms, -- NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT); -- -- priv->cmd_timeout_ms = NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT; -- } -- -- if (of_device_is_compatible(priv->dev->of_node, -- "nuvoton,npcm750-peci")) { -- priv->gcr_regmap = syscon_regmap_lookup_by_compatible -- ("nuvoton,npcm750-gcr"); -- if (!IS_ERR(priv->gcr_regmap)) { -- volt = of_property_read_bool(priv->dev->of_node, -- "high-volt-range"); -- if (volt) -- regmap_update_bits(priv->gcr_regmap, -- NPCM7XX_INTCR3_OFFSET, -- NPCM7XX_INTCR3_PECIVSEL, -- NPCM7XX_INTCR3_PECIVSEL); -- else -- regmap_update_bits(priv->gcr_regmap, -- NPCM7XX_INTCR3_OFFSET, -- NPCM7XX_INTCR3_PECIVSEL, 0); -- } -- } -- -- ret = of_property_read_u32(priv->dev->of_node, "pull-down", -- &pull_down); -- if (ret || pull_down > NPCM_PECI_PULL_DOWN_MAX) { -- if (ret) -- dev_warn(priv->dev, -- "pull-down not found, use default : %u\n", -- NPCM_PECI_PULL_DOWN_DEFAULT); -- else -- dev_warn(priv->dev, -- "Invalid pull-down : %u. Use default : %u\n", -- pull_down, -- NPCM_PECI_PULL_DOWN_DEFAULT); -- pull_down = NPCM_PECI_PULL_DOWN_DEFAULT; -- } -- -- regmap_update_bits(priv->regmap, NPCM_PECI_CTL2, NPCM_PECI_CTL2_MASK, -- pull_down << 6); -- -- ret = of_property_read_u32(priv->dev->of_node, "host-neg-bit-rate", -- &host_neg_bit_rate); -- if (ret || host_neg_bit_rate > NPCM_PECI_HOST_NEG_BIT_RATE_MAX || -- host_neg_bit_rate < NPCM_PECI_HOST_NEG_BIT_RATE_MIN) { -- if (ret) -- dev_warn(priv->dev, -- "host-neg-bit-rate not found, use default : %u\n", -- NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT); -- else -- dev_warn(priv->dev, -- "Invalid host-neg-bit-rate : %u. Use default : %u\n", -- host_neg_bit_rate, -- NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT); -- host_neg_bit_rate = NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT; -- } -- -- regmap_update_bits(priv->regmap, NPCM_PECI_PDDR, NPCM_PECI_PDDR_MASK, -- host_neg_bit_rate); -- -- priv->host_bit_rate = clk_get_rate(priv->clk) / -- (4 * (host_neg_bit_rate + 1)); -- -- ret = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts, -- !(cmd_sts & NPCM_PECI_CTRL_START_BUSY), -- NPCM_PECI_IDLE_CHECK_INTERVAL_USEC, -- NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC); -- if (ret) -- return ret; /* -ETIMEDOUT */ -- -- /* PECI interrupt enable */ -- regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS, -- NPCM_PECI_CTRL_DONE_INT_EN, -- NPCM_PECI_CTRL_DONE_INT_EN); -- -- return 0; --} -- --static const struct regmap_config npcm_peci_regmap_config = { -- .reg_bits = 8, -- .val_bits = 8, -- .max_register = NPCM_PECI_MAX_REG, -- .fast_io = true, --}; -- --static int npcm_peci_xfer(struct peci_adapter *adapter, -- struct peci_xfer_msg *msg) --{ -- struct npcm_peci *priv = peci_get_adapdata(adapter); -- -- return npcm_peci_xfer_native(priv, msg); --} -- --static int npcm_peci_probe(struct platform_device *pdev) --{ -- struct peci_adapter *adapter; -- struct npcm_peci *priv; -- struct resource *res; -- void __iomem *base; -- int ret; -- -- adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv)); -- if (!adapter) -- return -ENOMEM; -- -- priv = peci_get_adapdata(adapter); -- priv->adapter = adapter; -- priv->dev = &pdev->dev; -- dev_set_drvdata(&pdev->dev, priv); -- -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- base = devm_ioremap_resource(&pdev->dev, res); -- if (IS_ERR(base)) { -- ret = PTR_ERR(base); -- goto err_put_adapter_dev; -- } -- -- priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, -- &npcm_peci_regmap_config); -- if (IS_ERR(priv->regmap)) { -- ret = PTR_ERR(priv->regmap); -- goto err_put_adapter_dev; -- } -- -- priv->irq = platform_get_irq(pdev, 0); -- if (!priv->irq) { -- ret = -ENODEV; -- goto err_put_adapter_dev; -- } -- -- ret = devm_request_irq(&pdev->dev, priv->irq, npcm_peci_irq_handler, -- 0, "peci-npcm-irq", priv); -- if (ret) -- goto err_put_adapter_dev; -- -- init_completion(&priv->xfer_complete); -- spin_lock_init(&priv->lock); -- -- priv->adapter->owner = THIS_MODULE; -- priv->adapter->dev.of_node = of_node_get(dev_of_node(priv->dev)); -- strlcpy(priv->adapter->name, pdev->name, sizeof(priv->adapter->name)); -- priv->adapter->xfer = npcm_peci_xfer; -- -- ret = npcm_peci_init_ctrl(priv); -- if (ret) -- goto err_put_adapter_dev; -- -- ret = peci_add_adapter(priv->adapter); -- if (ret) -- goto err_put_adapter_dev; -- -- dev_info(&pdev->dev, "peci bus %d registered, host negotiation bit rate %dHz", -- priv->adapter->nr, priv->host_bit_rate); -- -- return 0; -- --err_put_adapter_dev: -- put_device(&adapter->dev); -- return ret; --} -- --static int npcm_peci_remove(struct platform_device *pdev) --{ -- struct npcm_peci *priv = dev_get_drvdata(&pdev->dev); -- -- clk_disable_unprepare(priv->clk); -- peci_del_adapter(priv->adapter); -- of_node_put(priv->adapter->dev.of_node); -- -- return 0; --} -- --static const struct of_device_id npcm_peci_of_table[] = { -- { .compatible = "nuvoton,npcm750-peci", }, -- { } --}; --MODULE_DEVICE_TABLE(of, npcm_peci_of_table); -- --static struct platform_driver npcm_peci_driver = { -- .probe = npcm_peci_probe, -- .remove = npcm_peci_remove, -- .driver = { -- .name = "peci-npcm", -- .of_match_table = of_match_ptr(npcm_peci_of_table), -- }, --}; --module_platform_driver(npcm_peci_driver); -- --MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>"); --MODULE_DESCRIPTION("NPCM Platform Environment Control Interface (PECI) driver"); --MODULE_LICENSE("GPL v2"); -diff --git a/include/linux/mfd/intel-peci-client.h b/include/linux/mfd/intel-peci-client.h -index 8f6d823..9854303 100644 ---- a/include/linux/mfd/intel-peci-client.h -+++ b/include/linux/mfd/intel-peci-client.h -@@ -1,5 +1,5 @@ - /* SPDX-License-Identifier: GPL-2.0 */ --/* Copyright (c) 2018 Intel Corporation */ -+/* Copyright (c) 2018-2019 Intel Corporation */ - - #ifndef __LINUX_MFD_INTEL_PECI_CLIENT_H - #define __LINUX_MFD_INTEL_PECI_CLIENT_H -@@ -9,14 +9,15 @@ - #if IS_ENABLED(CONFIG_X86) - #include <asm/intel-family.h> - #else --/** -+/* - * Architectures other than x86 cannot include the header file so define these - * at here. These are needed for detecting type of client x86 CPUs behind a PECI - * connection. - */ --#define INTEL_FAM6_HASWELL_X 0x3F --#define INTEL_FAM6_BROADWELL_X 0x4F --#define INTEL_FAM6_SKYLAKE_X 0x55 -+#define INTEL_FAM6_HASWELL_X 0x3F -+#define INTEL_FAM6_BROADWELL_X 0x4F -+#define INTEL_FAM6_SKYLAKE_X 0x55 -+#define INTEL_FAM6_SKYLAKE_XD 0x56 - #endif - - #define CORE_MAX_ON_HSX 18 /* Max number of cores on Haswell */ -@@ -31,6 +32,10 @@ - #define CHAN_RANK_MAX_ON_SKX 6 /* Max number of channel ranks on Skylake */ - #define DIMM_IDX_MAX_ON_SKX 2 /* Max DIMM index per channel on Skylake */ - -+#define CORE_MAX_ON_SKXD 16 /* Max number of cores on Skylake D */ -+#define CHAN_RANK_MAX_ON_SKXD 2 /* Max number of channel ranks on Skylake D */ -+#define DIMM_IDX_MAX_ON_SKXD 2 /* Max DIMM index per channel on Skylake D */ -+ - #define CORE_NUMS_MAX CORE_MAX_ON_SKX - #define CHAN_RANK_MAX CHAN_RANK_MAX_ON_HSX - #define DIMM_IDX_MAX DIMM_IDX_MAX_ON_HSX -@@ -58,7 +63,6 @@ struct cpu_gen_info { - /** - * struct peci_client_manager - PECI client manager information - * @client; pointer to the PECI client -- * @dev: pointer to the struct device - * @name: PECI client manager name - * @gen_info: CPU generation info of the detected CPU - * -@@ -67,7 +71,6 @@ struct cpu_gen_info { - */ - struct peci_client_manager { - struct peci_client *client; -- struct device *dev; - char name[PECI_NAME_SIZE]; - const struct cpu_gen_info *gen_info; - }; -@@ -93,18 +96,22 @@ peci_client_read_package_config(struct peci_client_manager *priv, - u8 index, u16 param, u8 *data) - { - struct peci_rd_pkg_cfg_msg msg; -- int rc; -+ int ret; - - msg.addr = priv->client->addr; - msg.index = index; - msg.param = param; - msg.rx_len = 4; - -- rc = peci_command(priv->client->adapter, PECI_CMD_RD_PKG_CFG, &msg); -- if (!rc) -- memcpy(data, msg.pkg_config, 4); -+ ret = peci_command(priv->client->adapter, PECI_CMD_RD_PKG_CFG, &msg); -+ if (msg.cc != PECI_DEV_CC_SUCCESS) -+ ret = -EAGAIN; -+ if (ret) -+ return ret; -+ -+ memcpy(data, msg.pkg_config, 4); - -- return rc; -+ return 0; - } - - #endif /* __LINUX_MFD_INTEL_PECI_CLIENT_H */ -diff --git a/include/linux/peci.h b/include/linux/peci.h -index d0e47d4..6fc424d 100644 ---- a/include/linux/peci.h -+++ b/include/linux/peci.h -@@ -1,19 +1,18 @@ - /* SPDX-License-Identifier: GPL-2.0 */ --/* Copyright (c) 2018 Intel Corporation */ -+/* Copyright (c) 2018-2019 Intel Corporation */ - - #ifndef __LINUX_PECI_H - #define __LINUX_PECI_H - --#include <linux/cdev.h> - #include <linux/device.h> -+#include <linux/mutex.h> - #include <linux/peci-ioctl.h> --#include <linux/rtmutex.h> - - #define PECI_NAME_SIZE 32 - - struct peci_board_info { - char type[PECI_NAME_SIZE]; -- unsigned short addr; /* CPU client address */ -+ u8 addr; /* CPU client address */ - struct device_node *of_node; - }; - -@@ -22,29 +21,29 @@ struct peci_board_info { - * @owner: owner module of the PECI adpater - * @bus_lock: mutex for exclusion of multiple callers - * @dev: device interface to this driver -- * @cdev: character device object to create character device - * @nr: the bus number to map - * @name: name of the adapter - * @userspace_clients_lock: mutex for exclusion of clients handling - * @userspace_clients: list of registered clients - * @xfer: low-level transfer function pointer of the adapter - * @cmd_mask: mask for supportable PECI commands -+ * @use_dma: flag for indicating that adapter uses DMA - * - * Each PECI adapter can communicate with one or more PECI client children. - * These make a small bus, sharing a single wired PECI connection. - */ - struct peci_adapter { - struct module *owner; -- struct rt_mutex bus_lock; -+ struct mutex bus_lock; - struct device dev; -- struct cdev cdev; - int nr; - char name[PECI_NAME_SIZE]; - struct mutex userspace_clients_lock; /* clients list mutex */ - struct list_head userspace_clients; - int (*xfer)(struct peci_adapter *adapter, - struct peci_xfer_msg *msg); -- uint cmd_mask; -+ u32 cmd_mask; -+ bool use_dma; - }; - - static inline struct peci_adapter *to_peci_adapter(void *d) -@@ -87,8 +86,8 @@ static inline struct peci_client *to_peci_client(void *d) - } - - struct peci_device_id { -- char name[PECI_NAME_SIZE]; -- unsigned long driver_data; /* Data private to the driver */ -+ char name[PECI_NAME_SIZE]; -+ ulong driver_data; /* Data private to the driver */ - }; - - /** -@@ -129,13 +128,22 @@ static inline struct peci_driver *to_peci_driver(void *d) - /* use a define to avoid include chaining to get THIS_MODULE */ - #define peci_add_driver(driver) peci_register_driver(THIS_MODULE, driver) - -+extern struct bus_type peci_bus_type; -+extern struct device_type peci_adapter_type; -+extern struct device_type peci_client_type; -+ - int peci_register_driver(struct module *owner, struct peci_driver *drv); - void peci_del_driver(struct peci_driver *driver); - struct peci_client *peci_verify_client(struct device *dev); --struct peci_adapter *peci_alloc_adapter(struct device *dev, unsigned int size); -+struct peci_adapter *peci_alloc_adapter(struct device *dev, uint size); -+struct peci_adapter *peci_get_adapter(int nr); -+void peci_put_adapter(struct peci_adapter *adapter); - int peci_add_adapter(struct peci_adapter *adapter); - void peci_del_adapter(struct peci_adapter *adapter); - struct peci_adapter *peci_verify_adapter(struct device *dev); -+int peci_for_each_dev(void *data, int (*fn)(struct device *, void *)); -+struct peci_xfer_msg *peci_get_xfer_msg(u8 tx_len, u8 rx_len); -+void peci_put_xfer_msg(struct peci_xfer_msg *msg); - int peci_command(struct peci_adapter *adpater, enum peci_cmd cmd, void *vmsg); - int peci_get_cpu_id(struct peci_adapter *adapter, u8 addr, u32 *cpu_id); - -diff --git a/include/uapi/linux/peci-ioctl.h b/include/uapi/linux/peci-ioctl.h -index a6dae71..253fb42 100644 ---- a/include/uapi/linux/peci-ioctl.h -+++ b/include/uapi/linux/peci-ioctl.h -@@ -1,5 +1,5 @@ - /* SPDX-License-Identifier: GPL-2.0 */ --/* Copyright (c) 2018 Intel Corporation */ -+/* Copyright (c) 2018-2019 Intel Corporation */ - - #ifndef __PECI_IOCTL_H - #define __PECI_IOCTL_H -@@ -7,136 +7,35 @@ - #include <linux/ioctl.h> - #include <linux/types.h> - --/* Base Address of 48d */ --#define PECI_BASE_ADDR 0x30 /* The PECI client's default address of 0x30 */ --#define PECI_OFFSET_MAX 8 /* Max numver of CPU clients */ -- --/* PCI Access */ --#define MAX_PCI_READ_LEN 24 /* Number of bytes of the PCI Space read */ -- --#define PCI_BUS0_CPU0 0x00 --#define PCI_BUS0_CPU1 0x80 --#define PCI_CPUBUSNO_BUS 0x00 --#define PCI_CPUBUSNO_DEV 0x08 --#define PCI_CPUBUSNO_FUNC 0x02 --#define PCI_CPUBUSNO 0xcc --#define PCI_CPUBUSNO_1 0xd0 --#define PCI_CPUBUSNO_VALID 0xd4 -- --/* Package Identifier Read Parameter Value */ --#define PKG_ID_CPU_ID 0x0000 /* CPUID Info */ --#define PKG_ID_PLATFORM_ID 0x0001 /* Platform ID */ --#define PKG_ID_UNCORE_ID 0x0002 /* Uncore Device ID */ --#define PKG_ID_MAX_THREAD_ID 0x0003 /* Max Thread ID */ --#define PKG_ID_MICROCODE_REV 0x0004 /* CPU Microcode Update Revision */ --#define PKG_ID_MACHINE_CHECK_STATUS 0x0005 /* Machine Check Status */ -- --/* RdPkgConfig Index */ --#define MBX_INDEX_CPU_ID 0 /* Package Identifier Read */ --#define MBX_INDEX_VR_DEBUG 1 /* VR Debug */ --#define MBX_INDEX_PKG_TEMP_READ 2 /* Package Temperature Read */ --#define MBX_INDEX_ENERGY_COUNTER 3 /* Energy counter */ --#define MBX_INDEX_ENERGY_STATUS 4 /* DDR Energy Status */ --#define MBX_INDEX_WAKE_MODE_BIT 5 /* "Wake on PECI" Mode bit */ --#define MBX_INDEX_EPI 6 /* Efficient Performance Indication */ --#define MBX_INDEX_PKG_RAPL_PERF 8 /* Pkg RAPL Performance Status Read */ --#define MBX_INDEX_PER_CORE_DTS_TEMP 9 /* Per Core DTS Temperature Read */ --#define MBX_INDEX_DTS_MARGIN 10 /* DTS thermal margin */ --#define MBX_INDEX_SKT_PWR_THRTL_DUR 11 /* Socket Power Throttled Duration */ --#define MBX_INDEX_CFG_TDP_CONTROL 12 /* TDP Config Control */ --#define MBX_INDEX_CFG_TDP_LEVELS 13 /* TDP Config Levels */ --#define MBX_INDEX_DDR_DIMM_TEMP 14 /* DDR DIMM Temperature */ --#define MBX_INDEX_CFG_ICCMAX 15 /* Configurable ICCMAX */ --#define MBX_INDEX_TEMP_TARGET 16 /* Temperature Target Read */ --#define MBX_INDEX_CURR_CFG_LIMIT 17 /* Current Config Limit */ --#define MBX_INDEX_DIMM_TEMP_READ 20 /* Package Thermal Status Read */ --#define MBX_INDEX_DRAM_IMC_TMP_READ 22 /* DRAM IMC Temperature Read */ --#define MBX_INDEX_DDR_CH_THERM_STAT 23 /* DDR Channel Thermal Status */ --#define MBX_INDEX_PKG_POWER_LIMIT1 26 /* Package Power Limit1 */ --#define MBX_INDEX_PKG_POWER_LIMIT2 27 /* Package Power Limit2 */ --#define MBX_INDEX_TDP 28 /* Thermal design power minimum */ --#define MBX_INDEX_TDP_HIGH 29 /* Thermal design power maximum */ --#define MBX_INDEX_TDP_UNITS 30 /* Units for power/energy registers */ --#define MBX_INDEX_RUN_TIME 31 /* Accumulated Run Time */ --#define MBX_INDEX_CONSTRAINED_TIME 32 /* Thermally Constrained Time Read */ --#define MBX_INDEX_TURBO_RATIO 33 /* Turbo Activation Ratio */ --#define MBX_INDEX_DDR_RAPL_PL1 34 /* DDR RAPL PL1 */ --#define MBX_INDEX_DDR_PWR_INFO_HIGH 35 /* DRAM Power Info Read (high) */ --#define MBX_INDEX_DDR_PWR_INFO_LOW 36 /* DRAM Power Info Read (low) */ --#define MBX_INDEX_DDR_RAPL_PL2 37 /* DDR RAPL PL2 */ --#define MBX_INDEX_DDR_RAPL_STATUS 38 /* DDR RAPL Performance Status */ --#define MBX_INDEX_DDR_HOT_ABSOLUTE 43 /* DDR Hottest Dimm Absolute Temp */ --#define MBX_INDEX_DDR_HOT_RELATIVE 44 /* DDR Hottest Dimm Relative Temp */ --#define MBX_INDEX_DDR_THROTTLE_TIME 45 /* DDR Throttle Time */ --#define MBX_INDEX_DDR_THERM_STATUS 46 /* DDR Thermal Status */ --#define MBX_INDEX_TIME_AVG_TEMP 47 /* Package time-averaged temperature */ --#define MBX_INDEX_TURBO_RATIO_LIMIT 49 /* Turbo Ratio Limit Read */ --#define MBX_INDEX_HWP_AUTO_OOB 53 /* HWP Autonomous Out-of-band */ --#define MBX_INDEX_DDR_WARM_BUDGET 55 /* DDR Warm Power Budget */ --#define MBX_INDEX_DDR_HOT_BUDGET 56 /* DDR Hot Power Budget */ --#define MBX_INDEX_PKG_PSYS_PWR_LIM3 57 /* Package/Psys Power Limit3 */ --#define MBX_INDEX_PKG_PSYS_PWR_LIM1 58 /* Package/Psys Power Limit1 */ --#define MBX_INDEX_PKG_PSYS_PWR_LIM2 59 /* Package/Psys Power Limit2 */ --#define MBX_INDEX_PKG_PSYS_PWR_LIM4 60 /* Package/Psys Power Limit4 */ --#define MBX_INDEX_PERF_LIMIT_REASON 65 /* Performance Limit Reasons */ -- --/* WrPkgConfig Index */ --#define MBX_INDEX_DIMM_AMBIENT 19 --#define MBX_INDEX_DIMM_TEMP 24 -+/* The PECI client's default address of 0x30 */ -+#define PECI_BASE_ADDR 0x30 -+ -+/* Max number of CPU clients */ -+#define PECI_OFFSET_MAX 8 -+ -+/* PECI read/write data buffer size max */ -+#define PECI_BUFFER_SIZE 255 - - /* Device Specific Completion Code (CC) Definition */ --#define DEV_PECI_CC_SUCCESS 0x40 --#define DEV_PECI_CC_TIMEOUT 0x80 --#define DEV_PECI_CC_OUT_OF_RESOURCE 0x81 --#define DEV_PECI_CC_UNAVAIL_RESOURCE 0x82 --#define DEV_PECI_CC_INVALID_REQ 0x90 -+#define PECI_DEV_CC_SUCCESS 0x40 -+#define PECI_DEV_CC_NEED_RETRY 0x80 -+#define PECI_DEV_CC_OUT_OF_RESOURCE 0x81 -+#define PECI_DEV_CC_UNAVAIL_RESOURCE 0x82 -+#define PECI_DEV_CC_INVALID_REQ 0x90 -+#define PECI_DEV_CC_MCA_ERROR 0x91 -+#define PECI_DEV_CC_CATASTROPHIC_MCA_ERROR 0x93 -+#define PECI_DEV_CC_FATAL_MCA_DETECTED 0x94 -+#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB 0x98 -+#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB_IERR 0x9B -+#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB_MCA 0x9C - - /* Completion Code mask to check retry needs */ --#define DEV_PECI_CC_RETRY_CHECK_MASK 0xf0 --#define DEV_PECI_CC_NEED_RETRY 0x80 -+#define PECI_DEV_CC_RETRY_CHECK_MASK 0xf0 - - /* Skylake EDS says to retry for 250ms */ --#define DEV_PECI_RETRY_TIME_MS 250 --#define DEV_PECI_RETRY_INTERVAL_USEC 10000 --#define DEV_PECI_RETRY_BIT 0x01 -- --#define GET_TEMP_WR_LEN 1 --#define GET_TEMP_RD_LEN 2 --#define GET_TEMP_PECI_CMD 0x01 -- --#define GET_DIB_WR_LEN 1 --#define GET_DIB_RD_LEN 8 --#define GET_DIB_PECI_CMD 0xf7 -- --#define RDPKGCFG_WRITE_LEN 5 --#define RDPKGCFG_READ_LEN_BASE 1 --#define RDPKGCFG_PECI_CMD 0xa1 -- --#define WRPKGCFG_WRITE_LEN_BASE 6 --#define WRPKGCFG_READ_LEN 1 --#define WRPKGCFG_PECI_CMD 0xa5 -- --#define RDIAMSR_WRITE_LEN 5 --#define RDIAMSR_READ_LEN 9 --#define RDIAMSR_PECI_CMD 0xb1 -- --#define WRIAMSR_PECI_CMD 0xb5 -- --#define RDPCICFG_WRITE_LEN 6 --#define RDPCICFG_READ_LEN 5 --#define RDPCICFG_PECI_CMD 0x61 -- --#define WRPCICFG_PECI_CMD 0x65 -- --#define RDPCICFGLOCAL_WRITE_LEN 5 --#define RDPCICFGLOCAL_READ_LEN_BASE 1 --#define RDPCICFGLOCAL_PECI_CMD 0xe1 -- --#define WRPCICFGLOCAL_WRITE_LEN_BASE 6 --#define WRPCICFGLOCAL_READ_LEN 1 --#define WRPCICFGLOCAL_PECI_CMD 0xe5 -- --#define PECI_BUFFER_SIZE 32 -+#define PECI_DEV_RETRY_TIME_MS 700 -+#define PECI_DEV_RETRY_INTERVAL_USEC 10000 -+#define PECI_DEV_RETRY_BIT 0x01 - - /** - * enum peci_cmd - PECI client commands -@@ -186,11 +85,12 @@ enum peci_cmd { - * raw PECI transfer - */ - struct peci_xfer_msg { -- __u8 addr; -- __u8 tx_len; -- __u8 rx_len; -- __u8 tx_buf[PECI_BUFFER_SIZE]; -- __u8 rx_buf[PECI_BUFFER_SIZE]; -+ __u8 addr; -+ __u8 tx_len; -+ __u8 rx_len; -+ __u8 padding; -+ __u8 *tx_buf; -+ __u8 *rx_buf; - } __attribute__((__packed__)); - - /** -@@ -202,7 +102,8 @@ struct peci_xfer_msg { - * powered-off, etc. - */ - struct peci_ping_msg { -- __u8 addr; -+ __u8 addr; -+ __u8 padding[3]; - } __attribute__((__packed__)); - - /** -@@ -216,8 +117,13 @@ struct peci_ping_msg { - * command. - */ - struct peci_get_dib_msg { -- __u8 addr; -- __u64 dib; -+#define PECI_GET_DIB_WR_LEN 1 -+#define PECI_GET_DIB_RD_LEN 8 -+#define PECI_GET_DIB_CMD 0xf7 -+ -+ __u8 addr; -+ __u8 padding[3]; -+ __u64 dib; - } __attribute__((__packed__)); - - /** -@@ -232,8 +138,13 @@ struct peci_get_dib_msg { - * below the maximum processor junction temperature. - */ - struct peci_get_temp_msg { -- __u8 addr; -- __s16 temp_raw; -+#define PECI_GET_TEMP_WR_LEN 1 -+#define PECI_GET_TEMP_RD_LEN 2 -+#define PECI_GET_TEMP_CMD 0x01 -+ -+ __u8 addr; -+ __u8 padding; -+ __s16 temp_raw; - } __attribute__((__packed__)); - - /** -@@ -242,6 +153,7 @@ struct peci_get_temp_msg { - * @index: encoding index for the requested service - * @param: specific data being requested - * @rx_len: number of data to be read in bytes -+ * @cc: completion code - * @pkg_config: package config data to be read - * - * The RdPkgConfig() command provides read access to the Package Configuration -@@ -251,11 +163,73 @@ struct peci_get_temp_msg { - * DIMM temperatures and so on. - */ - struct peci_rd_pkg_cfg_msg { -- __u8 addr; -- __u8 index; -- __u16 param; -- __u8 rx_len; -- __u8 pkg_config[4]; -+#define PECI_RDPKGCFG_WRITE_LEN 5 -+#define PECI_RDPKGCFG_READ_LEN_BASE 1 -+#define PECI_RDPKGCFG_CMD 0xa1 -+ -+ __u8 addr; -+ __u8 index; -+#define PECI_MBX_INDEX_CPU_ID 0 /* Package Identifier Read */ -+#define PECI_MBX_INDEX_VR_DEBUG 1 /* VR Debug */ -+#define PECI_MBX_INDEX_PKG_TEMP_READ 2 /* Package Temperature Read */ -+#define PECI_MBX_INDEX_ENERGY_COUNTER 3 /* Energy counter */ -+#define PECI_MBX_INDEX_ENERGY_STATUS 4 /* DDR Energy Status */ -+#define PECI_MBX_INDEX_WAKE_MODE_BIT 5 /* "Wake on PECI" Mode bit */ -+#define PECI_MBX_INDEX_EPI 6 /* Efficient Performance Indication */ -+#define PECI_MBX_INDEX_PKG_RAPL_PERF 8 /* Pkg RAPL Performance Status Read */ -+#define PECI_MBX_INDEX_PER_CORE_DTS_TEMP 9 /* Per Core DTS Temperature Read */ -+#define PECI_MBX_INDEX_DTS_MARGIN 10 /* DTS thermal margin */ -+#define PECI_MBX_INDEX_SKT_PWR_THRTL_DUR 11 /* Socket Power Throttled Duration */ -+#define PECI_MBX_INDEX_CFG_TDP_CONTROL 12 /* TDP Config Control */ -+#define PECI_MBX_INDEX_CFG_TDP_LEVELS 13 /* TDP Config Levels */ -+#define PECI_MBX_INDEX_DDR_DIMM_TEMP 14 /* DDR DIMM Temperature */ -+#define PECI_MBX_INDEX_CFG_ICCMAX 15 /* Configurable ICCMAX */ -+#define PECI_MBX_INDEX_TEMP_TARGET 16 /* Temperature Target Read */ -+#define PECI_MBX_INDEX_CURR_CFG_LIMIT 17 /* Current Config Limit */ -+#define PECI_MBX_INDEX_DIMM_TEMP_READ 20 /* Package Thermal Status Read */ -+#define PECI_MBX_INDEX_DRAM_IMC_TMP_READ 22 /* DRAM IMC Temperature Read */ -+#define PECI_MBX_INDEX_DDR_CH_THERM_STAT 23 /* DDR Channel Thermal Status */ -+#define PECI_MBX_INDEX_PKG_POWER_LIMIT1 26 /* Package Power Limit1 */ -+#define PECI_MBX_INDEX_PKG_POWER_LIMIT2 27 /* Package Power Limit2 */ -+#define PECI_MBX_INDEX_TDP 28 /* Thermal design power minimum */ -+#define PECI_MBX_INDEX_TDP_HIGH 29 /* Thermal design power maximum */ -+#define PECI_MBX_INDEX_TDP_UNITS 30 /* Units for power/energy registers */ -+#define PECI_MBX_INDEX_RUN_TIME 31 /* Accumulated Run Time */ -+#define PECI_MBX_INDEX_CONSTRAINED_TIME 32 /* Thermally Constrained Time Read */ -+#define PECI_MBX_INDEX_TURBO_RATIO 33 /* Turbo Activation Ratio */ -+#define PECI_MBX_INDEX_DDR_RAPL_PL1 34 /* DDR RAPL PL1 */ -+#define PECI_MBX_INDEX_DDR_PWR_INFO_HIGH 35 /* DRAM Power Info Read (high) */ -+#define PECI_MBX_INDEX_DDR_PWR_INFO_LOW 36 /* DRAM Power Info Read (low) */ -+#define PECI_MBX_INDEX_DDR_RAPL_PL2 37 /* DDR RAPL PL2 */ -+#define PECI_MBX_INDEX_DDR_RAPL_STATUS 38 /* DDR RAPL Performance Status */ -+#define PECI_MBX_INDEX_DDR_HOT_ABSOLUTE 43 /* DDR Hottest Dimm Absolute Temp */ -+#define PECI_MBX_INDEX_DDR_HOT_RELATIVE 44 /* DDR Hottest Dimm Relative Temp */ -+#define PECI_MBX_INDEX_DDR_THROTTLE_TIME 45 /* DDR Throttle Time */ -+#define PECI_MBX_INDEX_DDR_THERM_STATUS 46 /* DDR Thermal Status */ -+#define PECI_MBX_INDEX_TIME_AVG_TEMP 47 /* Package time-averaged temperature */ -+#define PECI_MBX_INDEX_TURBO_RATIO_LIMIT 49 /* Turbo Ratio Limit Read */ -+#define PECI_MBX_INDEX_HWP_AUTO_OOB 53 /* HWP Autonomous Out-of-band */ -+#define PECI_MBX_INDEX_DDR_WARM_BUDGET 55 /* DDR Warm Power Budget */ -+#define PECI_MBX_INDEX_DDR_HOT_BUDGET 56 /* DDR Hot Power Budget */ -+#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM3 57 /* Package/Psys Power Limit3 */ -+#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM1 58 /* Package/Psys Power Limit1 */ -+#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM2 59 /* Package/Psys Power Limit2 */ -+#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM4 60 /* Package/Psys Power Limit4 */ -+#define PECI_MBX_INDEX_PERF_LIMIT_REASON 65 /* Performance Limit Reasons */ -+ -+ __u16 param; -+/* When index is PECI_MBX_INDEX_CPU_ID */ -+#define PECI_PKG_ID_CPU_ID 0x0000 /* CPUID Info */ -+#define PECI_PKG_ID_PLATFORM_ID 0x0001 /* Platform ID */ -+#define PECI_PKG_ID_UNCORE_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_MACHINE_CHECK_STATUS 0x0005 /* Machine Check Status */ -+ -+ __u8 rx_len; -+ __u8 cc; -+ __u8 padding[2]; -+ __u8 pkg_config[4]; - } __attribute__((__packed__)); - - /** -@@ -264,6 +238,7 @@ struct peci_rd_pkg_cfg_msg { - * @index: encoding index for the requested service - * @param: specific data being requested - * @tx_len: number of data to be written in bytes -+ * @cc: completion code - * @value: package config data to be written - * - * The WrPkgConfig() command provides write access to the Package Configuration -@@ -272,11 +247,20 @@ struct peci_rd_pkg_cfg_msg { - * may include power limiting, thermal averaging constant programming and so on. - */ - struct peci_wr_pkg_cfg_msg { -- __u8 addr; -- __u8 index; -- __u16 param; -- __u8 tx_len; -- __u32 value; -+#define PECI_WRPKGCFG_WRITE_LEN_BASE 6 -+#define PECI_WRPKGCFG_READ_LEN 1 -+#define PECI_WRPKGCFG_CMD 0xa5 -+ -+ __u8 addr; -+ __u8 index; -+#define PECI_MBX_INDEX_DIMM_AMBIENT 19 -+#define PECI_MBX_INDEX_DIMM_TEMP 24 -+ -+ __u16 param; -+ __u8 tx_len; -+ __u8 cc; -+ __u8 padding[2]; -+ __u32 value; - } __attribute__((__packed__)); - - /** -@@ -284,16 +268,47 @@ struct peci_wr_pkg_cfg_msg { - * @addr: address of the client - * @thread_id: ID of the specific logical processor - * @address: address of MSR to read from -+ * @cc: completion code - * @value: data to be read - * - * The RdIAMSR() PECI command provides read access to Model Specific Registers - * (MSRs) defined in the processor's Intel Architecture (IA). - */ - struct peci_rd_ia_msr_msg { -- __u8 addr; -- __u8 thread_id; -- __u16 address; -- __u64 value; -+#define PECI_RDIAMSR_WRITE_LEN 5 -+#define PECI_RDIAMSR_READ_LEN 9 -+#define PECI_RDIAMSR_CMD 0xb1 -+ -+ __u8 addr; -+ __u8 thread_id; -+ __u16 address; -+ __u8 cc; -+ __u8 padding[3]; -+ __u64 value; -+} __attribute__((__packed__)); -+ -+/** -+ * struct peci_wr_ia_msr_msg - WrIAMSR command -+ * @addr: address of the client -+ * @thread_id: ID of the specific logical processor -+ * @address: address of MSR to write to -+ * @tx_len: number of data to be written in bytes -+ * @cc: completion code -+ * @value: data to be written -+ * -+ * The WrIAMSR() PECI command provides write access to Model Specific Registers -+ * (MSRs) defined in the processor's Intel Architecture (IA). -+ */ -+struct peci_wr_ia_msr_msg { -+#define PECI_WRIAMSR_CMD 0xb5 -+ -+ __u8 addr; -+ __u8 thread_id; -+ __u16 address; -+ __u8 tx_len; -+ __u8 cc; -+ __u8 padding[2]; -+ __u64 value; - } __attribute__((__packed__)); - - /** -@@ -303,6 +318,7 @@ struct peci_rd_ia_msr_msg { - * @device: PCI device number - * @function: specific function to read from - * @reg: specific register to read from -+ * @cc: completion code - * @pci_config: config data to be read - * - * The RdPCIConfig() command provides sideband read access to the PCI -@@ -310,12 +326,56 @@ struct peci_rd_ia_msr_msg { - * processor. - */ - struct peci_rd_pci_cfg_msg { -- __u8 addr; -- __u8 bus; -- __u8 device; -- __u8 function; -- __u16 reg; -- __u8 pci_config[4]; -+#define PECI_RDPCICFG_WRITE_LEN 6 -+#define PECI_RDPCICFG_READ_LEN 5 -+#define PECI_RDPCICFG_READ_LEN_MAX 24 -+#define PECI_RDPCICFG_CMD 0x61 -+ -+ __u8 addr; -+ __u8 bus; -+#define PECI_PCI_BUS0_CPU0 0x00 -+#define PECI_PCI_BUS0_CPU1 0x80 -+#define PECI_PCI_CPUBUSNO_BUS 0x00 -+#define PECI_PCI_CPUBUSNO_DEV 0x08 -+#define PECI_PCI_CPUBUSNO_FUNC 0x02 -+#define PECI_PCI_CPUBUSNO 0xcc -+#define PECI_PCI_CPUBUSNO_1 0xd0 -+#define PECI_PCI_CPUBUSNO_VALID 0xd4 -+ -+ __u8 device; -+ __u8 function; -+ __u16 reg; -+ __u8 cc; -+ __u8 padding[1]; -+ __u8 pci_config[4]; -+} __attribute__((__packed__)); -+ -+/** -+ * struct peci_wr_pci_cfg_msg - WrPCIConfig command -+ * @addr: address of the client -+ * @bus: PCI bus number -+ * @device: PCI device number -+ * @function: specific function to write to -+ * @reg: specific register to write to -+ * @tx_len: number of data to be written in bytes -+ * @cc: completion code -+ * @pci_config: config data to be written -+ * -+ * The RdPCIConfig() command provides sideband write access to the PCI -+ * configuration space maintained in downstream devices external to the -+ * processor. -+ */ -+struct peci_wr_pci_cfg_msg { -+#define PECI_WRPCICFG_CMD 0x65 -+ -+ __u8 addr; -+ __u8 bus; -+ __u8 device; -+ __u8 function; -+ __u16 reg; -+ __u8 tx_len; -+ __u8 cc; -+ __u8 pci_config[4]; - } __attribute__((__packed__)); - - /** -@@ -326,6 +386,7 @@ struct peci_rd_pci_cfg_msg { - * @function: specific function to read from - * @reg: specific register to read from - * @rx_len: number of data to be read in bytes -+ * @cc: completion code - * @pci_config: config data to be read - * - * The RdPCIConfigLocal() command provides sideband read access to the PCI -@@ -333,13 +394,18 @@ struct peci_rd_pci_cfg_msg { - * processor IIO and uncore registers within the PCI configuration space. - */ - struct peci_rd_pci_cfg_local_msg { -- __u8 addr; -- __u8 bus; -- __u8 device; -- __u8 function; -- __u16 reg; -- __u8 rx_len; -- __u8 pci_config[4]; -+#define PECI_RDPCICFGLOCAL_WRITE_LEN 5 -+#define PECI_RDPCICFGLOCAL_READ_LEN_BASE 1 -+#define PECI_RDPCICFGLOCAL_CMD 0xe1 -+ -+ __u8 addr; -+ __u8 bus; -+ __u8 device; -+ __u8 function; -+ __u16 reg; -+ __u8 rx_len; -+ __u8 cc; -+ __u8 pci_config[4]; - } __attribute__((__packed__)); - - /** -@@ -350,6 +416,7 @@ struct peci_rd_pci_cfg_local_msg { - * @function: specific function to read from - * @reg: specific register to read from - * @tx_len: number of data to be written in bytes -+ * @cc: completion code - * @value: config data to be written - * - * The WrPCIConfigLocal() command provides sideband write access to the PCI -@@ -357,13 +424,18 @@ struct peci_rd_pci_cfg_local_msg { - * access this space even before BIOS enumeration of the system buses. - */ - struct peci_wr_pci_cfg_local_msg { -- __u8 addr; -- __u8 bus; -- __u8 device; -- __u8 function; -- __u16 reg; -- __u8 tx_len; -- __u32 value; -+#define PECI_WRPCICFGLOCAL_WRITE_LEN_BASE 6 -+#define PECI_WRPCICFGLOCAL_READ_LEN 1 -+#define PECI_WRPCICFGLOCAL_CMD 0xe5 -+ -+ __u8 addr; -+ __u8 bus; -+ __u8 device; -+ __u8 function; -+ __u16 reg; -+ __u8 tx_len; -+ __u8 cc; -+ __u32 value; - } __attribute__((__packed__)); - - #define PECI_IOC_BASE 0xb7 -@@ -389,9 +461,15 @@ struct peci_wr_pci_cfg_local_msg { - #define PECI_IOC_RD_IA_MSR \ - _IOWR(PECI_IOC_BASE, PECI_CMD_RD_IA_MSR, struct peci_rd_ia_msr_msg) - -+#define PECI_IOC_WR_IA_MSR \ -+ _IOWR(PECI_IOC_BASE, PECI_CMD_WR_IA_MSR, struct peci_wr_ia_msr_msg) -+ - #define PECI_IOC_RD_PCI_CFG \ - _IOWR(PECI_IOC_BASE, PECI_CMD_RD_PCI_CFG, struct peci_rd_pci_cfg_msg) - -+#define PECI_IOC_WR_PCI_CFG \ -+ _IOWR(PECI_IOC_BASE, PECI_CMD_WR_PCI_CFG, struct peci_wr_pci_cfg_msg) -+ - #define PECI_IOC_RD_PCI_CFG_LOCAL \ - _IOWR(PECI_IOC_BASE, PECI_CMD_RD_PCI_CFG_LOCAL, \ - struct peci_rd_pci_cfg_local_msg) --- -2.7.4 - |