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>
This commit is contained in:
Vadim Bendebury
2016-09-22 18:52:47 -07:00
committed by chrome-bot
parent 75aaabcd9a
commit 5a6bb19a88
6 changed files with 52 additions and 42 deletions

View File

@@ -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);

View File

@@ -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,

View File

@@ -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);

View File

@@ -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);

View File

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

View File

@@ -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.