summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLouis Yung-Chieh Lo <yjlou@chromium.org>2014-07-07 14:27:43 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-07-08 04:28:40 +0000
commit3becb4c5c3267507fa6de7e99821783b1187e8d2 (patch)
treea2b257f54e242d68777d30f4658c998233be42bb
parent3b49eaee539f9982faa554c4eaa75e5f94ee0395 (diff)
downloadchrome-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.c56
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;