Merge "dmaengine: msm_gpi: fix gpi terminate sequence issue"

This commit is contained in:
QCTECMDR Service 2024-07-29 09:30:30 -07:00 committed by Gerrit - the friendly Code Review server
commit 984a99ba02
4 changed files with 143 additions and 6 deletions

View File

@ -676,6 +676,7 @@ static int gpi_start_chan(struct gpii_chan *gpii_chan);
static void gpi_free_chan_desc(struct gpii_chan *gpii_chan);
static int gpi_deep_sleep_exit_config(struct dma_chan *chan,
struct dma_slave_config *config);
static void gpi_noop_tre(struct gpii_chan *gpii_chan);
static inline struct gpii_chan *to_gpii_chan(struct dma_chan *dma_chan)
{
@ -2223,6 +2224,14 @@ static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan,
struct msm_gpi_tre *gpi_tre;
spin_unlock_irqrestore(&gpii_chan->vc.lock, flags);
/*
* RP pointed by Event is to last TRE processed,
* we need to update ring rp to tre + 1
*/
tre += ch_ring->el_size;
if (tre >= (ch_ring->base + ch_ring->len))
tre = ch_ring->base;
ch_ring->rp = tre;
GPII_ERR(gpii, gpii_chan->chid,
"event without a pending descriptor!\n");
gpi_ere = (struct gpi_ere *)imed_event;
@ -2345,6 +2354,14 @@ static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan,
struct gpi_ere *gpi_ere;
spin_unlock_irqrestore(&gpii_chan->vc.lock, flags);
/*
* RP pointed by Event is to last TRE processed,
* we need to update ring rp to ev_rp + 1
*/
ev_rp += ch_ring->el_size;
if (ev_rp >= (ch_ring->base + ch_ring->len))
ev_rp = ch_ring->base;
ch_ring->rp = ev_rp;
GPII_ERR(gpii, gpii_chan->chid,
"Event without a pending descriptor!\n");
gpi_ere = (struct gpi_ere *)compl_event;
@ -3095,6 +3112,88 @@ int gpi_terminate_all(struct dma_chan *chan)
GPII_INFO(gpii, gpii_chan->chid, "Enter\n");
mutex_lock(&gpii->ctrl_lock);
/*
* treat both channels as a group if its protocol is not UART
* STOP, RESET, or START needs to be in lockstep
*/
schid = (gpii->protocol == SE_PROTOCOL_UART) ? gpii_chan->chid : 0;
echid = (gpii->protocol == SE_PROTOCOL_UART) ? schid + 1 :
MAX_CHANNELS_PER_GPII;
/* stop the channel */
for (i = schid; i < echid; i++) {
gpii_chan = &gpii->gpii_chan[i];
/* disable ch state so no more TRE processing */
write_lock_irq(&gpii->pm_lock);
gpii_chan->pm_state = PREPARE_TERMINATE;
write_unlock_irq(&gpii->pm_lock);
/* send command to Stop the channel */
ret = gpi_send_cmd(gpii, gpii_chan, GPI_CH_CMD_STOP);
if (ret)
GPII_ERR(gpii, gpii_chan->chid,
"Error Stopping Chan:%d resetting\n", ret);
}
/* reset the channels (clears any pending tre) */
for (i = schid; i < echid; i++) {
gpii_chan = &gpii->gpii_chan[i];
ret = gpi_reset_chan(gpii_chan, GPI_CH_CMD_RESET);
if (ret) {
GPII_ERR(gpii, gpii_chan->chid,
"Error resetting channel ret:%d\n", ret);
if (!gpii->reg_table_dump) {
gpi_dump_debug_reg(gpii);
gpii->reg_table_dump = true;
}
goto terminate_exit;
}
/* reprogram channel CNTXT */
ret = gpi_alloc_chan(gpii_chan, false);
if (ret) {
GPII_ERR(gpii, gpii_chan->chid,
"Error alloc_channel ret:%d\n", ret);
goto terminate_exit;
}
}
/* restart the channels */
for (i = schid; i < echid; i++) {
gpii_chan = &gpii->gpii_chan[i];
ret = gpi_start_chan(gpii_chan);
if (ret) {
GPII_ERR(gpii, gpii_chan->chid,
"Error Starting Channel ret:%d\n", ret);
goto terminate_exit;
}
}
terminate_exit:
mutex_unlock(&gpii->ctrl_lock);
return ret;
}
/**
* gpi_q2spi_terminate_all() - function to stop and restart the channels
* @chan: gsi dma channel handle
*
* Return: Returns success or failure
*/
int gpi_q2spi_terminate_all(struct dma_chan *chan)
{
struct gpii_chan *gpii_chan = to_gpii_chan(chan);
struct gpii *gpii = gpii_chan->gpii;
int schid, echid, i;
int ret = 0;
bool stop_cmd_failed = false;
GPII_INFO(gpii, gpii_chan->chid, "Enter\n");
mutex_lock(&gpii->ctrl_lock);
/*
* treat both channels as a group if its protocol is not UART
* STOP, RESET if STOP fails, and RE-START needs to be in lockstep
@ -3117,6 +3216,14 @@ int gpi_terminate_all(struct dma_chan *chan)
if (ret) {
GPII_ERR(gpii, gpii_chan->chid,
"Error Stopping Chan:%d resetting\n", ret);
stop_cmd_failed = true;
}
}
/* Reset both TX and RX channel if stop cmd fails */
if (stop_cmd_failed) {
for (i = schid; i < echid; i++) {
gpii_chan = &gpii->gpii_chan[i];
ret = gpi_reset_chan(gpii_chan, GPI_CH_CMD_RESET);
if (ret) {
GPII_ERR(gpii, gpii_chan->chid,
@ -3127,6 +3234,14 @@ int gpi_terminate_all(struct dma_chan *chan)
}
goto terminate_exit;
}
/* reprogram channel CNTXT */
ret = gpi_alloc_chan(gpii_chan, false);
if (ret) {
GPII_ERR(gpii, gpii_chan->chid,
"Error alloc_channel ret:%d\n", ret);
goto terminate_exit;
}
}
}
@ -3146,6 +3261,7 @@ int gpi_terminate_all(struct dma_chan *chan)
mutex_unlock(&gpii->ctrl_lock);
return ret;
}
EXPORT_SYMBOL_GPL(gpi_q2spi_terminate_all);
static void gpi_noop_tre(struct gpii_chan *gpii_chan)
{

View File

@ -1106,7 +1106,20 @@ static void gi2c_ev_cb(struct dma_chan *ch, struct msm_gpi_cb const *cb_str,
static void gi2c_gsi_cb_err(struct msm_gpi_dma_async_tx_cb_param *cb,
char *xfer)
{
struct geni_i2c_dev *gi2c = cb->userdata;
struct geni_i2c_dev *gi2c;
if (!cb || !cb->userdata) {
pr_err("%s: Invalid gsi_cb\n", __func__);
return;
}
gi2c = cb->userdata;
if (!gi2c->cur) {
geni_i2c_err(gi2c, GENI_SPURIOUS_IRQ);
I2C_LOG_DBG(gi2c->ipcl, false, gi2c->dev, "%s: Invalid gi2c dev\n", __func__);
return;
}
if (cb->status & DM_I2C_CB_ERR) {
I2C_LOG_DBG(gi2c->ipcl, false, gi2c->dev,

View File

@ -450,7 +450,7 @@ int check_gsi_transfer_completion_db_rx(struct q2spi_geni *q2spi)
Q2SPI_DEBUG(q2spi, "%s Err QUP GSI Error\n", __func__);
q2spi->gsi->qup_gsi_err = false;
q2spi->setup_config0 = false;
dmaengine_terminate_all(q2spi->gsi->tx_c);
gpi_q2spi_terminate_all(q2spi->gsi->tx_c);
}
return ret;
}
@ -492,7 +492,7 @@ 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;
dmaengine_terminate_all(q2spi->gsi->tx_c);
gpi_q2spi_terminate_all(q2spi->gsi->tx_c);
}
return ret;
}
@ -593,7 +593,7 @@ int q2spi_setup_gsi_xfer(struct q2spi_packet *q2spi_pkt)
if (dma_submit_error(q2spi->gsi->tx_cookie)) {
Q2SPI_DEBUG(q2spi, "%s Err dmaengine_submit failed (%d)\n",
__func__, q2spi->gsi->tx_cookie);
dmaengine_terminate_all(q2spi->gsi->tx_c);
gpi_q2spi_terminate_all(q2spi->gsi->tx_c);
return -EINVAL;
}
@ -622,7 +622,7 @@ int q2spi_setup_gsi_xfer(struct q2spi_packet *q2spi_pkt)
if (dma_submit_error(q2spi->gsi->rx_cookie)) {
Q2SPI_DEBUG(q2spi, "%s Err dmaengine_submit failed (%d)\n",
__func__, q2spi->gsi->rx_cookie);
dmaengine_terminate_all(q2spi->gsi->rx_c);
gpi_q2spi_terminate_all(q2spi->gsi->rx_c);
return -EINVAL;
}
} else if (cmd == Q2SPI_RX_ONLY) {
@ -650,7 +650,7 @@ int q2spi_setup_gsi_xfer(struct q2spi_packet *q2spi_pkt)
if (dma_submit_error(q2spi->gsi->rx_cookie)) {
Q2SPI_DEBUG(q2spi, "%s Err dmaengine_submit failed (%d)\n",
__func__, q2spi->gsi->rx_cookie);
dmaengine_terminate_all(q2spi->gsi->rx_c);
gpi_q2spi_terminate_all(q2spi->gsi->rx_c);
return -EINVAL;
}
}

View File

@ -413,6 +413,14 @@ struct gsi_common {
*/
void gpi_dump_for_geni(struct dma_chan *chan);
/**
* gpi_q2spi_terminate_all() - function to stop and restart the channels
* @chan: gsi dma channel handle
*
* Return: Returns success or failure
*/
int gpi_q2spi_terminate_all(struct dma_chan *chan);
/**
* gpi_update_multi_desc_flag() - update multi descriptor flag and num of msgs for
* multi descriptor mode handling.