q2spi-msm-geni: skip terminate sequence during start sequence failed

When SOC in sleep state, q2spi first transfer will be failed with
start sequence timed out status. As part of timeout host performs
terminate sequence, once terminate sequence is done, GSI-FW can
serve the doorbell any point of time, which is leading to race
conditions. To solve this skipped terminate sequence during
start sequence failure case.

Also modified SW sequence as per recommendation by HPG.

Change-Id: I8ccbb93d45b2fe6da67bc36086691666e34cb0db
Signed-off-by: Chandana Kishori Chiluveru <quic_cchiluve@quicinc.com>
Signed-off-by: Anil Veshala Veshala <quic_aveshala@quicinc.com>
This commit is contained in:
Anil Veshala Veshala 2024-08-05 04:21:13 -07:00 committed by Chandana Kishori Chiluveru
parent 811947e6b5
commit 2875185c00
3 changed files with 63 additions and 9 deletions

View File

@ -106,6 +106,40 @@ static void q2spi_parse_cr_header(struct q2spi_geni *q2spi, struct msm_gpi_cb co
q2spi_doorbell(q2spi, &cb->q2spi_cr_header_event);
}
/*
* q2spi_check_m_irq_err_status() - this function checks m_irq error status and
* also if start sequence error seen it will set is_start_seq_fail flag as true.
*
* @q2spi: q2spi master device handle
* @cb_status: irq status fields
*
* Return: None
*/
static void q2spi_check_m_irq_err_status(struct q2spi_geni *q2spi, u32 cb_status)
{
/* bit 5 to 12 represents gp irq status */
u32 status = (cb_status & M_GP_IRQ_MASK) >> M_GP_IRQ_ERR_START_BIT;
if (status & Q2SPI_PWR_ON_NACK)
Q2SPI_DEBUG(q2spi, "%s Q2SPI_PWR_ON_NACK\n", __func__);
if (status & Q2SPI_HDR_FAIL)
Q2SPI_DEBUG(q2spi, "%s Q2SPI_HDR_FAIL\n", __func__);
if (status & Q2SPI_HCR_FAIL)
Q2SPI_DEBUG(q2spi, "%s Q2SPI_HCR_FAIL\n", __func__);
if (status & Q2SPI_CHECKSUM_FAIL)
Q2SPI_DEBUG(q2spi, "%s Q2SPI_CHEKSUM_FAIL\n", __func__);
if (status & Q2SPI_START_SEQ_TIMEOUT) {
q2spi->is_start_seq_fail = true;
Q2SPI_DEBUG(q2spi, "%s Q2SPI_START_SEQ_TIMEOUT\n", __func__);
}
if (status & Q2SPI_STOP_SEQ_TIMEOUT)
Q2SPI_DEBUG(q2spi, "%s Q2SPI_STOP_SEQ_TIMEOUT\n", __func__);
if (status & Q2SPI_WAIT_PHASE_TIMEOUT)
Q2SPI_DEBUG(q2spi, "%s Q2SPI_WAIT_PHASE_TIMEOUT\n", __func__);
if (status & Q2SPI_CLIENT_EN_NOT_DETECTED)
Q2SPI_DEBUG(q2spi, "%s Q2SPI_CLIENT_EN_NOT_DETECTED\n", __func__);
}
static void q2spi_gsi_tx_callback(void *cb)
{
struct msm_gpi_dma_async_tx_cb_param *cb_param = NULL;
@ -131,6 +165,9 @@ static void q2spi_gsi_tx_callback(void *cb)
if (cb_param->completion_code == MSM_GPI_TCE_UNEXP_ERR) {
Q2SPI_DEBUG(q2spi, "%s Unexpected GSI CB completion code CB status:0x%x\n",
__func__, cb_param->status);
q2spi->gsi->qup_gsi_err = true;
q2spi_check_m_irq_err_status(q2spi, cb_param->status);
complete_all(&q2spi->tx_cb);
return;
} else if (cb_param->completion_code == MSM_GPI_TCE_EOT) {
Q2SPI_DEBUG(q2spi, "%s MSM_GPI_TCE_EOT\n", __func__);
@ -470,7 +507,7 @@ int check_gsi_transfer_completion(struct q2spi_geni *q2spi)
Q2SPI_DEBUG(q2spi, "%s PID:%d Tx[%d] timeout\n", __func__, current->pid, i);
ret = -ETIMEDOUT;
goto err_gsi_geni_transfer;
} else {
} else if (!q2spi->gsi->qup_gsi_err) {
Q2SPI_DEBUG(q2spi, "%s tx completed\n", __func__);
}
}
@ -482,7 +519,7 @@ int check_gsi_transfer_completion(struct q2spi_geni *q2spi)
Q2SPI_DEBUG(q2spi, "%s PID:%d Rx[%d] timeout\n", __func__, current->pid, i);
ret = -ETIMEDOUT;
goto err_gsi_geni_transfer;
} else {
} else if (!q2spi->gsi->qup_gsi_err) {
Q2SPI_DEBUG(q2spi, "%s rx completed\n", __func__);
}
}
@ -492,7 +529,8 @@ int check_gsi_transfer_completion(struct q2spi_geni *q2spi)
Q2SPI_DEBUG(q2spi, "%s Err QUP Gsi Error\n", __func__);
q2spi->gsi->qup_gsi_err = false;
q2spi->setup_config0 = false;
gpi_q2spi_terminate_all(q2spi->gsi->tx_c);
if (!q2spi->is_start_seq_fail)
gpi_q2spi_terminate_all(q2spi->gsi->tx_c);
}
return ret;
}

