From 811947e6b5b75ca7f35596c49884a4002ca663a0 Mon Sep 17 00:00:00 2001 From: Chandana Kishori Chiluveru Date: Fri, 19 Jul 2024 08:06:36 -0700 Subject: [PATCH] q2spi-msm-geni: connect GSI doorbell after start channel operation Synchronous channel command 48 needed to connect doorbell signal after performing start channel operation to serve the doorbell signal from gsi. Also ensure doorbell buffers are mapped after doorbell connect cmd. Without this GSI FW corruptions seen during q2spi sleep wakeup sequence. Change-Id: Idf7a420e29eac3767d66492872d54c20bb657371 Signed-off-by: Chandana Kishori Chiluveru --- drivers/dma/qcom/msm_gpi.c | 33 +++++++++++++++++++++++++++++---- drivers/spi/q2spi-gsi.c | 6 ++++++ drivers/spi/q2spi-msm-geni.c | 31 ++++++++++++------------------- include/linux/msm_gpi.h | 8 ++++++++ 4 files changed, 55 insertions(+), 23 deletions(-) diff --git a/drivers/dma/qcom/msm_gpi.c b/drivers/dma/qcom/msm_gpi.c index a728e20655a8..18d69ed0f969 100644 --- a/drivers/dma/qcom/msm_gpi.c +++ b/drivers/dma/qcom/msm_gpi.c @@ -1772,11 +1772,40 @@ int gpi_terminate_channel(struct gpii_chan *gpii_chan) return ret; } +/* + * geni_gsi_connect_doorbell() - function to connect gsi doorbell + * @chan: gsi channel handle + * + * This function uses asynchronous channel command 48 to connect + * io_6 input from GSI interrupt input. + * + * Return: Returns success or failure + */ +int geni_gsi_connect_doorbell(struct dma_chan *chan) +{ + struct gpii_chan *gpii_chan = to_gpii_chan(chan); + struct gpii *gpii = gpii_chan->gpii; + int ret = 0; + + GPII_VERB(gpii, gpii_chan->chid, "Enter\n"); + ret = gpi_send_cmd(gpii, gpii_chan, GPI_CH_CMD_ENABLE_HID); + if (ret) { + GPII_ERR(gpii, gpii_chan->chid, "Error enable Chan:%d HID interrupt\n", ret); + gpi_dump_debug_reg(gpii); + } + + return ret; +} +EXPORT_SYMBOL_GPL(geni_gsi_connect_doorbell); + /* * geni_gsi_disconnect_doorbell_stop_ch() - function to disconnect gsi doorbell and stop channel * @chan: gsi channel handle * @stop_ch: stop channel if set to true * + * This function uses asynchronous channel command 49 to dis-connect + * io_6 input from GSI interrupt input. + * * Return: Returns success or failure */ int geni_gsi_disconnect_doorbell_stop_ch(struct dma_chan *chan, bool stop_ch) @@ -1786,10 +1815,6 @@ int geni_gsi_disconnect_doorbell_stop_ch(struct dma_chan *chan, bool stop_ch) int ret = 0; bool error = false; - /* - * Use asynchronous channel command 49 (see section 3.10.7) to dis-connect - * io_6 input from GSI interrupt input. - */ GPII_VERB(gpii, gpii_chan->chid, "Enter\n"); ret = gpi_send_cmd(gpii, gpii_chan, GPI_CH_CMD_DISABLE_HID); if (ret) { diff --git a/drivers/spi/q2spi-gsi.c b/drivers/spi/q2spi-gsi.c index ee4a9b225b2c..7f7e4a1630b1 100644 --- a/drivers/spi/q2spi-gsi.c +++ b/drivers/spi/q2spi-gsi.c @@ -708,6 +708,7 @@ void q2spi_gsi_ch_ev_cb(struct dma_chan *ch, struct msm_gpi_cb const *cb, void * case MSM_GPI_QUP_CR_HEADER: /* Update last access time of a device for autosuspend */ pm_runtime_mark_last_busy(q2spi->dev); + q2spi->gsi->qup_gsi_err = false; q2spi_cr_hdr_event = &cb->q2spi_cr_header_event; num_crs = q2spi_cr_hdr_event->byte0_len; if (q2spi_cr_hdr_event->code == Q2SPI_CR_HEADER_LEN_ZERO || @@ -744,6 +745,11 @@ void q2spi_gsi_ch_ev_cb(struct dma_chan *ch, struct msm_gpi_cb const *cb, void * if (cb->cb_event == MSM_GPI_QUP_ERROR) q2spi->gsi->qup_gsi_global_err = true; + if (cb->cb_event == MSM_GPI_QUP_FW_ERROR) { + q2spi_geni_se_dump_regs(q2spi); + gpi_dump_for_geni(q2spi->gsi->tx_c); + } + if (q2spi->gsi->qup_gsi_err) Q2SPI_DEBUG(q2spi, "%s set qup_gsi_err\n", __func__); } diff --git a/drivers/spi/q2spi-msm-geni.c b/drivers/spi/q2spi-msm-geni.c index dc8b1613cd3d..adaceda5c111 100644 --- a/drivers/spi/q2spi-msm-geni.c +++ b/drivers/spi/q2spi-msm-geni.c @@ -1977,15 +1977,16 @@ static int q2spi_transfer_with_retries(struct q2spi_geni *q2spi, struct q2spi_re return ret; } else if (ret == -ETIMEDOUT) { /* Upon transfer failure's retry here */ - Q2SPI_DEBUG(q2spi, "%s ret:%d retry_count:%d retrying cur_q2spi_pkt:%p\n", - __func__, ret, i + 1, cur_q2spi_pkt); + Q2SPI_DEBUG(q2spi, "%s ret:%d retry_count:%d q2spi_pkt:%p db_pending:%d\n", + __func__, ret, i + 1, cur_q2spi_pkt, + atomic_read(&q2spi->doorbell_pending)); if (q2spi->gsi->qup_gsi_global_err) { Q2SPI_DEBUG(q2spi, "%s GSI global error, No retry\n", __func__); ret = -EIO; goto transfer_exit; } - if (i == 0) { + if (i == 0 && !atomic_read(&q2spi->doorbell_pending)) { ret = q2spi_wakeup_hw_from_sleep(q2spi); if (ret) { Q2SPI_DEBUG(q2spi, "%s Err q2spi_wakeup_hw_from_sleep\n", @@ -2212,7 +2213,7 @@ static ssize_t q2spi_transfer(struct file *filp, const char __user *buf, size_t return -EINVAL; } q2spi = filp->private_data; - Q2SPI_DEBUG(q2spi, "%s Enter PID=%d\n", __func__, current->pid); + Q2SPI_DEBUG(q2spi, "In %s Enter PID=%d\n", __func__, current->pid); mutex_lock(&q2spi->port_lock); ret = q2spi_transfer_check(q2spi, &q2spi_req, buf, len); @@ -2784,9 +2785,6 @@ static int q2spi_gsi_submit(struct q2spi_packet *q2spi_pkt) if (ret) { Q2SPI_DEBUG(q2spi, "%s Err q2spi_setup_gsi_xfer failed: %d\n", __func__, ret); atomic_set(&q2spi->sma_wr_pending, 0); - atomic_set(&q2spi->doorbell_pending, 0); - q2spi_geni_se_dump_regs(q2spi); - gpi_dump_for_geni(q2spi->gsi->tx_c); del_timer_sync(&q2spi->slave_sleep_timer); goto unmap_buf; } @@ -2797,9 +2795,6 @@ static int q2spi_gsi_submit(struct q2spi_packet *q2spi_pkt) Q2SPI_DEBUG(q2spi, "%s PID:%d Err completion timeout: %d\n", __func__, current->pid, ret); atomic_set(&q2spi->sma_wr_pending, 0); - atomic_set(&q2spi->doorbell_pending, 0); - q2spi_geni_se_dump_regs(q2spi); - gpi_dump_for_geni(q2spi->gsi->tx_c); del_timer_sync(&q2spi->slave_sleep_timer); goto unmap_buf; } @@ -3102,14 +3097,11 @@ int __q2spi_send_messages(struct q2spi_geni *q2spi, void *ptr) q2spi_pkt->var5_pkt->flow_id); } } - if (!cm_flow_pkt && atomic_read(&q2spi->doorbell_pending)) { - atomic_inc(&q2spi->retry); - Q2SPI_DEBUG(q2spi, "%s doorbell pending retry\n", __func__); - complete_all(&q2spi_pkt->bulk_wait); - q2spi_unmap_var_bufs(q2spi, q2spi_pkt); - ret = -EAGAIN; - goto send_msg_exit; - } + + if (!cm_flow_pkt && atomic_read(&q2spi->doorbell_pending)) + Q2SPI_DEBUG(q2spi, "%s cm_flow_pkt:%d doorbell_pending:%d\n", + __func__, cm_flow_pkt, atomic_read(&q2spi->doorbell_pending)); + ret = q2spi_gsi_submit(q2spi_pkt); if (ret) { Q2SPI_DEBUG(q2spi, "%s Err q2spi_gsi_submit failed: %d\n", __func__, ret); @@ -4619,7 +4611,7 @@ int q2spi_wakeup_slave_through_gpio(struct q2spi_geni *q2spi) return ret; } geni_gsi_ch_start(q2spi->gsi->tx_c); - + geni_gsi_connect_doorbell(q2spi->gsi->tx_c); ret = q2spi_map_doorbell_rx_buf(q2spi); return ret; } @@ -4769,6 +4761,7 @@ static int q2spi_geni_runtime_resume(struct device *dev) Q2SPI_DEBUG(q2spi, "%s Failed to set IRQ wake\n", __func__); geni_gsi_ch_start(q2spi->gsi->tx_c); + geni_gsi_connect_doorbell(q2spi->gsi->tx_c); /* Clear is_suspend to map doorbell buffers */ atomic_set(&q2spi->is_suspend, 0); diff --git a/include/linux/msm_gpi.h b/include/linux/msm_gpi.h index dac16f3d4157..1f64a2ed1e8f 100644 --- a/include/linux/msm_gpi.h +++ b/include/linux/msm_gpi.h @@ -470,6 +470,14 @@ int gsi_common_tx_tre_optimization(struct gsi_common *gsi, u32 num_xfers, u32 nu */ int geni_gsi_ch_start(struct dma_chan *chan); +/** + * geni_gsi_connect_doorbell() - function to connect gsi doorbell + * @chan: dma channel handle + * + * Return: Returns success or failure + */ +int geni_gsi_connect_doorbell(struct dma_chan *chan); + /** * geni_gsi_disconnect_doorbell_stop_ch() - function to disconnect gsi doorbell and stop channel * @chan: dma channel handle