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 <quic_cchiluve@quicinc.com>
This commit is contained in:
Chandana Kishori Chiluveru 2024-07-19 08:06:36 -07:00
parent 76c1fe285b
commit 811947e6b5
4 changed files with 55 additions and 23 deletions

View File

@ -1772,11 +1772,40 @@ int gpi_terminate_channel(struct gpii_chan *gpii_chan)
return ret; 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 * geni_gsi_disconnect_doorbell_stop_ch() - function to disconnect gsi doorbell and stop channel
* @chan: gsi channel handle * @chan: gsi channel handle
* @stop_ch: stop channel if set to true * @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 * Return: Returns success or failure
*/ */
int geni_gsi_disconnect_doorbell_stop_ch(struct dma_chan *chan, bool stop_ch) 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; int ret = 0;
bool error = false; 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"); GPII_VERB(gpii, gpii_chan->chid, "Enter\n");
ret = gpi_send_cmd(gpii, gpii_chan, GPI_CH_CMD_DISABLE_HID); ret = gpi_send_cmd(gpii, gpii_chan, GPI_CH_CMD_DISABLE_HID);
if (ret) { if (ret) {

View File

@ -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: case MSM_GPI_QUP_CR_HEADER:
/* Update last access time of a device for autosuspend */ /* Update last access time of a device for autosuspend */
pm_runtime_mark_last_busy(q2spi->dev); pm_runtime_mark_last_busy(q2spi->dev);
q2spi->gsi->qup_gsi_err = false;
q2spi_cr_hdr_event = &cb->q2spi_cr_header_event; q2spi_cr_hdr_event = &cb->q2spi_cr_header_event;
num_crs = q2spi_cr_hdr_event->byte0_len; num_crs = q2spi_cr_hdr_event->byte0_len;
if (q2spi_cr_hdr_event->code == Q2SPI_CR_HEADER_LEN_ZERO || 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) if (cb->cb_event == MSM_GPI_QUP_ERROR)
q2spi->gsi->qup_gsi_global_err = true; 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) if (q2spi->gsi->qup_gsi_err)
Q2SPI_DEBUG(q2spi, "%s set qup_gsi_err\n", __func__); Q2SPI_DEBUG(q2spi, "%s set qup_gsi_err\n", __func__);
} }

View File

@ -1977,15 +1977,16 @@ static int q2spi_transfer_with_retries(struct q2spi_geni *q2spi, struct q2spi_re
return ret; return ret;
} else if (ret == -ETIMEDOUT) { } else if (ret == -ETIMEDOUT) {
/* Upon transfer failure's retry here */ /* Upon transfer failure's retry here */
Q2SPI_DEBUG(q2spi, "%s ret:%d retry_count:%d retrying cur_q2spi_pkt:%p\n", Q2SPI_DEBUG(q2spi, "%s ret:%d retry_count:%d q2spi_pkt:%p db_pending:%d\n",
__func__, ret, i + 1, cur_q2spi_pkt); __func__, ret, i + 1, cur_q2spi_pkt,
atomic_read(&q2spi->doorbell_pending));
if (q2spi->gsi->qup_gsi_global_err) { if (q2spi->gsi->qup_gsi_global_err) {
Q2SPI_DEBUG(q2spi, "%s GSI global error, No retry\n", __func__); Q2SPI_DEBUG(q2spi, "%s GSI global error, No retry\n", __func__);
ret = -EIO; ret = -EIO;
goto transfer_exit; goto transfer_exit;
} }
if (i == 0) { if (i == 0 && !atomic_read(&q2spi->doorbell_pending)) {
ret = q2spi_wakeup_hw_from_sleep(q2spi); ret = q2spi_wakeup_hw_from_sleep(q2spi);
if (ret) { if (ret) {
Q2SPI_DEBUG(q2spi, "%s Err q2spi_wakeup_hw_from_sleep\n", 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; return -EINVAL;
} }
q2spi = filp->private_data; 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); mutex_lock(&q2spi->port_lock);
ret = q2spi_transfer_check(q2spi, &q2spi_req, buf, len); 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) { if (ret) {
Q2SPI_DEBUG(q2spi, "%s Err q2spi_setup_gsi_xfer failed: %d\n", __func__, 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->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); del_timer_sync(&q2spi->slave_sleep_timer);
goto unmap_buf; 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", Q2SPI_DEBUG(q2spi, "%s PID:%d Err completion timeout: %d\n",
__func__, current->pid, ret); __func__, current->pid, ret);
atomic_set(&q2spi->sma_wr_pending, 0); 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); del_timer_sync(&q2spi->slave_sleep_timer);
goto unmap_buf; goto unmap_buf;
} }
@ -3102,14 +3097,11 @@ int __q2spi_send_messages(struct q2spi_geni *q2spi, void *ptr)
q2spi_pkt->var5_pkt->flow_id); q2spi_pkt->var5_pkt->flow_id);
} }
} }
if (!cm_flow_pkt && atomic_read(&q2spi->doorbell_pending)) {
atomic_inc(&q2spi->retry); if (!cm_flow_pkt && atomic_read(&q2spi->doorbell_pending))
Q2SPI_DEBUG(q2spi, "%s doorbell pending retry\n", __func__); Q2SPI_DEBUG(q2spi, "%s cm_flow_pkt:%d doorbell_pending:%d\n",
complete_all(&q2spi_pkt->bulk_wait); __func__, cm_flow_pkt, atomic_read(&q2spi->doorbell_pending));
q2spi_unmap_var_bufs(q2spi, q2spi_pkt);
ret = -EAGAIN;
goto send_msg_exit;
}
ret = q2spi_gsi_submit(q2spi_pkt); ret = q2spi_gsi_submit(q2spi_pkt);
if (ret) { if (ret) {
Q2SPI_DEBUG(q2spi, "%s Err q2spi_gsi_submit failed: %d\n", __func__, 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; return ret;
} }
geni_gsi_ch_start(q2spi->gsi->tx_c); geni_gsi_ch_start(q2spi->gsi->tx_c);
geni_gsi_connect_doorbell(q2spi->gsi->tx_c);
ret = q2spi_map_doorbell_rx_buf(q2spi); ret = q2spi_map_doorbell_rx_buf(q2spi);
return ret; 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__); Q2SPI_DEBUG(q2spi, "%s Failed to set IRQ wake\n", __func__);
geni_gsi_ch_start(q2spi->gsi->tx_c); geni_gsi_ch_start(q2spi->gsi->tx_c);
geni_gsi_connect_doorbell(q2spi->gsi->tx_c);
/* Clear is_suspend to map doorbell buffers */ /* Clear is_suspend to map doorbell buffers */
atomic_set(&q2spi->is_suspend, 0); atomic_set(&q2spi->is_suspend, 0);

View File

@ -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); 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 * geni_gsi_disconnect_doorbell_stop_ch() - function to disconnect gsi doorbell and stop channel
* @chan: dma channel handle * @chan: dma channel handle