View File

@ -1986,7 +1986,9 @@ static int q2spi_transfer_with_retries(struct q2spi_geni *q2spi, struct q2spi_re
goto transfer_exit;
}
if (i == 0 && !atomic_read(&q2spi->doorbell_pending)) {
if (i == 0 && !atomic_read(&q2spi->doorbell_pending) &&
q2spi->is_start_seq_fail) {
q2spi->is_start_seq_fail = false;
ret = q2spi_wakeup_hw_from_sleep(q2spi);
if (ret) {
Q2SPI_DEBUG(q2spi, "%s Err q2spi_wakeup_hw_from_sleep\n",
@ -2270,6 +2272,7 @@ 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;
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);
@ -4570,8 +4573,6 @@ int q2spi_wakeup_slave_through_gpio(struct q2spi_geni *q2spi)
Q2SPI_DEBUG(q2spi, "%s Sending disconnect doorbell only\n", __func__);
atomic_set(&q2spi->slave_in_sleep, 0);
geni_gsi_disconnect_doorbell_stop_ch(q2spi->gsi->tx_c, true);
q2spi_unmap_doorbell_rx_buf(q2spi);
ret = pinctrl_select_state(q2spi->geni_pinctrl, q2spi->geni_gpio_default);
if (ret) {
@ -4610,9 +4611,10 @@ int q2spi_wakeup_slave_through_gpio(struct q2spi_geni *q2spi)
__func__, ret);
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);
/* add necessary delay to wake up the soc */
usleep_range(5000, 6000);
gpi_q2spi_terminate_all(q2spi->gsi->tx_c);
return ret;
}

View File

@ -133,6 +133,18 @@
#define SE_SPI_RX_TRANS_LEN 0x270
#define TRANS_LEN_MSK GENMASK(23, 0)
/* GENI General Purpose Interrupt Status */
#define M_GP_IRQ_ERR_START_BIT 5
#define M_GP_IRQ_MASK GENMASK(12, 5)
#define Q2SPI_PWR_ON_NACK BIT(0)
#define Q2SPI_HDR_FAIL BIT(1)
#define Q2SPI_HCR_FAIL BIT(2)
#define Q2SPI_CHECKSUM_FAIL BIT(3)
#define Q2SPI_START_SEQ_TIMEOUT BIT(4)
#define Q2SPI_STOP_SEQ_TIMEOUT BIT(5)
#define Q2SPI_WAIT_PHASE_TIMEOUT BIT(6)
#define Q2SPI_CLIENT_EN_NOT_DETECTED BIT(7)
/* HRF FLOW Info */
#define HRF_ENTRY_OPCODE 3
#define HRF_ENTRY_TYPE 3
@ -518,6 +530,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
* @slave_sleep_lock: lock to wait for 3msec after sleep packet before initiating next transfer.
* @is_start_seq_fail: start sequence fail due to slave not responding
*/
struct q2spi_geni {
struct device *wrapper_dev;
@ -626,6 +639,7 @@ struct q2spi_geni {
bool q2spi_cr_hdr_err;
/* lock to protect sleep cmd to slave and next transfer */
struct mutex slave_sleep_lock;
bool is_start_seq_fail;
};
/**