diff options
author | Louis Yung-Chieh Lo <yjlou@chromium.org> | 2014-07-07 14:27:43 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-07-08 04:28:40 +0000 |
commit | 3becb4c5c3267507fa6de7e99821783b1187e8d2 (patch) | |
tree | a2b257f54e242d68777d30f4658c998233be42bb | |
parent | 3b49eaee539f9982faa554c4eaa75e5f94ee0395 (diff) | |
download | chrome-ec-3becb4c5c3267507fa6de7e99821783b1187e8d2.tar.gz |
stm32 spi: postpone the RX DMA setup if handler is still using buffer.
(cherry-pick back to ToT)
If the AP de-asserts the SPI NSS pin while host command handler is
still processing the command, we would delay the Rx DMA setup later.
If this case happens, the pending result of handler will be dropped.
BUG=chrome-os-partner:28979
BRANCH=tot,nyan
TEST=build and play around on big.
Signed-off-by: Louis Yung-Chieh Lo <yjlou@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/204427
Reviewed-by: Randall Spangler <rspangler@chromium.org>
(cherry picked from commit 4be73492817f3f6c24ece75fed33eb956c0038b8)
Change-Id: Ie2a6550696760eadad3b0d6e3a4e56a2b29abdda
Original-Change-Id: I371a2a0b96b1ee0602be91338bd53d13f6abbd2e
Reviewed-on: https://chromium-review.googlesource.com/206922
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Commit-Queue: Yung-chieh Lo <yjlou@chromium.org>
Tested-by: Yung-chieh Lo <yjlou@chromium.org>
-rw-r--r-- | chip/stm32/spi.c | 56 |
1 files changed, 55 insertions, 1 deletions
diff --git a/chip/stm32/spi.c b/chip/stm32/spi.c index 960c6934b6..c6fd24bc36 100644 --- a/chip/stm32/spi.c +++ b/chip/stm32/spi.c @@ -89,6 +89,12 @@ static uint8_t enabled; static struct host_cmd_handler_args args; static struct host_packet spi_packet; +/* + * This is set if SPI NSS raises to high while EC is still processing a + * command. + */ +static int setup_transaction_later; + enum spi_state { /* SPI not enabled (initial state, and when chipset is off) */ SPI_STATE_DISABLED = 0, @@ -236,6 +242,9 @@ static void setup_for_transaction(void) stm32_spi_regs_t *spi = STM32_SPI1_REGS; volatile uint8_t dummy __attribute__((unused)); + /* clear this as soon as possible */ + setup_transaction_later = 0; + /* Not ready to receive yet */ spi->dr = EC_SPI_NOT_READY; @@ -259,6 +268,24 @@ static void setup_for_transaction(void) spi->dr = EC_SPI_OLD_READY; } + +/* + * If a setup_for_transaction() was postponed, call it now. + * Note that setup_for_transaction() cancels Tx DMA. + */ +static void check_setup_transaction_later(void) +{ + if (setup_transaction_later) { + setup_for_transaction(); + /* + * 'state' is set to SPI_STATE_READY_TO_RX. Somehow AP + * de-asserted the SPI NSS during the handler was running. + * Thus, the pending result will be dropped anyway. + */ + } +} + + /** * Called for V2 protocol to indicate that a command has completed * @@ -278,12 +305,21 @@ static void spi_send_response(struct host_cmd_handler_args *args) if (state != SPI_STATE_PROCESSING) return; + /* state == SPI_STATE_PROCESSING */ + if (args->response_size > args->response_max) result = EC_RES_INVALID_RESPONSE; /* Transmit the reply */ txdma = dma_get_channel(STM32_DMAC_SPI1_TX); reply(txdma, result, args->response, args->response_size); + + /* + * Before the state is set to SENDING, any CS de-assertion would + * set setup_transaction_later to 1. + */ + state = SPI_STATE_SENDING; + check_setup_transaction_later(); } /** @@ -304,6 +340,8 @@ static void spi_send_response_packet(struct host_packet *pkt) if (state != SPI_STATE_PROCESSING) return; + /* state == SPI_STATE_PROCESSING */ + /* Append our past-end byte, which we reserved space for. */ ((uint8_t *)pkt->response)[pkt->response_size] = EC_SPI_PAST_END; @@ -312,6 +350,13 @@ static void spi_send_response_packet(struct host_packet *pkt) dma_prepare_tx(&dma_tx_option, sizeof(out_preamble) + pkt->response_size + 1, out_msg); dma_go(txdma); + + /* + * Before the state is set to SENDING, any CS de-assertion would + * set setup_transaction_later to 1. + */ + state = SPI_STATE_SENDING; + check_setup_transaction_later(); } /** @@ -333,9 +378,18 @@ void spi_event(enum gpio_signal signal) if (!enabled) return; - /* Check chip select. If it's high, the AP ended a tranaction. */ + /* Check chip select. If it's high, the AP ended a transaction. */ nss_reg = gpio_get_level_reg(GPIO_SPI1_NSS, &nss_mask); if (REG16(nss_reg) & nss_mask) { + /* + * If the buffer is still used by the host command, postpone + * the DMA rx setup. + */ + if (state == SPI_STATE_PROCESSING) { + setup_transaction_later = 1; + return; + } + /* Set up for the next transaction */ setup_for_transaction(); return; |