diff mbox series

peci: Set "Wake On PECI" mode when required

Message ID e6f4ab29854ac58a878189c1edece4e8eed2e7fd.camel@yadro.com
State New
Headers show
Series peci: Set "Wake On PECI" mode when required | expand

Commit Message

Andrei Kartashev Oct. 21, 2020, 12:25 p.m. UTC
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@yadro.com>
---
 drivers/peci/peci-core.c | 88 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 85 insertions(+), 3 deletions(-)
diff mbox series

Patch

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];