summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2016-09-22 18:52:47 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-09-26 22:16:45 -0700
commit5a6bb19a889f5b7fa5f4b590aba5893bee9d5452 (patch)
treeadac78be67c57bcde092587fc2ade2d57ca6f5fc
parent75aaabcd9ade5d2a2ad068d2543e8e82011b979f (diff)
downloadchrome-ec-5a6bb19a889f5b7fa5f4b590aba5893bee9d5452.tar.gz
tpm: reset communications channels when resetting TPM
TPM resets happen asynchronously, conceivably there is some interface (i2cs or sps) activity under way when TPM is reset. Sps driver provides a means of disconnecting the client of the driver, while the i2cs driver does not. Come to think of it, there is no real need to provide a special function to disconnect a client, this makes API simpler and allows to add driver initialization to the client registration function. To make tpm_registers.c more flexible - allow to register a callback for interface initialization, this way when TPM is reset, the interface can be also re-initialized and is guaranteed to start from scratch after reset. BRANCH=none BUG=chrome-os-partner:52366 TEST=both firmware_TPMExtend and firmware_TPMKernelVersion autotests pass Change-Id: I212166a23f9cd512d8f75315377d1f5620aea070 Signed-off-by: Vadim Bendebury <vbendeb@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/388886 Reviewed-by: Randall Spangler <rspangler@chromium.org> Reviewed-by: Bill Richardson <wfrichar@chromium.org>
-rw-r--r--chip/g/i2cs.c6
-rw-r--r--chip/g/sps.c18
-rw-r--r--chip/g/sps_tpm.c15
-rw-r--r--common/i2cs_tpm.c12
-rw-r--r--common/tpm_registers.c34
-rw-r--r--include/tpm_registers.h9
6 files changed, 52 insertions, 42 deletions
diff --git a/chip/g/i2cs.c b/chip/g/i2cs.c
index 5e45ec0ee8..507fbfcb1a 100644
--- a/chip/g/i2cs.c
+++ b/chip/g/i2cs.c
@@ -114,7 +114,6 @@ static void i2cs_init(void)
/* Slave address is hardcoded to 0x50. */
GWRITE(I2CS, SLAVE_DEVADDRVAL, 0x50);
}
-DECLARE_HOOK(HOOK_INIT, i2cs_init, HOOK_PRIO_DEFAULT);
/* Process the 'end of a write cycle' interrupt. */
static void _i2cs_write_complete_int(void)
@@ -258,9 +257,8 @@ void i2cs_post_read_fill_fifo(uint8_t *buffer, size_t len)
int i2cs_register_write_complete_handler(wr_complete_handler_f wc_handler)
{
- if (write_complete_handler_)
- return -1;
-
+ task_disable_irq(GC_IRQNUM_I2CS0_INTR_WRITE_COMPLETE_INT);
+ i2cs_init();
write_complete_handler_ = wc_handler;
task_enable_irq(GC_IRQNUM_I2CS0_INTR_WRITE_COMPLETE_INT);
diff --git a/chip/g/sps.c b/chip/g/sps.c
index a25e379bb6..82336eb5a7 100644
--- a/chip/g/sps.c
+++ b/chip/g/sps.c
@@ -211,8 +211,8 @@ static rx_handler_f sps_rx_handler;
int sps_register_rx_handler(enum sps_mode mode, rx_handler_f rx_handler,
unsigned rx_fifo_threshold)
{
- if (sps_rx_handler)
- return -1;
+ task_disable_irq(GC_IRQNUM_SPS0_RXFIFO_LVL_INTR);
+ task_disable_irq(GC_IRQNUM_SPS0_CS_DEASSERT_INTR);
if (!rx_fifo_threshold)
rx_fifo_threshold = 8; /* This is a sensible default. */
@@ -225,18 +225,6 @@ int sps_register_rx_handler(enum sps_mode mode, rx_handler_f rx_handler,
return 0;
}
-int sps_unregister_rx_handler(void)
-{
- if (!sps_rx_handler)
- return -1;
-
- task_disable_irq(GC_IRQNUM_SPS0_RXFIFO_LVL_INTR);
- task_disable_irq(GC_IRQNUM_SPS0_CS_DEASSERT_INTR);
-
- sps_rx_handler = NULL;
- return 0;
-}
-
static void sps_init(void)
{
/*
@@ -503,8 +491,6 @@ static int command_sps(int argc, char **argv)
}
}
- sps_unregister_rx_handler();
-
ccprintf("Processed %d frames\n", count - 1);
ccprintf("rx count %d, tx count %d, tx_empty %d, max rx batch %d\n",
sps_rx_count, sps_tx_count,
diff --git a/chip/g/sps_tpm.c b/chip/g/sps_tpm.c
index 3ef12994e6..771ae847b1 100644
--- a/chip/g/sps_tpm.c
+++ b/chip/g/sps_tpm.c
@@ -262,7 +262,7 @@ static void tpm_rx_handler(uint8_t *data, size_t data_size, int cs_disabled)
init_new_cycle();
}
-void sps_tpm_enable(void)
+static void sps_tpm_enable(void)
{
/*
* Let's make sure we get an interrupt as soon as the header is
@@ -272,11 +272,12 @@ void sps_tpm_enable(void)
init_new_cycle();
}
-void sps_tpm_disable(void)
+
+static void sps_if_register(void)
{
- sps_tpm_state = SPS_TPM_STATE_PONDERING;
- sps_unregister_rx_handler();
- /* We don't care anymore, so we can sleep whenever */
- delay_sleep_by(0);
- enable_sleep(SLEEP_MASK_SPI);
+ if (!(system_get_board_properties() & BOARD_SLAVE_CONFIG_SPI))
+ return;
+
+ tpm_register_interface(sps_tpm_enable);
}
+DECLARE_HOOK(HOOK_INIT, sps_if_register, HOOK_PRIO_LAST);
diff --git a/common/i2cs_tpm.c b/common/i2cs_tpm.c
index 7700fd8373..5aa3a07e01 100644
--- a/common/i2cs_tpm.c
+++ b/common/i2cs_tpm.c
@@ -223,8 +223,16 @@ static void wr_complete_handler(void *i2cs_data, size_t i2cs_data_size)
gpio_set_level(GPIO_INT_AP_L, 1);
}
-static void i2cs_tpm_init(void)
+static void i2cs_tpm_enable(void)
{
i2cs_register_write_complete_handler(wr_complete_handler);
}
-DECLARE_HOOK(HOOK_INIT, i2cs_tpm_init, HOOK_PRIO_LAST);
+
+static void i2cs_if_register(void)
+{
+ if (!(system_get_board_properties() & BOARD_SLAVE_CONFIG_I2C))
+ return;
+
+ tpm_register_interface(i2cs_tpm_enable);
+}
+DECLARE_HOOK(HOOK_INIT, i2cs_if_register, HOOK_PRIO_LAST);
diff --git a/common/tpm_registers.c b/common/tpm_registers.c
index dce342ee5f..a2bdec4925 100644
--- a/common/tpm_registers.c
+++ b/common/tpm_registers.c
@@ -46,6 +46,8 @@
#define GOOGLE_DID 0x0028
#define CR50_RID 0 /* No revision ID yet */
+static uint8_t reset_in_progress __attribute__((section(".bss.noreinit")));
+
/* Tpm state machine states. */
enum tpm_states {
tpm_state_idle,
@@ -372,6 +374,9 @@ void tpm_register_put(uint32_t regaddr, const uint8_t *data, uint32_t data_size)
{
uint32_t i;
+ if (reset_in_progress)
+ return;
+
CPRINTF("%s(0x%03x, %d,", __func__, regaddr, data_size);
for (i = 0; i < data_size && i < 4; i++)
CPRINTF(" %02x", data[i]);
@@ -443,6 +448,9 @@ void tpm_register_get(uint32_t regaddr, uint8_t *dest, uint32_t data_size)
{
int i;
+ if (reset_in_progress)
+ return;
+
CPRINTF("%s(0x%06x, %d)", __func__, regaddr, data_size);
switch (regaddr) {
case TPM_DID_VID:
@@ -492,11 +500,23 @@ void tpm_register_get(uint32_t regaddr, uint8_t *dest, uint32_t data_size)
CPRINTF("\n");
}
+static interface_restart_func if_restart
+__attribute__((section(".bss.noreinit")));
+void tpm_register_interface(interface_restart_func interface_restart)
+{
+ if_restart = interface_restart;
+}
+
static void tpm_init(void)
{
/* This is more related to TPM task activity than TPM transactions */
cprints(CC_TASK, "%s", __func__);
+ if (system_rolling_reboot_suspected()) {
+ cprints(CC_TASK, "%s interrupted", __func__);
+ return;
+ }
+
set_tpm_state(tpm_state_idle);
tpm_.regs.access = tpm_reg_valid_sts;
/*
@@ -534,6 +554,9 @@ static void tpm_init(void)
}
_plat__SetNvAvail();
+
+ /* Reinitialize TPM interface. */
+ if_restart();
}
size_t tpm_get_burst_size(void)
@@ -604,11 +627,11 @@ int tpm_reset(void)
static void tpm_reset_now(void)
{
+ reset_in_progress = 1;
+
/* This is more related to TPM task activity than TPM transactions */
cprints(CC_TASK, "%s", __func__);
- sps_tpm_disable();
-
/*
* Clear the TPM library's zero-init data. Note that the linker script
* includes this file's .bss in the same section, so it will be cleared
@@ -626,22 +649,17 @@ static void tpm_reset_now(void)
/* Re-initialize our registers */
tpm_init();
- sps_tpm_enable();
-
if (waiting_for_reset != TASK_ID_INVALID) {
/* Wake the waiting task, if any */
task_set_event(waiting_for_reset, TPM_EVENT_RESET, 0);
waiting_for_reset = TASK_ID_INVALID;
}
+ reset_in_progress = 0;
}
void tpm_task(void)
{
- if (system_rolling_reboot_suspected())
- return;
-
tpm_init();
- sps_tpm_enable();
while (1) {
uint8_t *response;
unsigned response_size;
diff --git a/include/tpm_registers.h b/include/tpm_registers.h
index 037fc73441..9c9390ffb7 100644
--- a/include/tpm_registers.h
+++ b/include/tpm_registers.h
@@ -23,14 +23,13 @@ void tpm_register_put(uint32_t regaddr,
/* The SPI master is reading data from a TPM register. */
void tpm_register_get(uint32_t regaddr, uint8_t *dest, uint32_t data_size);
-/* Enable SPS TPM driver. */
-void sps_tpm_enable(void);
-/* Disable SPS TPM driver. */
-void sps_tpm_disable(void);
-
/* Get the current value of the burst size field of the status register. */
size_t tpm_get_burst_size(void);
+/* Register a function to restart TPM communications layer. */
+typedef void (*interface_restart_func)(void);
+void tpm_register_interface(interface_restart_func interface_restart);
+
/*
* Reset the TPM. This sends a request to the TPM task, so that the reset can
* happen when the TPM task finishes whatever it's doing at the moment.