[Skiboot] [PATCH v2 16/31] libstb/drivers/tpm_i2c_nuvoton.c: read FIFO

Claudio Carvalho cclaudio at linux.vnet.ibm.com
Wed Sep 28 18:01:15 AEST 2016


This adds the 4/5 step performed by the TPM I2C Nuvoton driver to
transmit a command to the TPM device. In this step the driver
reads from the I2C master FIFO the result that the TPM device returned
for the last command sent.

Signed-off-by: Claudio Carvalho <cclaudio at linux.vnet.ibm.com>
---
 libstb/drivers/tpm_i2c_nuvoton.c | 122 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 122 insertions(+)

diff --git a/libstb/drivers/tpm_i2c_nuvoton.c b/libstb/drivers/tpm_i2c_nuvoton.c
index 91e5a1d..3a6bf04 100644
--- a/libstb/drivers/tpm_i2c_nuvoton.c
+++ b/libstb/drivers/tpm_i2c_nuvoton.c
@@ -34,6 +34,7 @@
  * as defined in the TCG PC Client Platform TPM Profile specification, Revision
  * 00.43.
  */
+#define TCG_PTP_TIMEOUT_A	750
 #define TCG_PTP_TIMEOUT_B	2000
 #define TCG_PTP_TIMEOUT_D	30
 
@@ -41,13 +42,16 @@
 #define NUVOTON_TPM_STS			0x00
 #define NUVOTON_TPM_BURST_COUNT		0x01
 #define NUVOTON_TPM_DATA_FIFO_W		0x20
+#define NUVOTON_TPM_DATA_FIFO_R		0x40
 
 /* Bit masks for the TPM STATUS register */
 #define TCG_PTP_STS_VALID		0x80
 #define TCG_PTP_STS_COMMAND_READY	0x40
 #define TCG_PTP_STS_GO			0x20
+#define TCG_PTP_STS_DATA_AVAIL		0x10
 #define TCG_PTP_STS_EXPECT		0x08
 
+
 /* TPM Driver values */
 #define MAX_STSVALID_POLLS 	5   /* Max poll of 50ms (5*10ms) */
 #define TPM_TIMEOUT_INTERVAL	10
@@ -144,6 +148,43 @@ static bool tpm_is_expecting(int* rc)
 	return false;
 }
 
+static bool tpm_is_data_avail(int* rc)
+{
+	uint8_t value = 0;
+
+	*rc = tpm_read_sts_reg_valid(&value);
+
+	if (*rc == 0 && (( value &
+			   TCG_PTP_STS_DATA_AVAIL) == TCG_PTP_STS_DATA_AVAIL))
+		return true;
+
+	return false;
+}
+
+static int tpm_poll_for_data_avail(void)
+{
+	int delay, rc;
+
+	for (delay = 0; delay < TCG_PTP_TIMEOUT_A;
+	     delay += TPM_TIMEOUT_INTERVAL) {
+		if (tpm_is_data_avail(&rc)) {
+			DBG("---- read FIFO. Data available. delay=%d/%d\n",
+			    delay, TCG_PTP_TIMEOUT_A);
+			return rc;
+		}
+		time_wait_ms(TPM_TIMEOUT_INTERVAL);
+	}
+	/**
+	 * @fwts-label TPMDataAvailBitTimeout
+	 * @fwts-advice The data avail bit of the tpm status register is taking
+	 * longer to be settled. Either the wait time need to be increased or
+	 * the TPM device is not functional.
+	 */
+	prlog(PR_ERR, "TPM: read FIFO. Polling timeout, delay=%d/%d\n",
+	      delay, TCG_PTP_TIMEOUT_A);
+	return STB_TPM_TIMEOUT;
+}
+
 static int tpm_read_burst_count(uint8_t* burst_count)
 {
 	int rc = 0;
@@ -273,6 +314,82 @@ static int tpm_write_fifo(uint8_t* buf, size_t buflen)
 	return rc;
 }
 
+static int tpm_read_fifo(uint8_t* buf, size_t* buflen)
+{
+	int rc;
+	uint8_t burst_count;
+	int delay = 0;
+	size_t curByte = 0;
+	uint8_t* bytePtr = (uint8_t*)buf;
+	uint8_t* curBytePtr = NULL;
+
+	rc = tpm_poll_for_data_avail();
+
+	if (rc == 0) {
+		do {
+			rc = tpm_read_burst_count(&burst_count);
+			if (rc < 0) {
+				break;
+			} else if (burst_count == 0) {
+				/* Need to delay to allow the TPM time */
+				time_wait_ms(TPM_TIMEOUT_INTERVAL);
+				delay += TPM_TIMEOUT_INTERVAL;
+				continue;
+			}
+			/* Buffer overflow check */
+			if (curByte + burst_count > *buflen)
+			{
+				 /**
+				 * @fwts-label TPMReadFifoOverflow1
+				 * @fwts-advice The read from TPM FIFO overflowed. It is
+				 * expecting more data even though we think we are done.
+				 * This indicates a bug in the TPM device driver.
+				 */
+				prlog(PR_ERR, "TPM: read FIFO overflow1. delay %d/%d\n",
+				      delay, TCG_PTP_TIMEOUT_D);
+				rc = STB_TPM_OVERFLOW;
+			}
+			/*
+			 *  Read some data
+			 */
+			curBytePtr = &(bytePtr[curByte]);
+			rc = tpm_i2c_request_send(tpm_device->bus_id,
+						  tpm_device->xscom_base,
+						  SMBUS_READ,
+						  NUVOTON_TPM_DATA_FIFO_R, 1,
+						  curBytePtr, burst_count);
+			curByte += burst_count;
+			DBG("%s read FIFO. received %zd bytes. burstcount"
+			    " polling delay=%d/%d, rc=%d\n",
+			    (rc) ? "!!!!" : "----", curByte, delay,
+			    TCG_PTP_TIMEOUT_D, rc);
+			delay = 0;
+			if (rc < 0)
+				break;
+			if (!tpm_is_data_avail(&rc))
+				break;
+		} while (delay < TCG_PTP_TIMEOUT_D);
+	}
+
+	if (rc == 0 && delay >= TCG_PTP_TIMEOUT_D) {
+		/**
+		 * @fwts-label TPMReadBurstcountBitTimeout
+		 * @fwts-advice The burstcount bit of the tpm status register is
+		 * taking longer to be settled. Either the wait time needs to be
+		 * increased or the TPM device is not functional.
+		 */
+		prlog(PR_ERR, "TPM: read FIFO, burstcount polling timeout."
+			  " delay=%d/%d\n",
+			  delay, TCG_PTP_TIMEOUT_D);
+		return STB_TPM_TIMEOUT;
+	}
+	if (rc == 0)
+		*buflen = curByte;
+	else
+		*buflen = 0;
+	return rc;
+}
+
 static int tpm_transmit(struct tpm_dev *dev, uint8_t* buf, size_t cmdlen,
 			size_t* buflen)
 {
@@ -311,6 +428,11 @@ static int tpm_transmit(struct tpm_dev *dev, uint8_t* buf, size_t cmdlen,
 	if (rc < 0)
 		goto out;
 
+	DBG("step 4/5: read FIFO\n");
+	rc = tpm_read_fifo(buf, buflen);
+	if (rc < 0)
+		goto out;
+
 out:
 	DBG("**** tpm_transmit %s, rc=%d ****\n",
 	    (rc) ? "ERROR" : "SUCCESS", rc);
-- 
1.9.1



More information about the Skiboot mailing list