[PATCH] peci: Set "Wake On PECI" mode when required

Andrei Kartashev a.kartashev at yadro.com
Wed Oct 21 23:25:26 AEDT 2020


RdPCIConfigLocal(), WrPCIConfigLocal(), and RdPCIConfig() PECI commands
can return "hardware resources are in a low power state". This case
retrying likely will also fail since wakeup is required.
Enable "Wake On PECI" mode before retry if processor in low power
state.

Tested: run RdPCIConfigLocal requests and control that there in no more
timeouts when processor is in low power state. There is no measurable
impact on request processing time between request succeeded from first
try before patch and request with wakeup.

Signed-off-by: Andrei Kartashev <a.kartashev at yadro.com>
---
 drivers/peci/peci-core.c | 88 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 85 insertions(+), 3 deletions(-)

diff --git a/drivers/peci/peci-core.c b/drivers/peci/peci-core.c
index ba561bf810f9..dbd33e0e3a1c 100644
--- a/drivers/peci/peci-core.c
+++ b/drivers/peci/peci-core.c
@@ -237,6 +237,10 @@ static int __peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg,
 		    PECI_DEV_CC_NEED_RETRY)
 			break;
 
+		/* Wakeup is needed when completion code is 0x82 */
+		if (msg->rx_buf[0] == PECI_DEV_CC_UNAVAIL_RESOURCE)
+			break;
+
 		/* Set the retry bit to indicate a retry attempt */
 		msg->tx_buf[1] |= PECI_DEV_RETRY_BIT;
 
@@ -285,6 +289,84 @@ static int peci_xfer_with_retries(struct peci_adapter *adapter,
 	return __peci_xfer(adapter, msg, true, has_aw_fcs);
 }
 
+static int peci_xfer_with_wakeup(struct peci_adapter *adapter,
+				  struct peci_xfer_msg *msg,
+				  bool has_aw_fcs)
+{
+	struct peci_xfer_msg *wmsg = NULL;
+	u8 aw_fcs;
+	int ret;
+	int ret_tmp;
+
+	ret = __peci_xfer(adapter, msg, true, has_aw_fcs);
+
+	/* Wakeup is needed when completion code is 0x82 */
+	if (msg->rx_buf[0] == PECI_DEV_CC_UNAVAIL_RESOURCE) {
+		wmsg = peci_get_xfer_msg(PECI_WRPKGCFG_WRITE_LEN_BASE + 4,
+					PECI_WRPKGCFG_READ_LEN);
+		if (!wmsg)
+			return -ENOMEM;
+
+		wmsg->addr = msg->addr;
+		wmsg->tx_buf[0] = PECI_WRPKGCFG_CMD;
+		wmsg->tx_buf[1] = 0;  /* request byte for Host ID | Retry bit */
+				      /* Host ID is 0 for PECI 3.0 */
+		/* RdPkgConfig index */
+		wmsg->tx_buf[2] = PECI_MBX_INDEX_WAKE_MODE_BIT;
+		wmsg->tx_buf[3] = 1;  /* LSB - Config parameter */
+		wmsg->tx_buf[4] = 0;  /* MSB - Config parameter */
+		wmsg->tx_buf[5] = 0;  /* Data */
+		wmsg->tx_buf[6] = 0;  /* Data */
+		wmsg->tx_buf[7] = 0;  /* Data */
+		wmsg->tx_buf[8] = 0;  /* Data */
+
+		/* Add an Assured Write Frame Check Sequence byte */
+		ret_tmp = peci_aw_fcs(wmsg, 8 + 4, &aw_fcs);
+		if (ret_tmp) {
+			ret = ret_tmp;
+			goto out;
+		}
+
+		wmsg->tx_buf[9] = 0x80 ^ aw_fcs;
+
+		ret_tmp = __peci_xfer(adapter, wmsg, true, true);
+		if (ret_tmp) {
+			ret = ret_tmp;
+			goto out;
+		}
+
+		/* Resend command */
+		ret = __peci_xfer(adapter, msg, true, has_aw_fcs);
+
+		/*
+		 * Assume that if we got CC 0x82 then “Wake on PECI” mode
+		 * bit was not set, so no need to read and remember it
+		 */
+		wmsg->tx_buf[3] = 0;    /* LSB - Config parameter */
+		/* Recalculate an Assured Write Frame Check Sequence byte */
+		ret_tmp = peci_aw_fcs(wmsg, 8 + 4, &aw_fcs);
+		if (ret_tmp) {
+			if (ret == 0)
+				ret = ret_tmp;
+			goto out;
+		}
+
+		wmsg->tx_buf[9] = 0x80 ^ aw_fcs;
+
+		ret_tmp = __peci_xfer(adapter, wmsg, true, true);
+		if (ret_tmp) {
+			if (ret == 0)
+				ret = ret_tmp;
+			goto out;
+		}
+	}
+
+out:
+	if (wmsg)
+		peci_put_xfer_msg(wmsg);
+	return ret;
+}
+
 static int peci_scan_cmd_mask(struct peci_adapter *adapter)
 {
 	struct peci_xfer_msg *msg;
@@ -658,7 +740,7 @@ static int peci_cmd_rd_pci_cfg(struct peci_adapter *adapter, void *vmsg)
 	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);
+	ret = peci_xfer_with_wakeup(adapter, msg, false);
 	if (!ret)
 		memcpy(umsg->pci_config, &msg->rx_buf[1], 4);
 
@@ -706,7 +788,7 @@ static int peci_cmd_rd_pci_cfg_local(struct peci_adapter *adapter, void *vmsg)
 	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);
+	ret = peci_xfer_with_wakeup(adapter, msg, false);
 	if (!ret)
 		memcpy(umsg->pci_config, &msg->rx_buf[1], umsg->rx_len);
 
@@ -758,7 +840,7 @@ static int peci_cmd_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg)
 
 	msg->tx_buf[5 + i] = 0x80 ^ aw_fcs;
 
-	ret = peci_xfer_with_retries(adapter, msg, true);
+	ret = peci_xfer_with_wakeup(adapter, msg, true);
 
 out:
 	umsg->cc = msg->rx_buf[0];
-- 
2.26.2



More information about the openbmc mailing list