From 4219aa4a08dad0959afb920fa4fb5c4c53f87e26 Mon Sep 17 00:00:00 2001 From: Chandana Kishori Chiluveru Date: Tue, 27 Aug 2024 23:04:40 -0700 Subject: [PATCH] q2spi-msm-geni: Ensure Channel errors handled sequentially after START sequence fail When slave is in sleep q2spi host transfer will fail with GSI start sequence failure. In this scenario two events reported from GSI channel error and TX dma completion event 0x22. Since GSI reports these events separately if start sequence fail is not processed before channel error gpi_q2spi_terminate_all is called twice and leading to GSI failures. Ensure Channel errors in GSI recover path are handled sequentially only after START sequence fail is processed. Change-Id: Ie85528b6354241153330c403ba026c5006d5c78e Signed-off-by: Chandana Kishori Chiluveru --- drivers/spi/q2spi-gsi.c | 17 +++++++++++------ drivers/spi/q2spi-msm-geni.c | 4 ++++ drivers/spi/q2spi-msm.h | 2 ++ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/spi/q2spi-gsi.c b/drivers/spi/q2spi-gsi.c index 1e233c97d07c..0af382331462 100644 --- a/drivers/spi/q2spi-gsi.c +++ b/drivers/spi/q2spi-gsi.c @@ -130,6 +130,7 @@ static void q2spi_check_m_irq_err_status(struct q2spi_geni *q2spi, u32 cb_status Q2SPI_DEBUG(q2spi, "%s Q2SPI_CHEKSUM_FAIL\n", __func__); if (status & Q2SPI_START_SEQ_TIMEOUT) { q2spi->is_start_seq_fail = true; + complete_all(&q2spi->wait_comp_start_fail); Q2SPI_DEBUG(q2spi, "%s Q2SPI_START_SEQ_TIMEOUT\n", __func__); } if (status & Q2SPI_STOP_SEQ_TIMEOUT) @@ -495,15 +496,15 @@ int check_gsi_transfer_completion_db_rx(struct q2spi_geni *q2spi) int check_gsi_transfer_completion(struct q2spi_geni *q2spi) { int i = 0, ret = 0; - unsigned long timeout = 0, xfer_timeout = 0; + unsigned long timeleft = 0, xfer_timeout = 0; xfer_timeout = XFER_TIMEOUT_OFFSET; Q2SPI_DEBUG(q2spi, "%s tx_eot:%d rx_eot:%d\n", __func__, q2spi->gsi->num_tx_eot, q2spi->gsi->num_rx_eot); for (i = 0 ; i < q2spi->gsi->num_tx_eot; i++) { - timeout = + timeleft = wait_for_completion_timeout(&q2spi->tx_cb, msecs_to_jiffies(xfer_timeout)); - if (!timeout) { + if (!timeleft) { Q2SPI_DEBUG(q2spi, "%s PID:%d Tx[%d] timeout\n", __func__, current->pid, i); ret = -ETIMEDOUT; goto err_gsi_geni_transfer; @@ -513,9 +514,9 @@ int check_gsi_transfer_completion(struct q2spi_geni *q2spi) } for (i = 0 ; i < q2spi->gsi->num_rx_eot; i++) { - timeout = + timeleft = wait_for_completion_timeout(&q2spi->rx_cb, msecs_to_jiffies(xfer_timeout)); - if (!timeout) { + if (!timeleft) { Q2SPI_DEBUG(q2spi, "%s PID:%d Rx[%d] timeout\n", __func__, current->pid, i); ret = -ETIMEDOUT; goto err_gsi_geni_transfer; @@ -524,11 +525,15 @@ int check_gsi_transfer_completion(struct q2spi_geni *q2spi) } } err_gsi_geni_transfer: - if (q2spi->gsi->qup_gsi_err || !timeout) { + if (q2spi->gsi->qup_gsi_err || !timeleft) { ret = -ETIMEDOUT; Q2SPI_DEBUG(q2spi, "%s Err QUP Gsi Error\n", __func__); q2spi->gsi->qup_gsi_err = false; q2spi->setup_config0 = false; + /* Block on TX completion callback for start sequence failure */ + wait_for_completion_interruptible_timeout + (&q2spi->wait_comp_start_fail, + msecs_to_jiffies(TIMEOUT_MSECONDS)); if (!q2spi->is_start_seq_fail) gpi_q2spi_terminate_all(q2spi->gsi->tx_c); } diff --git a/drivers/spi/q2spi-msm-geni.c b/drivers/spi/q2spi-msm-geni.c index a5cb66cd941c..4b64d1c66d91 100644 --- a/drivers/spi/q2spi-msm-geni.c +++ b/drivers/spi/q2spi-msm-geni.c @@ -2267,7 +2267,9 @@ static ssize_t q2spi_transfer(struct file *filp, const char __user *buf, size_t pm_runtime_set_suspended(q2spi->dev); goto err; } + q2spi->is_start_seq_fail = false; + reinit_completion(&q2spi->wait_comp_start_fail); Q2SPI_DEBUG(q2spi, "%s PM after get_sync count:%d\n", __func__, atomic_read(&q2spi->dev->power.usage_count)); q2spi_wait_for_doorbell_setup_ready(q2spi); @@ -2286,6 +2288,7 @@ static ssize_t q2spi_transfer(struct file *filp, const char __user *buf, size_t ret = -ENOMEM; goto err; } + Q2SPI_DEBUG(q2spi, "%s flow_id:%d\n", __func__, flow_id); ret = q2spi_transfer_with_retries(q2spi, q2spi_req, cur_q2spi_pkt, len, flow_id, user_buf); Q2SPI_DEBUG(q2spi, "%s transfer_with_retries ret:%d\n", __func__, ret); @@ -4421,6 +4424,7 @@ static int q2spi_geni_probe(struct platform_device *pdev) atomic_set(&q2spi->sma_rd_pending, 0); init_completion(&q2spi->sma_wr_comp); init_completion(&q2spi->sma_rd_comp); + init_completion(&q2spi->wait_comp_start_fail); /* Pre allocate buffers for transfers */ ret = q2spi_pre_alloc_buffers(q2spi); diff --git a/drivers/spi/q2spi-msm.h b/drivers/spi/q2spi-msm.h index 83cf08b298da..e0b4db019da5 100644 --- a/drivers/spi/q2spi-msm.h +++ b/drivers/spi/q2spi-msm.h @@ -529,6 +529,7 @@ struct q2spi_dma_transfer { * @q2spi_sleep_cmd_enable: reflects start sending the sleep command to slave * @q2spi_cr_hdr_err: reflects CR Header incorrect in CR Header * @is_start_seq_fail: start sequence fail due to slave not responding + * @wait_comp_start_fail: completion for transfer callback during start sequence failure */ struct q2spi_geni { struct device *wrapper_dev; @@ -636,6 +637,7 @@ struct q2spi_geni { bool q2spi_sleep_cmd_enable; bool q2spi_cr_hdr_err; bool is_start_seq_fail; + struct completion wait_comp_start_fail; }; /**