[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