diff --git a/drivers/dma/qcom/msm_gpi.c b/drivers/dma/qcom/msm_gpi.c index 839260466936..8518dbfb1800 100644 --- a/drivers/dma/qcom/msm_gpi.c +++ b/drivers/dma/qcom/msm_gpi.c @@ -1939,8 +1939,7 @@ static void gpi_process_ch_ctrl_irq(struct gpii *gpii) /* notifying clients if in error state */ if (gpii_chan->ch_state == CH_STATE_ERROR) - gpi_generate_cb_event(gpii_chan, MSM_GPI_QUP_CH_ERROR, - ch_irq); + gpi_generate_cb_event(gpii_chan, MSM_GPI_QUP_CH_ERROR, ch_irq); } } @@ -2522,7 +2521,7 @@ gpi_process_xfer_q2spi_cr_header(struct gpii_chan *gpii_chan, q2spi_cr_header_event->cr_hdr[0], q2spi_cr_header_event->cr_hdr[1], q2spi_cr_header_event->cr_hdr[2], q2spi_cr_header_event->cr_hdr[3]); GPII_VERB(gpii_ptr, gpii_chan->chid, - "cr_byte_0:0x%x cr_byte_1:0x%x cr_byte_2:0x%x cr_byte_3h:0x%x\n", + "cr_ed_byte_0:0x%x cr_ed_byte_1:0x%x cr_ed_byte_2:0x%x cr_ed_byte_3:0x%x\n", q2spi_cr_header_event->cr_ed_byte[0], q2spi_cr_header_event->cr_ed_byte[1], q2spi_cr_header_event->cr_ed_byte[2], q2spi_cr_header_event->cr_ed_byte[3]); GPII_VERB(gpii_ptr, gpii_chan->chid, "code:0x%x\n", q2spi_cr_header_event->code); @@ -2530,6 +2529,13 @@ gpi_process_xfer_q2spi_cr_header(struct gpii_chan *gpii_chan, "cr_byte_0_len:0x%x cr_byte_0_err:0x%x type:0x%x ch_id:0x%x\n", q2spi_cr_header_event->byte0_len, q2spi_cr_header_event->byte0_err, q2spi_cr_header_event->type, q2spi_cr_header_event->ch_id); + + if (q2spi_cr_header_event->code == Q2SPI_CR_HEADER_LEN_ZERO) + GPII_ERR(gpii_ptr, gpii_chan->chid, "Err negative 1H doorbell response\n"); + + if (q2spi_cr_header_event->code == Q2SPI_CR_HEADER_INCORRECT) + GPII_ERR(gpii_ptr, gpii_chan->chid, "Err unexpected CR Header is received\n"); + msm_gpi_cb.cb_event = MSM_GPI_QUP_CR_HEADER; msm_gpi_cb.q2spi_cr_header_event = *q2spi_cr_header_event; GPII_VERB(gpii_chan->gpii, gpii_chan->chid, "sending CB event:%s\n", @@ -3165,7 +3171,7 @@ static void gpi_noop_tre(struct gpii_chan *gpii_chan) while (local_rp != local_wp) { /* dump the channel ring at the time of error */ tre = (struct msm_gpi_tre *)cntxt_rp; - GPII_ERR(gpii, gpii_chan->chid, "local_rp:0x%011x TRE: %08x %08x %08x %08x\n", + GPII_ERR(gpii, gpii_chan->chid, "local_rp:%llu TRE: %08x %08x %08x %08x\n", local_rp, tre->dword[0], tre->dword[1], tre->dword[2], tre->dword[3]); tre->dword[3] &= noop_mask; @@ -4242,7 +4248,7 @@ static int gpi_probe(struct platform_device *pdev) /* setup debug capabilities */ gpi_setup_debug(gpi_dev); - GPI_LOG(gpi_dev, "probe success\n"); + GPI_LOG(gpi_dev, "%s: probe success\n", __func__); return ret; } diff --git a/drivers/spi/q2spi-gsi.c b/drivers/spi/q2spi-gsi.c index b2976e496a47..0a13481f0795 100644 --- a/drivers/spi/q2spi-gsi.c +++ b/drivers/spi/q2spi-gsi.c @@ -40,7 +40,7 @@ static void q2spi_rx_xfer_completion_event(struct msm_gpi_dma_async_tx_cb_param status = cb_param->status; if (cb_param->length <= xfer->rx_len) { xfer->rx_len = cb_param->length; - q2spi_dump_ipc(q2spi, q2spi->ipc, "rx_xfer_completion_event RX", + q2spi_dump_ipc(q2spi, "rx_xfer_completion_event RX", (char *)xfer->rx_buf, cb_param->length); if (q2spi_pkt->m_cmd_param == Q2SPI_RX_ONLY) { Q2SPI_DEBUG(q2spi, "%s call db_rx_cb\n", __func__); @@ -52,16 +52,30 @@ static void q2spi_rx_xfer_completion_event(struct msm_gpi_dma_async_tx_cb_param Q2SPI_DEBUG(q2spi, "%s q2spi_pkt:%p state=%d vtype:%d\n", __func__, q2spi_pkt, q2spi_pkt->state, q2spi_pkt->vtype); } else { - Q2SPI_ERROR(q2spi, "%s Err length miss-match %d %d\n", + Q2SPI_DEBUG(q2spi, "%s Err length miss-match %d %d\n", __func__, cb_param->length, xfer->rx_len); } } static void q2spi_tx_xfer_completion_event(struct msm_gpi_dma_async_tx_cb_param *cb_param) { - struct q2spi_packet *q2spi_pkt = cb_param->userdata; - struct q2spi_geni *q2spi = q2spi_pkt->q2spi; - struct q2spi_dma_transfer *xfer = q2spi_pkt->xfer; + struct q2spi_packet *q2spi_pkt; + struct q2spi_geni *q2spi; + struct q2spi_dma_transfer *xfer; + + q2spi_pkt = cb_param->userdata; + if (!q2spi_pkt) { + pr_err("%s Err Invalid q2spi_packet\n", __func__); + return; + } + + q2spi = q2spi_pkt->q2spi; + if (!q2spi || !q2spi_pkt->xfer) { + pr_err("%s Err Invalid q2spi or xfer\n", __func__); + return; + } + + xfer = q2spi_pkt->xfer; Q2SPI_DEBUG(q2spi, "%s xfer->tx_len:%d cb_param_length:%d\n", __func__, xfer->tx_len, cb_param->length); @@ -69,7 +83,7 @@ static void q2spi_tx_xfer_completion_event(struct msm_gpi_dma_async_tx_cb_param Q2SPI_DEBUG(q2spi, "%s complete_tx_cb\n", __func__); complete_all(&q2spi->tx_cb); } else { - Q2SPI_ERROR(q2spi, "%s Err length miss-match\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err length miss-match\n", __func__); } } @@ -111,11 +125,12 @@ static void q2spi_gsi_tx_callback(void *cb) } if (cb_param->status == MSM_GPI_TCE_UNEXP_ERR) { - Q2SPI_DEBUG(q2spi, "%s Unexpected CB status\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Unexpected CB status:0x%x\n", __func__, cb_param->status); return; } if (cb_param->completion_code == MSM_GPI_TCE_UNEXP_ERR) { - Q2SPI_DEBUG(q2spi, "%s Unexpected GSI CB completion code\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Unexpected GSI CB completion code CB status:0x%x\n", + __func__, cb_param->status); return; } else if (cb_param->completion_code == MSM_GPI_TCE_EOT) { Q2SPI_DEBUG(q2spi, "%s MSM_GPI_TCE_EOT\n", __func__); @@ -152,12 +167,13 @@ static void q2spi_gsi_rx_callback(void *cb) } if (cb_param->status == MSM_GPI_TCE_UNEXP_ERR) { - Q2SPI_ERROR(q2spi, "%s Err cb_status:%d\n", __func__, cb_param->status); + Q2SPI_DEBUG(q2spi, "%s Err cb_status:0x%x\n", __func__, cb_param->status); return; } if (cb_param->completion_code == MSM_GPI_TCE_UNEXP_ERR) { - Q2SPI_ERROR(q2spi, "%s Err MSM_GPI_TCE_UNEXP_ERR\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err MSM_GPI_TCE_UNEXP_ERR CB status:0x%x\n", + __func__, cb_param->status); return; } else if (cb_param->completion_code == MSM_GPI_TCE_EOT) { Q2SPI_DEBUG(q2spi, "%s MSM_GPI_TCE_EOT\n", __func__); @@ -214,7 +230,7 @@ int q2spi_geni_gsi_setup(struct q2spi_geni *q2spi) q2spi->gsi = gsi; Q2SPI_DEBUG(q2spi, "%s gsi:%p\n", __func__, gsi); if (gsi->chan_setup) { - Q2SPI_ERROR(q2spi, "%s Err GSI channel already configured\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err GSI channel already configured\n", __func__); return ret; } @@ -324,7 +340,7 @@ static struct msm_gpi_tre *setup_cfg0_tre(struct q2spi_geni *q2spi) Q2SPI_DEBUG(q2spi, "%s Start PID=%d\n", __func__, current->pid); ret = get_q2spi_clk_cfg(q2spi->cur_speed_hz, q2spi, &idx, &div); if (ret) { - Q2SPI_ERROR(q2spi, "%s Err setting clks:%d\n", __func__, ret); + Q2SPI_DEBUG(q2spi, "%s Err setting clks:%d\n", __func__, ret); return ERR_PTR(ret); } @@ -423,13 +439,19 @@ int check_gsi_transfer_completion_db_rx(struct q2spi_geni *q2spi) xfer_timeout = XFER_TIMEOUT_OFFSET; timeout = wait_for_completion_timeout(&q2spi->db_rx_cb, msecs_to_jiffies(xfer_timeout)); if (!timeout) { - Q2SPI_ERROR(q2spi, "%s Rx[%d] timeout%lu\n", __func__, i, timeout); + Q2SPI_DEBUG(q2spi, "%s Rx[%d] timeout%lu\n", __func__, i, timeout); ret = -ETIMEDOUT; - goto err_gsi_geni_transfer; } else { Q2SPI_DEBUG(q2spi, "%s rx completed\n", __func__); } -err_gsi_geni_transfer: + + if (q2spi->gsi->qup_gsi_err) { + ret = -EIO; + 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); + } return ret; } @@ -445,7 +467,7 @@ int check_gsi_transfer_completion(struct q2spi_geni *q2spi) timeout = wait_for_completion_timeout(&q2spi->tx_cb, msecs_to_jiffies(xfer_timeout)); if (!timeout) { - Q2SPI_ERROR(q2spi, "%s PID:%d Tx[%d] timeout\n", __func__, current->pid, i); + Q2SPI_DEBUG(q2spi, "%s PID:%d Tx[%d] timeout\n", __func__, current->pid, i); ret = -ETIMEDOUT; goto err_gsi_geni_transfer; } else { @@ -457,7 +479,7 @@ int check_gsi_transfer_completion(struct q2spi_geni *q2spi) timeout = wait_for_completion_timeout(&q2spi->rx_cb, msecs_to_jiffies(xfer_timeout)); if (!timeout) { - Q2SPI_ERROR(q2spi, "%s PID:%d Rx[%d] timeout\n", __func__, current->pid, i); + Q2SPI_DEBUG(q2spi, "%s PID:%d Rx[%d] timeout\n", __func__, current->pid, i); ret = -ETIMEDOUT; goto err_gsi_geni_transfer; } else { @@ -467,7 +489,7 @@ int check_gsi_transfer_completion(struct q2spi_geni *q2spi) err_gsi_geni_transfer: if (q2spi->gsi->qup_gsi_err || !timeout) { ret = -ETIMEDOUT; - Q2SPI_ERROR(q2spi, "%s Err QUP Gsi Error\n", __func__); + 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); @@ -506,6 +528,7 @@ int q2spi_setup_gsi_xfer(struct q2spi_packet *q2spi_pkt) q2spi->gsi->num_tx_eot = 0; q2spi->gsi->num_rx_eot = 0; q2spi->gsi->qup_gsi_err = false; + q2spi->gsi->qup_gsi_global_err = false; xfer_tx_sg = q2spi->gsi->tx_sg; xfer_rx_sg = q2spi->gsi->rx_sg; c0_tre = &q2spi->gsi->config0_tre; @@ -549,7 +572,7 @@ int q2spi_setup_gsi_xfer(struct q2spi_packet *q2spi_pkt) tx_tre = &q2spi->gsi->tx_dma_tre; tx_tre = setup_dma_tre(tx_tre, xfer->tx_dma, xfer->tx_len, q2spi, 1); if (IS_ERR_OR_NULL(tx_tre)) { - Q2SPI_ERROR(q2spi, "%s Err setting up tx tre\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err setting up tx tre\n", __func__); return -EINVAL; } sg_set_buf(xfer_tx_sg++, tx_tre, sizeof(*tx_tre)); @@ -558,7 +581,7 @@ int q2spi_setup_gsi_xfer(struct q2spi_packet *q2spi_pkt) q2spi->gsi->tx_desc = dmaengine_prep_slave_sg(q2spi->gsi->tx_c, q2spi->gsi->tx_sg, tx_nent, DMA_MEM_TO_DEV, flags); if (IS_ERR_OR_NULL(q2spi->gsi->tx_desc)) { - Q2SPI_ERROR(q2spi, "%s Err setting up tx desc\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err setting up tx desc\n", __func__); return -EIO; } q2spi->gsi->tx_ev.init.cb_param = q2spi_pkt; @@ -568,7 +591,7 @@ int q2spi_setup_gsi_xfer(struct q2spi_packet *q2spi_pkt) q2spi->gsi->tx_cookie = dmaengine_submit(q2spi->gsi->tx_desc); Q2SPI_DEBUG(q2spi, "%s Tx cb_param:%p\n", __func__, q2spi->gsi->tx_desc->callback_param); if (dma_submit_error(q2spi->gsi->tx_cookie)) { - Q2SPI_ERROR(q2spi, "%s Err dmaengine_submit failed (%d)\n", + Q2SPI_DEBUG(q2spi, "%s Err dmaengine_submit failed (%d)\n", __func__, q2spi->gsi->tx_cookie); dmaengine_terminate_all(q2spi->gsi->tx_c); return -EINVAL; @@ -578,14 +601,14 @@ int q2spi_setup_gsi_xfer(struct q2spi_packet *q2spi_pkt) rx_tre = &q2spi->gsi->rx_dma_tre; rx_tre = setup_dma_tre(rx_tre, xfer->rx_dma, xfer->rx_len, q2spi, 1); if (IS_ERR_OR_NULL(rx_tre)) { - Q2SPI_ERROR(q2spi, "%s Err setting up rx tre\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err setting up rx tre\n", __func__); return -EINVAL; } sg_set_buf(xfer_rx_sg, rx_tre, sizeof(*rx_tre)); q2spi->gsi->rx_desc = dmaengine_prep_slave_sg(q2spi->gsi->rx_c, q2spi->gsi->rx_sg, rx_nent, DMA_DEV_TO_MEM, flags); if (IS_ERR_OR_NULL(q2spi->gsi->rx_desc)) { - Q2SPI_ERROR(q2spi, "%s rx_desc fail\n", __func__); + Q2SPI_DEBUG(q2spi, "%s rx_desc fail\n", __func__); return -EIO; } q2spi->gsi->rx_ev.init.cb_param = q2spi_pkt; @@ -597,7 +620,7 @@ int q2spi_setup_gsi_xfer(struct q2spi_packet *q2spi_pkt) Q2SPI_DEBUG(q2spi, "%s Rx cb_param:%p\n", __func__, q2spi->gsi->rx_desc->callback_param); if (dma_submit_error(q2spi->gsi->rx_cookie)) { - Q2SPI_ERROR(q2spi, "%s Err dmaengine_submit failed (%d)\n", + Q2SPI_DEBUG(q2spi, "%s Err dmaengine_submit failed (%d)\n", __func__, q2spi->gsi->rx_cookie); dmaengine_terminate_all(q2spi->gsi->rx_c); return -EINVAL; @@ -606,7 +629,7 @@ int q2spi_setup_gsi_xfer(struct q2spi_packet *q2spi_pkt) rx_tre = &q2spi->gsi->rx_dma_tre; rx_tre = setup_dma_tre(rx_tre, xfer->rx_dma, xfer->rx_len, q2spi, 1); if (IS_ERR_OR_NULL(rx_tre)) { - Q2SPI_ERROR(q2spi, "%s Err setting up rx tre\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err setting up rx tre\n", __func__); return -EINVAL; } sg_set_buf(xfer_rx_sg, rx_tre, sizeof(*rx_tre)); @@ -614,7 +637,7 @@ int q2spi_setup_gsi_xfer(struct q2spi_packet *q2spi_pkt) q2spi->gsi->rx_sg, rx_nent, DMA_DEV_TO_MEM, flags); if (IS_ERR_OR_NULL(q2spi->gsi->db_rx_desc)) { - Q2SPI_ERROR(q2spi, "%s Err db_rx_desc fail\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err db_rx_desc fail\n", __func__); return -EIO; } q2spi->gsi->db_rx_desc->callback = q2spi_gsi_rx_callback; @@ -625,7 +648,7 @@ int q2spi_setup_gsi_xfer(struct q2spi_packet *q2spi_pkt) Q2SPI_DEBUG(q2spi, "%s DB cb_param:%p\n", __func__, q2spi->gsi->db_rx_desc->callback_param); if (dma_submit_error(q2spi->gsi->rx_cookie)) { - Q2SPI_ERROR(q2spi, "%s Err dmaengine_submit failed (%d)\n", + Q2SPI_DEBUG(q2spi, "%s Err dmaengine_submit failed (%d)\n", __func__, q2spi->gsi->rx_cookie); dmaengine_terminate_all(q2spi->gsi->rx_c); return -EINVAL; @@ -633,7 +656,7 @@ int q2spi_setup_gsi_xfer(struct q2spi_packet *q2spi_pkt) } if (cmd & Q2SPI_RX_ONLY) { Q2SPI_DEBUG(q2spi, "%s rx_c dma_async_issue_pending\n", __func__); - q2spi_dump_ipc(q2spi, q2spi->ipc, "GSI DMA-RX", (char *)xfer->rx_buf, tx_rx_len); + q2spi_dump_ipc(q2spi, "GSI DMA-RX", (char *)xfer->rx_buf, tx_rx_len); if (q2spi_pkt->m_cmd_param == Q2SPI_RX_ONLY) reinit_completion(&q2spi->db_rx_cb); else @@ -642,8 +665,8 @@ int q2spi_setup_gsi_xfer(struct q2spi_packet *q2spi_pkt) } if (cmd & Q2SPI_TX_ONLY) - q2spi_dump_ipc(q2spi, q2spi->ipc, "GSI DMA TX", (char *)xfer->tx_buf, - Q2SPI_HEADER_LEN + tx_rx_len); + q2spi_dump_ipc(q2spi, "GSI DMA TX", + (char *)xfer->tx_buf, Q2SPI_HEADER_LEN + tx_rx_len); Q2SPI_DEBUG(q2spi, "%s tx_c dma_async_issue_pending\n", __func__); reinit_completion(&q2spi->tx_cb); @@ -672,10 +695,10 @@ void q2spi_gsi_ch_ev_cb(struct dma_chan *ch, struct msm_gpi_cb const *cb, void * case MSM_GPI_QUP_PENDING_EVENT: case MSM_GPI_QUP_EOT_DESC_MISMATCH: case MSM_GPI_QUP_SW_ERROR: - Q2SPI_ERROR(q2spi, "%s cb_ev %d status %llu ts %llu count %llu\n", - __func__, cb->cb_event, cb->status, + Q2SPI_DEBUG(q2spi, "%s cb_ev %s status %llu ts %llu count %llu\n", + __func__, TO_GPI_CB_EVENT_STR(cb->cb_event), cb->status, cb->timestamp, cb->count); - Q2SPI_ERROR(q2spi, "%s err_routine:%u err_type:%u err.code%u\n", + Q2SPI_DEBUG(q2spi, "%s err_routine:%u err_type:%u err.code%u\n", __func__, cb->error_log.routine, cb->error_log.type, cb->error_log.error_code); q2spi->gsi->qup_gsi_err = true; @@ -683,8 +706,19 @@ void q2spi_gsi_ch_ev_cb(struct dma_chan *ch, struct msm_gpi_cb const *cb, void * complete_all(&q2spi->rx_cb); break; case MSM_GPI_QUP_CR_HEADER: + /* Update last access time of a device for autosuspend */ + pm_runtime_mark_last_busy(q2spi->dev); 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 || + q2spi_cr_hdr_event->code == Q2SPI_CR_HEADER_INCORRECT || + num_crs > MAX_RX_CRS) { + Q2SPI_DEBUG(q2spi, "%s Invalid num_crs:%d or Negative DB header code:%d\n", + __func__, num_crs, q2spi_cr_hdr_event->code); + q2spi->q2spi_cr_hdr_err = true; + break; + } + for (i = 0; i < num_crs; i++) { if (q2spi_cr_hdr_event->cr_hdr[i] == CR_ADDR_LESS_RD) { reinit_completion(&q2spi->sma_rd_comp); @@ -707,8 +741,9 @@ void q2spi_gsi_ch_ev_cb(struct dma_chan *ch, struct msm_gpi_cb const *cb, void * break; } - if (cb->cb_event == MSM_GPI_QUP_FW_ERROR) { - q2spi_geni_se_dump_regs(q2spi); - Q2SPI_ERROR(q2spi, "%s dump GSI regs\n", __func__); - } + if (cb->cb_event == MSM_GPI_QUP_ERROR) + q2spi->gsi->qup_gsi_global_err = true; + + if (q2spi->gsi->qup_gsi_err) + Q2SPI_DEBUG(q2spi, "%s set qup_gsi_err\n", __func__); } diff --git a/drivers/spi/q2spi-gsi.h b/drivers/spi/q2spi-gsi.h index 95285d15b21d..96de141a003b 100644 --- a/drivers/spi/q2spi-gsi.h +++ b/drivers/spi/q2spi-gsi.h @@ -50,6 +50,7 @@ * num_tx_eot: Represents number of TX End of Transfers * num_rx_eot: Represents number of RX End of Transfers * qup_gsi_err: flag to represent gsi error if any + * qup_gsi_global_err: flag to represent gsi global error */ struct q2spi_gsi { struct dma_chan *tx_c; @@ -74,6 +75,7 @@ struct q2spi_gsi { int num_tx_eot; int num_rx_eot; bool qup_gsi_err; + bool qup_gsi_global_err; }; #endif /* __SPI_Q2SPI_GPI_H_ */ diff --git a/drivers/spi/q2spi-msm-geni.c b/drivers/spi/q2spi-msm-geni.c index 0428b113ce6f..90138f3154dc 100644 --- a/drivers/spi/q2spi-msm-geni.c +++ b/drivers/spi/q2spi-msm-geni.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include "q2spi-msm.h" #include "q2spi-slave-reg.h" @@ -27,7 +27,7 @@ #define CREATE_TRACE_POINTS #include "q2spi-trace.h" -static int q2spi_slave_init(struct q2spi_geni *q2spi); +static int q2spi_slave_init(struct q2spi_geni *q2spi, bool slave_init); static int q2spi_gsi_submit(struct q2spi_packet *q2spi_pkt); static struct q2spi_geni *get_q2spi(struct device *dev); static int q2spi_geni_runtime_resume(struct device *dev); @@ -101,7 +101,6 @@ void __q2spi_dump_ipc(struct q2spi_geni *q2spi, char *prefix, /** * q2spi_dump_ipc - Log dump function for debugging * @q2spi: Pointer to main q2spi_geni structure - * @ipc_ctx: IPC context pointer to dump logs in IPC * @prefix: Prefix to use in log * @str: String to dump in log * @size: Size of data bytes per line @@ -110,13 +109,12 @@ void __q2spi_dump_ipc(struct q2spi_geni *q2spi, char *prefix, * * Return: none */ -void q2spi_dump_ipc(struct q2spi_geni *q2spi, void *ipc_ctx, char *prefix, - char *str, int size) +void q2spi_dump_ipc(struct q2spi_geni *q2spi, char *prefix, char *str, int size) { int offset = 0, total_bytes = size; if (!str) { - Q2SPI_ERROR(q2spi, "%s: Err str is NULL\n", __func__); + Q2SPI_DEBUG(q2spi, "%s: Err str is NULL\n", __func__); return; } @@ -406,19 +404,19 @@ static int q2spi_free_resp_buf(struct q2spi_geni *q2spi) static void q2spi_free_dma_buf(struct q2spi_geni *q2spi) { if (q2spi_free_bulk_buf(q2spi)) - Q2SPI_ERROR(q2spi, "%s Err free bulk buf fail\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err free bulk buf fail\n", __func__); if (q2spi_free_cr_buf(q2spi)) - Q2SPI_ERROR(q2spi, "%s Err free cr buf fail\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err free cr buf fail\n", __func__); if (q2spi_free_var5_buf(q2spi)) - Q2SPI_ERROR(q2spi, "%s Err free var5 buf fail\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err free var5 buf fail\n", __func__); if (q2spi_free_var1_buf(q2spi)) - Q2SPI_ERROR(q2spi, "%s Err free var1 buf fail\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err free var1 buf fail\n", __func__); if (q2spi_free_resp_buf(q2spi)) - Q2SPI_ERROR(q2spi, "%s Err free resp buf fail\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err free resp buf fail\n", __func__); } /** @@ -559,7 +557,7 @@ q2spi_unmap_dma_buf_used(struct q2spi_geni *q2spi, dma_addr_t tx_dma, dma_addr_t } } if (!unmapped) - Q2SPI_ERROR(q2spi, "%s PID:%d Err unmap fail for tx_dma:%p rx_dma:%p\n", + Q2SPI_DEBUG(q2spi, "%s PID:%d Err unmap fail for tx_dma:%p rx_dma:%p\n", __func__, current->pid, (void *)tx_dma, (void *)rx_dma); Q2SPI_DEBUG(q2spi, "%s End PID=%d\n", __func__, current->pid); } @@ -623,7 +621,7 @@ static int q2spi_get_doorbell_rx_buf(struct q2spi_geni *q2spi) } } - Q2SPI_ERROR(q2spi, "%s Err DB RX dma alloc failed\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err DB RX dma alloc failed\n", __func__); return -ENOMEM; } @@ -643,7 +641,7 @@ static void q2spi_unmap_rx_buf(struct q2spi_packet *q2spi_pkt) bool unmapped = false; if (!xfer->rx_buf || !xfer->rx_dma) { - Q2SPI_ERROR(q2spi, "%s Err RX buffer NULL\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err RX buffer NULL\n", __func__); return; } @@ -662,7 +660,7 @@ static void q2spi_unmap_rx_buf(struct q2spi_packet *q2spi_pkt) } } if (!unmapped) - Q2SPI_ERROR(q2spi, "%s PID:%d Err unmap fail for rx_dma:%p\n", + Q2SPI_DEBUG(q2spi, "%s PID:%d Err unmap fail for rx_dma:%p\n", __func__, current->pid, (void *)xfer->rx_dma); Q2SPI_DEBUG(q2spi, "%s End PID=%d\n", __func__, current->pid); } @@ -686,7 +684,7 @@ static int q2spi_get_rx_buf(struct q2spi_packet *q2spi_pkt, int len) Q2SPI_DEBUG(q2spi, "%s len:%d\n", __func__, len); if (!len) { - Q2SPI_ERROR(q2spi, "%s Err Zero length for alloc\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err Zero length for alloc\n", __func__); return -EINVAL; } @@ -702,7 +700,7 @@ static int q2spi_get_rx_buf(struct q2spi_packet *q2spi_pkt, int len) return 0; } } - Q2SPI_ERROR(q2spi, "%s: Err short of RX dma buffers\n", __func__); + Q2SPI_DEBUG(q2spi, "%s: Err short of RX dma buffers\n", __func__); return -ENOMEM; } @@ -782,7 +780,7 @@ static int q2spi_hrf_entry_format(struct q2spi_geni *q2spi, struct q2spi_request hrf_entry.type = HRF_ENTRY_TYPE; flow_id = q2spi_alloc_xfer_tid(q2spi); if (flow_id < 0) { - Q2SPI_ERROR(q2spi, "%s Err failed to alloc flow_id", __func__); + Q2SPI_DEBUG(q2spi, "%s Err failed to alloc flow_id", __func__); return -EINVAL; } hrf_entry.flow_id = flow_id; @@ -888,7 +886,7 @@ int q2spi_map_doorbell_rx_buf(struct q2spi_geni *q2spi) /* Alloc RX DMA buf and map to gsi so that SW can receive Doorbell */ ret = q2spi_get_doorbell_rx_buf(q2spi); if (ret) { - Q2SPI_ERROR(q2spi, "%s Err failed to alloc RX DMA buf", __func__); + Q2SPI_DEBUG(q2spi, "%s Err failed to alloc RX DMA buf", __func__); return ret; } @@ -903,7 +901,7 @@ int q2spi_map_doorbell_rx_buf(struct q2spi_geni *q2spi) Q2SPI_DEBUG(q2spi, "%s PID=%d acquired gsi_lock\n", __func__, current->pid); ret = q2spi_setup_gsi_xfer(q2spi_pkt); if (ret) { - Q2SPI_ERROR(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); mutex_unlock(&q2spi->gsi_lock); return ret; } @@ -953,6 +951,7 @@ void q2spi_doorbell(struct q2spi_geni *q2spi, if (q2spi_sys_restart) return; + atomic_set(&q2spi->slave_in_sleep, 0); memcpy(&q2spi->q2spi_cr_hdr_event, q2spi_cr_hdr_event, sizeof(struct qup_q2spi_cr_header_event)); queue_work(q2spi->doorbell_wq, &q2spi->q2spi_doorbell_work); @@ -1023,7 +1022,7 @@ struct q2spi_cr_packet *q2spi_prepare_cr_pkt(struct q2spi_geni *q2spi) q2spi_cr_pkt->bulk_pkt[i].cmd = q2spi_cr_pkt->cr_hdr[i].cmd; q2spi_cr_pkt->bulk_pkt[i].flow = q2spi_cr_pkt->cr_hdr[i].flow; q2spi_cr_pkt->bulk_pkt[i].parity = q2spi_cr_pkt->cr_hdr[i].parity; - q2spi_dump_ipc(q2spi, q2spi->ipc, "DB BULK DMA RX", + q2spi_dump_ipc(q2spi, "DB BULK DMA RX", (char *)ptr, q2spi->db_xfer->rx_len); q2spi_cr_pkt->bulk_pkt[i].status = ptr[0] & 0xF; q2spi_cr_pkt->bulk_pkt[i].flow_id = ptr[0] >> 4; @@ -1036,12 +1035,21 @@ struct q2spi_cr_packet *q2spi_prepare_cr_pkt(struct q2spi_geni *q2spi) (q2spi_cr_pkt->cr_hdr[i].cmd == ADDR_LESS_RD_ACCESS)) { memcpy((void *)&q2spi_cr_pkt->var3_pkt[i], (void *)ptr, sizeof(struct q2spi_client_dma_pkt)); - q2spi_dump_ipc(q2spi, q2spi->ipc, "DB VAR3 DMA RX", + q2spi_dump_ipc(q2spi, "DB VAR3 DMA RX", (char *)ptr, q2spi->db_xfer->rx_len); ptr += CR_DMA_DATA_SIZE; q2spi_cr_pkt->cr_hdr_type[i] = CR_HDR_VAR3; Q2SPI_DEBUG(q2spi, "%s i:%d cr_hdr_type:0x%x\n", __func__, i, q2spi_cr_pkt->cr_hdr_type[i]); + if (q2spi_cr_pkt->var3_pkt[i].arg1 == Q2SPI_CR_TRANSACTION_ERROR) { + Q2SPI_DEBUG(q2spi, "%s arg1:0x%x arg2:0x%x arg3:0x%x\n", + __func__, q2spi_cr_pkt->var3_pkt[i].arg1, + q2spi_cr_pkt->var3_pkt[i].arg2, + q2spi_cr_pkt->var3_pkt[i].arg3); + q2spi->q2spi_cr_txn_err = true; + spin_unlock_irqrestore(&q2spi->cr_queue_lock, flags); + return 0; + } Q2SPI_DEBUG(q2spi, "%s var3_pkt:%p var3_flow_id:%d\n", __func__, &q2spi_cr_pkt->var3_pkt[i], q2spi_cr_pkt->var3_pkt[i].flow_id); @@ -1107,15 +1115,16 @@ static int q2spi_open(struct inode *inode, struct file *filp) } mutex_lock(&q2spi->port_lock); + atomic_set(&q2spi->slave_in_sleep, 0); if (q2spi_geni_resources_on(q2spi)) { ret = -EIO; goto err; } /* Q2SPI slave HPG 2.1 Initialization */ - ret = q2spi_slave_init(q2spi); + ret = q2spi_slave_init(q2spi, false); if (ret) { - Q2SPI_ERROR(q2spi, "%s Err Failed to init q2spi slave %d\n", + Q2SPI_DEBUG(q2spi, "%s Err Failed to init q2spi slave %d\n", __func__, ret); goto err; } @@ -1123,12 +1132,15 @@ static int q2spi_open(struct inode *inode, struct file *filp) if (!q2spi->doorbell_setup) { ret = q2spi_map_doorbell_rx_buf(q2spi); if (ret) { - Q2SPI_ERROR(q2spi, "%s Err failed to alloc RX DMA buf\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err failed to alloc RX DMA buf\n", __func__); q2spi->port_release = true; goto err; } } filp->private_data = q2spi; + q2spi->q2spi_cr_txn_err = false; + q2spi->q2spi_sleep_cmd_enable = false; + q2spi->q2spi_cr_hdr_err = false; Q2SPI_DEBUG(q2spi, "%s End PID:%d, allocs:%d\n", __func__, current->pid, atomic_read(&q2spi->alloc_count)); err: @@ -1153,7 +1165,7 @@ static inline void *q2spi_get_variant_buf(struct q2spi_geni *q2spi, int i; if (vtype != VARIANT_1_LRA && vtype != VARIANT_5) { - Q2SPI_ERROR(q2spi, "%s Err Invalid variant:%d!\n", __func__, vtype); + Q2SPI_DEBUG(q2spi, "%s Err Invalid variant:%d!\n", __func__, vtype); return NULL; } @@ -1185,7 +1197,7 @@ static inline void *q2spi_get_variant_buf(struct q2spi_geni *q2spi, return (void *)q2spi->var5_buf[i]; } } - Q2SPI_ERROR(q2spi, "%s Err Short of buffers for variant:%d!\n", __func__, vtype); + Q2SPI_DEBUG(q2spi, "%s Err Short of buffers for variant:%d!\n", __func__, vtype); return NULL; } @@ -1292,7 +1304,7 @@ int q2spi_frame_lra(struct q2spi_geni *q2spi, struct q2spi_request q2spi_req, if (!q2spi_req.flow_id && !q2spi->hrf_flow) { ret = q2spi_alloc_xfer_tid(q2spi); if (ret < 0) { - Q2SPI_ERROR(q2spi, "%s Err failed to alloc xfer_tid\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err failed to alloc xfer_tid\n", __func__); return -EINVAL; } q2spi_hc_var1->flow_id = ret; @@ -1337,7 +1349,7 @@ int q2spi_sma_format(struct q2spi_geni *q2spi, struct q2spi_request q2spi_req, q2spi_hc_var5 = (struct q2spi_host_variant4_5_pkt *) q2spi_get_variant_buf(q2spi, q2spi_pkt, VARIANT_5); if (!q2spi_hc_var5) { - Q2SPI_ERROR(q2spi, "%s Err var5 buffer is not available\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err var5 buffer is not available\n", __func__); return -ENOMEM; } memset(q2spi_hc_var5->data_buf, 0xba, 4096); @@ -1369,9 +1381,9 @@ int q2spi_sma_format(struct q2spi_geni *q2spi, struct q2spi_request q2spi_req, q2spi_req.data_len = sizeof(q2spi_hc_var5->data_buf) <= q2spi_req.data_len ? sizeof(q2spi_hc_var5->data_buf) : q2spi_req.data_len; memcpy(q2spi_hc_var5->data_buf, q2spi_req.data_buff, q2spi_req.data_len); - q2spi_dump_ipc(q2spi, q2spi->ipc, "sma format q2spi_req data_buf", + q2spi_dump_ipc(q2spi, "sma format q2spi_req data_buf", (char *)q2spi_req.data_buff, q2spi_req.data_len); - q2spi_dump_ipc(q2spi, q2spi->ipc, "sma format var5 data_buf", + q2spi_dump_ipc(q2spi, "sma format var5 data_buf", (char *)q2spi_hc_var5->data_buf, q2spi_req.data_len); q2spi_kfree(q2spi, q2spi_req.data_buff, __LINE__); q2spi_req.data_buff = NULL; @@ -1397,7 +1409,7 @@ int q2spi_sma_format(struct q2spi_geni *q2spi, struct q2spi_request q2spi_req, if (!q2spi_req.flow_id && !q2spi->hrf_flow) { flow_id = q2spi_alloc_xfer_tid(q2spi); if (flow_id < 0) { - Q2SPI_ERROR(q2spi, "%s Err failed to alloc tid", __func__); + Q2SPI_DEBUG(q2spi, "%s Err failed to alloc tid", __func__); return -EINVAL; } q2spi_hc_var5->flow_id = flow_id; @@ -1416,7 +1428,7 @@ int q2spi_sma_format(struct q2spi_geni *q2spi, struct q2spi_request q2spi_req, Q2SPI_DEBUG(q2spi, "%s flow id:%d q2spi_pkt:%p pkt_var1:%p pkt_tx_dma:%p var5_pkt:%p\n", __func__, q2spi_hc_var5->flow_id, q2spi_pkt, q2spi_pkt->var1_pkt, (void *)q2spi_pkt->var5_tx_dma, q2spi_pkt->var5_pkt); - q2spi_dump_ipc(q2spi, q2spi->ipc, "sma format var5(2) data_buf", + q2spi_dump_ipc(q2spi, "sma format var5(2) data_buf", (char *)q2spi_hc_var5->data_buf, q2spi_req.data_len); return q2spi_hc_var5->flow_id; } @@ -1428,7 +1440,7 @@ static int q2spi_abort_command(struct q2spi_geni *q2spi, struct q2spi_request q2 struct q2spi_packet *q2spi_pkt; if (!q2spi) { - Q2SPI_ERROR(q2spi, "%s Err Invalid q2spi\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err Invalid q2spi\n", __func__); return -EINVAL; } Q2SPI_DEBUG(q2spi, "%s cmd:%d addr:%d flow_id:%d data_len:%d\n", @@ -1494,10 +1506,11 @@ static int q2spi_soft_reset(struct q2spi_geni *q2spi, struct q2spi_request q2spi void q2spi_notify_data_avail_for_client(struct q2spi_geni *q2spi) { - Q2SPI_DEBUG(q2spi, "%s wake userspace\n", __func__); atomic_inc(&q2spi->rx_avail); wake_up_interruptible(&q2spi->readq); wake_up(&q2spi->read_wq); + Q2SPI_DEBUG(q2spi, "%s wake userspace rx_avail:%d\n", __func__, + atomic_read(&q2spi->rx_avail)); } int q2spi_hrf_sleep(struct q2spi_geni *q2spi, struct q2spi_request q2spi_req, @@ -1509,7 +1522,7 @@ int q2spi_hrf_sleep(struct q2spi_geni *q2spi, struct q2spi_request q2spi_req, ret = q2spi_hrf_entry_format_sleep(q2spi, q2spi_req, &q2spi_hrf_req); if (ret < 0) { - Q2SPI_ERROR(q2spi, "%s Err q2spi_hrf_entry_format failed ret:%d\n", __func__, ret); + Q2SPI_DEBUG(q2spi, "%s Err q2spi_hrf_entry_format failed ret:%d\n", __func__, ret); return ret; } Q2SPI_DEBUG(q2spi, "%s hrf_req cmd:%d flow_id:%d data_buff:%p\n", @@ -1519,7 +1532,7 @@ int q2spi_hrf_sleep(struct q2spi_geni *q2spi, struct q2spi_request q2spi_req, Q2SPI_DEBUG(q2spi, "%s q2spi_hrf_req:%p q2spi_pkt:%p\n", __func__, q2spi_hrf_req, q2spi_pkt); if (ret < 0) { - Q2SPI_ERROR(q2spi, "%s Err q2spi_frame_lra failed ret:%d\n", __func__, ret); + Q2SPI_DEBUG(q2spi, "%s Err q2spi_frame_lra failed ret:%d\n", __func__, ret); return ret; } list_add_tail(&q2spi_pkt->list, &q2spi->tx_queue_list); @@ -1540,7 +1553,7 @@ int q2spi_hrf_flow(struct q2spi_geni *q2spi, struct q2spi_request q2spi_req, q2spi->hrf_flow = true; ret = q2spi_hrf_entry_format(q2spi, q2spi_req, &q2spi_hrf_req); if (ret < 0) { - Q2SPI_ERROR(q2spi, "%s Err q2spi_hrf_entry_format failed ret:%d\n", __func__, ret); + Q2SPI_DEBUG(q2spi, "%s Err q2spi_hrf_entry_format failed ret:%d\n", __func__, ret); return ret; } @@ -1553,7 +1566,7 @@ int q2spi_hrf_flow(struct q2spi_geni *q2spi, struct q2spi_request q2spi_req, Q2SPI_DEBUG(q2spi, "%s q2spi_hrf_req:%p q2spi_pkt:%p\n", __func__, q2spi_hrf_req, q2spi_pkt); if (ret < 0) { - Q2SPI_ERROR(q2spi, "%s Err q2spi_frame_lra failed ret:%d\n", __func__, ret); + Q2SPI_DEBUG(q2spi, "%s Err q2spi_frame_lra failed ret:%d\n", __func__, ret); return ret; } @@ -1658,6 +1671,11 @@ int q2spi_add_req_to_tx_queue(struct q2spi_geni *q2spi, struct q2spi_request q2s struct q2spi_packet *q2spi_pkt = NULL; int ret = -EINVAL; + if (q2spi->port_release) { + Q2SPI_DEBUG(q2spi, "%s Err Port in closed state, return\n", __func__); + return -ENOENT; + } + q2spi_tx_queue_status(q2spi); q2spi_print_req_cmd(q2spi, q2spi_req); if (q2spi_req.cmd == LOCAL_REG_READ || q2spi_req.cmd == LOCAL_REG_WRITE) { @@ -1711,7 +1729,7 @@ int q2spi_add_req_to_tx_queue(struct q2spi_geni *q2spi, struct q2spi_request q2s return ret; } } else { - Q2SPI_ERROR(q2spi, "%s Err cmd:%d\n", __func__, q2spi_req.cmd); + Q2SPI_DEBUG(q2spi, "%s Err cmd:%d\n", __func__, q2spi_req.cmd); return -EINVAL; } @@ -1780,19 +1798,26 @@ static int q2spi_wakeup_hw_from_sleep(struct q2spi_geni *q2spi) long timeout = 0; int ret = 0; + if (q2spi->q2spi_cr_txn_err || q2spi->q2spi_cr_hdr_err) { + q2spi_transfer_abort(q2spi); + q2spi->q2spi_cr_txn_err = false; + q2spi->q2spi_cr_hdr_err = false; + return 0; + } + xfer_timeout = msecs_to_jiffies(EXT_CR_TIMEOUT_MSECS); reinit_completion(&q2spi->wait_for_ext_cr); /* Send gpio wakeup signal on q2spi lines to hw */ Q2SPI_DEBUG(q2spi, "%s Send wakeup_hw to wakeup client\n", __func__); - ret = q2spi_wakeup_hw_through_gpio(q2spi); + ret = q2spi_wakeup_slave_through_gpio(q2spi); if (ret) { - Q2SPI_ERROR(q2spi, "%s Err q2spi_wakeup_hw_through_gpio\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err q2spi_wakeup_slave_through_gpio\n", __func__); return ret; } Q2SPI_DEBUG(q2spi, "%s Waiting for Extended CR\n", __func__); timeout = wait_for_completion_interruptible_timeout(&q2spi->wait_for_ext_cr, xfer_timeout); if (timeout <= 0) { - Q2SPI_ERROR(q2spi, "%s Err timeout %ld for Extended CR\n", __func__, timeout); + Q2SPI_DEBUG(q2spi, "%s Err timeout %ld for Extended CR\n", __func__, timeout); if (timeout == -ERESTARTSYS) { q2spi_sys_restart = true; return -ERESTARTSYS; @@ -1820,7 +1845,7 @@ static int q2spi_wakeup_hw_from_sleep(struct q2spi_geni *q2spi) static int __q2spi_transfer(struct q2spi_geni *q2spi, struct q2spi_request q2spi_req, struct q2spi_packet *q2spi_pkt, size_t len) { - unsigned long xfer_timeout = msecs_to_jiffies(XFER_TIMEOUT_OFFSET); + unsigned long xfer_timeout = 0; long timeout = 0; int ret = 0; @@ -1829,9 +1854,23 @@ static int __q2spi_transfer(struct q2spi_geni *q2spi, struct q2spi_request q2spi return -EINVAL; } + if (q2spi->port_release) { + Q2SPI_DEBUG(q2spi, "%s Err Port in closed state, return 0 for user to retry\n", + __func__); + return -ENOENT; + } + + Q2SPI_DEBUG(q2spi, "%s is slave_in_sleep:%d\n", + __func__, atomic_read(&q2spi->slave_in_sleep)); + ret = __q2spi_send_messages(q2spi, (void *)q2spi_pkt); if (ret == -ETIMEDOUT) { return -ETIMEDOUT; + } else if (ret == -EAGAIN && atomic_read(&q2spi->retry)) { + atomic_dec(&q2spi->retry); + Q2SPI_DEBUG(q2spi, "%s q2spi_pkt:%p CR Doorbell Pending try again\n", + __func__, q2spi_pkt); + return 0; } else if (ret) { Q2SPI_DEBUG(q2spi, "%s q2spi_pkt:%p __q2spi_send_messages ret:%d\n", __func__, q2spi_pkt, ret); @@ -1842,7 +1881,7 @@ static int __q2spi_transfer(struct q2spi_geni *q2spi, struct q2spi_request q2spi if (q2spi_pkt->vtype == VARIANT_5_HRF) { ret = q2spi_process_hrf_flow_after_lra(q2spi, q2spi_pkt); if (ret) { - Q2SPI_ERROR(q2spi, "%s Err hrf_flow sma write fail ret %d\n", + Q2SPI_DEBUG(q2spi, "%s Err hrf_flow sma write fail ret %d\n", __func__, ret); q2spi_unmap_var_bufs(q2spi, q2spi_pkt); return ret; @@ -1857,24 +1896,18 @@ static int __q2spi_transfer(struct q2spi_geni *q2spi, struct q2spi_request q2spi if (q2spi_req.cmd == HRF_WRITE) { /* HRF_WRITE */ + xfer_timeout = msecs_to_jiffies(XFER_TIMEOUT_OFFSET); Q2SPI_DEBUG(q2spi, "%s q2spi_pkt:%p waiting for bulk_wait\n", __func__, q2spi_pkt); timeout = wait_for_completion_interruptible_timeout (&q2spi_pkt->bulk_wait, xfer_timeout); if (timeout <= 0) { - Q2SPI_ERROR(q2spi, "%s q2spi_pkt:%p Err timeout %ld for bulk_wait\n", + Q2SPI_DEBUG(q2spi, "%s q2spi_pkt:%p Err timeout %ld for bulk_wait\n", __func__, q2spi_pkt, timeout); if (timeout == -ERESTARTSYS) { q2spi_sys_restart = true; return -ERESTARTSYS; } return -ETIMEDOUT; - } else if (atomic_read(&q2spi->retry)) { - atomic_dec(&q2spi->retry); - Q2SPI_DEBUG(q2spi, "%s q2spi_pkt:%p CR Doorbell Pending try again\n", - __func__, q2spi_pkt); - if (atomic_read(&q2spi->doorbell_pending)) - usleep_range(5000, 10000); - return 0; } Q2SPI_DEBUG(q2spi, "%s q2spi_pkt:%p bulk_wait completed wait DB clear\n", __func__, q2spi_pkt); @@ -1913,9 +1946,15 @@ static int q2spi_transfer_with_retries(struct q2spi_geni *q2spi, struct q2spi_re int flow_id, void *user_buf) { void *data_buf; - int i, ret = 0; + int i, ret = 0, retry_count = Q2SPI_MAX_TX_RETRIES; - for (i = 0; i <= Q2SPI_MAX_TX_RETRIES; i++) { + if (q2spi_req.cmd == LOCAL_REG_READ) + retry_count = 0; + + for (i = 0; i <= retry_count; i++) { + /* Reset 100msec client sleep timer */ + mod_timer(&q2spi->slave_sleep_timer, + jiffies + msecs_to_jiffies(Q2SPI_SLAVE_SLEEP_TIME_MSECS)); ret = __q2spi_transfer(q2spi, q2spi_req, cur_q2spi_pkt, len); Q2SPI_DEBUG(q2spi, "%s flow_id:%d ret:%d\n", __func__, flow_id, ret); q2spi_free_xfer_tid(q2spi, flow_id); @@ -1932,13 +1971,7 @@ static int q2spi_transfer_with_retries(struct q2spi_geni *q2spi, struct q2spi_re q2spi->hw_state_is_bad = true; q2spi_dump_client_error_regs(q2spi); } - pm_runtime_mark_last_busy(q2spi->dev); - Q2SPI_DEBUG(q2spi, "%s PM put_autosuspend count:%d line:%d\n", __func__, - atomic_read(&q2spi->dev->power.usage_count), __LINE__); - pm_runtime_put_autosuspend(q2spi->dev); - Q2SPI_DEBUG(q2spi, "%s PM after put_autosuspend count:%d\n", __func__, - atomic_read(&q2spi->dev->power.usage_count)); - return ret; + goto pm_put_exit; } else if (ret == -ERESTARTSYS) { Q2SPI_DEBUG(q2spi, "%s system is in restart\n", __func__); return ret; @@ -1946,22 +1979,29 @@ static int q2spi_transfer_with_retries(struct q2spi_geni *q2spi, struct q2spi_re /* 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); + 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) { ret = q2spi_wakeup_hw_from_sleep(q2spi); if (ret) { - Q2SPI_ERROR(q2spi, "%s Err q2spi_wakeup_hw_from_sleep\n", + Q2SPI_DEBUG(q2spi, "%s Err q2spi_wakeup_hw_from_sleep\n", __func__); - pm_runtime_mark_last_busy(q2spi->dev); - pm_runtime_put_autosuspend(q2spi->dev); - Q2SPI_DEBUG(q2spi, "%s PM after put_autosuspend cnt:%d\n", - __func__, - atomic_read(&q2spi->dev->power.usage_count)); - return ret; + goto pm_put_exit; } } + q2spi->q2spi_cr_txn_err = false; + q2spi->q2spi_cr_hdr_err = false; + /* Reset 100msec client sleep timer */ + mod_timer(&q2spi->slave_sleep_timer, + jiffies + msecs_to_jiffies(Q2SPI_SLAVE_SLEEP_TIME_MSECS)); /* Should not perform SOFT RESET when UWB sets reserved[0] bit 0 set */ - if (!(q2spi_req.reserved[0] & BIT(0)) && i == 1) + if (!q2spi->q2spi_cr_txn_err && + (!(q2spi_req.reserved[0] & Q2SPI_SOFT_RESET_CMD_BIT)) && i == 1) q2spi_transfer_soft_reset(q2spi); cur_q2spi_pkt->state = IN_DELETION; @@ -1973,23 +2013,15 @@ static int q2spi_transfer_with_retries(struct q2spi_geni *q2spi, struct q2spi_re data_buf = q2spi_kzalloc(q2spi, q2spi_req.data_len, __LINE__); if (!data_buf) { Q2SPI_DEBUG(q2spi, "%s Err buf2 alloc failed\n", __func__); - pm_runtime_mark_last_busy(q2spi->dev); - pm_runtime_put_autosuspend(q2spi->dev); - Q2SPI_DEBUG(q2spi, "%s PM after put_autosuspend count:%d\n", - __func__, - atomic_read(&q2spi->dev->power.usage_count)); - return -ENOMEM; + ret = -ENOMEM; + goto pm_put_exit; } if (copy_from_user(data_buf, user_buf, q2spi_req.data_len)) { Q2SPI_DEBUG(q2spi, "%s Err copy_from_user to buf2 failed\n", __func__); q2spi_kfree(q2spi, data_buf, __LINE__); - pm_runtime_mark_last_busy(q2spi->dev); - pm_runtime_put_autosuspend(q2spi->dev); - Q2SPI_DEBUG(q2spi, "%s PM after put_autosuspend count:%d\n", - __func__, - atomic_read(&q2spi->dev->power.usage_count)); - return -EFAULT; + ret = -EFAULT; + goto pm_put_exit; } q2spi_req.data_buff = data_buf; } @@ -2000,7 +2032,8 @@ static int q2spi_transfer_with_retries(struct q2spi_geni *q2spi, struct q2spi_re q2spi_kfree(q2spi, data_buf, __LINE__); Q2SPI_DEBUG(q2spi, "%s Err Failed to add tx req to queue ret:%d\n", __func__, flow_id); - return -ENOMEM; + ret = -ENOMEM; + goto pm_put_exit; } Q2SPI_DEBUG(q2spi, "%s cur_q2spi_pkt=%p\n", __func__, cur_q2spi_pkt); } else { @@ -2012,6 +2045,7 @@ transfer_exit: cur_q2spi_pkt->state = IN_DELETION; q2spi_del_pkt_from_tx_queue(q2spi, cur_q2spi_pkt); q2spi_free_q2spi_pkt(cur_q2spi_pkt, __LINE__); +pm_put_exit: pm_runtime_mark_last_busy(q2spi->dev); Q2SPI_DEBUG(q2spi, "%s PM put_autosuspend count:%d line:%d\n", __func__, atomic_read(&q2spi->dev->power.usage_count), __LINE__); @@ -2021,6 +2055,38 @@ transfer_exit: return ret; } +/* + * q2spi_transfer_abort - Add Abort request in tx_queue list and submit q2spi transfer + * @q2spi: Pointer to main q2spi_geni structure + * + * Return: 0 on success. Error code on failure. + */ +void q2spi_transfer_abort(struct q2spi_geni *q2spi) +{ + struct q2spi_packet *cur_q2spi_abort_pkt; + struct q2spi_request abort_request; + int ret = 0; + + Q2SPI_DEBUG(q2spi, "%s ABORT\n", __func__); + abort_request.cmd = ABORT; + abort_request.sync = 1; + mutex_lock(&q2spi->queue_lock); + ret = q2spi_add_req_to_tx_queue(q2spi, abort_request, &cur_q2spi_abort_pkt); + mutex_unlock(&q2spi->queue_lock); + if (ret < 0) { + Q2SPI_DEBUG(q2spi, "%s Err q2spi_add_req_to_tx_queue ret:%d\n", __func__, ret); + return; + } + __q2spi_transfer(q2spi, abort_request, cur_q2spi_abort_pkt, 0); + if (ret) + Q2SPI_DEBUG(q2spi, "%s __q2spi_transfer q2spi_pkt:%p ret%d\n", + __func__, cur_q2spi_abort_pkt, ret); + cur_q2spi_abort_pkt->state = IN_DELETION; + q2spi_del_pkt_from_tx_queue(q2spi, cur_q2spi_abort_pkt); + q2spi_kfree(q2spi, cur_q2spi_abort_pkt->xfer, __LINE__); + cur_q2spi_abort_pkt->xfer = NULL; +} + /* * q2spi_transfer_soft_reset - Add soft-reset request in tx_queue list and submit q2spi transfer * @@ -2034,16 +2100,20 @@ void q2spi_transfer_soft_reset(struct q2spi_geni *q2spi) struct q2spi_request soft_reset_request; int ret = 0; + Q2SPI_DEBUG(q2spi, "%s SOFT_RESET\n", __func__); soft_reset_request.cmd = SOFT_RESET; soft_reset_request.sync = 1; mutex_lock(&q2spi->queue_lock); ret = q2spi_add_req_to_tx_queue(q2spi, soft_reset_request, &cur_q2spi_sr_pkt); mutex_unlock(&q2spi->queue_lock); if (ret < 0) { - Q2SPI_ERROR(q2spi, "%s Err q2spi_add_req_to_tx_queue ret:%d\n", __func__, ret); + Q2SPI_DEBUG(q2spi, "%s Err q2spi_add_req_to_tx_queue ret:%d\n", __func__, ret); return; } __q2spi_transfer(q2spi, soft_reset_request, cur_q2spi_sr_pkt, 0); + if (ret) + Q2SPI_DEBUG(q2spi, "%s __q2spi_transfer q2spi_pkt:%p ret%d\n", + __func__, cur_q2spi_sr_pkt, ret); cur_q2spi_sr_pkt->state = IN_DELETION; q2spi_del_pkt_from_tx_queue(q2spi, cur_q2spi_sr_pkt); q2spi_kfree(q2spi, cur_q2spi_sr_pkt->xfer, __LINE__); @@ -2107,6 +2177,13 @@ static int q2spi_transfer_check(struct q2spi_geni *q2spi, struct q2spi_request * Q2SPI_DEBUG(q2spi, "%s Err Invalid address:%x\n", __func__, q2spi_req->addr); return -EINVAL; } + + if (q2spi_req->reserved[0] & Q2SPI_SLEEP_CMD_BIT) { + Q2SPI_DEBUG(q2spi, "%s allow_sleep\n", __func__); + q2spi->q2spi_sleep_cmd_enable = true; + } else { + q2spi->q2spi_sleep_cmd_enable = false; + } return 0; } @@ -2135,7 +2212,6 @@ static ssize_t q2spi_transfer(struct file *filp, const char __user *buf, size_t } q2spi = filp->private_data; Q2SPI_DEBUG(q2spi, "%s Enter PID=%d\n", __func__, current->pid); - q2spi_wait_for_doorbell_setup_ready(q2spi); mutex_lock(&q2spi->port_lock); ret = q2spi_transfer_check(q2spi, &q2spi_req, buf, len); @@ -2166,8 +2242,7 @@ static ssize_t q2spi_transfer(struct file *filp, const char __user *buf, size_t goto err; } user_buf = q2spi_req.data_buff; - q2spi_dump_ipc(q2spi, q2spi->ipc, "q2spi_transfer", (char *)data_buf, - q2spi_req.data_len); + q2spi_dump_ipc(q2spi, "q2spi_transfer", (char *)data_buf, q2spi_req.data_len); q2spi_req.data_buff = data_buf; } @@ -2180,19 +2255,21 @@ static ssize_t q2spi_transfer(struct file *filp, const char __user *buf, size_t atomic_read(&q2spi->dev->power.usage_count)); ret = pm_runtime_get_sync(q2spi->dev); if (ret < 0) { - Q2SPI_ERROR(q2spi, "%s Err for PM get\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err for PM get\n", __func__); pm_runtime_put_noidle(q2spi->dev); pm_runtime_set_suspended(q2spi->dev); goto err; } 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); mutex_lock(&q2spi->queue_lock); reinit_completion(&q2spi->sma_wr_comp); flow_id = q2spi_add_req_to_tx_queue(q2spi, q2spi_req, &cur_q2spi_pkt); mutex_unlock(&q2spi->queue_lock); if (flow_id < 0) { - q2spi_kfree(q2spi, data_buf, __LINE__); + if (q2spi_req.data_buff) + q2spi_kfree(q2spi, data_buf, __LINE__); Q2SPI_DEBUG(q2spi, "%s Err Failed to add tx request ret:%d\n", __func__, flow_id); pm_runtime_mark_last_busy(q2spi->dev); pm_runtime_put_autosuspend(q2spi->dev); @@ -2230,7 +2307,6 @@ static ssize_t q2spi_response(struct file *filp, char __user *buf, size_t count, q2spi = filp->private_data; Q2SPI_DEBUG(q2spi, "%s Enter PID=%d\n", __func__, current->pid); - mutex_lock(&q2spi->port_lock); if (q2spi->hw_state_is_bad) { Q2SPI_DEBUG(q2spi, "%s Err Retries failed, check HW state\n", __func__); ret = -EPIPE; @@ -2247,7 +2323,7 @@ static ssize_t q2spi_response(struct file *filp, char __user *buf, size_t count, atomic_read(&q2spi->dev->power.usage_count)); ret = pm_runtime_get_sync(q2spi->dev); if (ret < 0) { - Q2SPI_ERROR(q2spi, "%s Err for PM get\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err for PM get\n", __func__); pm_runtime_put_noidle(q2spi->dev); pm_runtime_set_suspended(q2spi->dev); goto err; @@ -2261,7 +2337,8 @@ static ssize_t q2spi_response(struct file *filp, char __user *buf, size_t count, goto err; } - Q2SPI_DEBUG(q2spi, "%s waiting on wait_event_interruptible\n", __func__); + Q2SPI_DEBUG(q2spi, "%s waiting on wait_event_interruptible rx_avail:%d\n", + __func__, atomic_read(&q2spi->rx_avail)); /* Wait for Rx data available with timeout */ timeout = wait_event_interruptible_timeout(q2spi->read_wq, atomic_read(&q2spi->rx_avail), msecs_to_jiffies(Q2SPI_RESPONSE_WAIT_TIMEOUT)); @@ -2271,7 +2348,6 @@ static ssize_t q2spi_response(struct file *filp, char __user *buf, size_t count, goto err; } atomic_dec(&q2spi->rx_avail); - Q2SPI_DEBUG(q2spi, "%s wait unblocked ret:%d\n", __func__, ret); mutex_lock(&q2spi->queue_lock); list_for_each_entry_safe(q2spi_pkt_tmp1, q2spi_pkt_tmp2, &q2spi->tx_queue_list, list) { if (q2spi_pkt_tmp1->state == DATA_AVAIL) { @@ -2325,12 +2401,12 @@ static ssize_t q2spi_response(struct file *filp, char __user *buf, size_t count, __func__, cr_request.data_len, cr_request.end_point, cr_request.proto_ind, cr_request.cmd, cr_request.status, cr_request.flow_id); if (!q2spi_pkt->xfer || !q2spi_pkt->xfer->rx_buf) { - Q2SPI_ERROR(q2spi, "%s Err q2spi_pkt rx_buf is NULL\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err q2spi_pkt rx_buf is NULL\n", __func__); ret = -EAGAIN; goto err; } - q2spi_dump_ipc(q2spi, q2spi->ipc, "q2spi_response", + q2spi_dump_ipc(q2spi, "q2spi_response", (char *)q2spi_pkt->xfer->rx_buf, cr_request.data_len); ret = copy_to_user(buf, &cr_request, sizeof(struct q2spi_client_request)); if (ret) { @@ -2363,7 +2439,6 @@ static ssize_t q2spi_response(struct file *filp, char __user *buf, size_t count, atomic_read(&q2spi->dev->power.usage_count)); err: Q2SPI_DEBUG(q2spi, "%s End ret:%d PID=%d", __func__, ret, current->pid); - mutex_unlock(&q2spi->port_lock); return ret; } @@ -2400,18 +2475,19 @@ static void q2spi_flush_pending_crs(struct q2spi_geni *q2spi) { struct q2spi_packet *q2spi_pkt = NULL, *q2spi_pkt_tmp; - Q2SPI_INFO(q2spi, "%s: PID=%d\n", __func__, current->pid); + Q2SPI_DEBUG(q2spi, "%s: PID=%d\n", __func__, current->pid); /* Delay to ensure any pending CRs in progress are consumed */ usleep_range(10000, 20000); q2spi_tx_queue_status(q2spi); mutex_lock(&q2spi->queue_lock); list_for_each_entry_safe(q2spi_pkt, q2spi_pkt_tmp, &q2spi->tx_queue_list, list) { - if (q2spi_pkt->state == DATA_AVAIL) { + if (q2spi_pkt->state == DATA_AVAIL || q2spi_pkt->state == IN_USE) { Q2SPI_DEBUG(q2spi, "%s q2spi_pkt %p data avail, force delete\n", __func__, q2spi_pkt); q2spi_unmap_rx_buf(q2spi_pkt); q2spi_pkt->state = IN_DELETION; + atomic_dec(&q2spi->rx_avail); list_del(&q2spi_pkt->list); q2spi_free_q2spi_pkt(q2spi_pkt, __LINE__); } else { @@ -2424,6 +2500,7 @@ static void q2spi_flush_pending_crs(struct q2spi_geni *q2spi) static int q2spi_release(struct inode *inode, struct file *filp) { + int retries = Q2SPI_RESP_BUF_RETRIES; struct q2spi_geni *q2spi; int ret = 0; @@ -2439,29 +2516,39 @@ static int q2spi_release(struct inode *inode, struct file *filp) Q2SPI_DEBUG(q2spi, "%s PID:%d allocs:%d\n", __func__, current->pid, atomic_read(&q2spi->alloc_count)); mutex_lock(&q2spi->port_lock); + del_timer_sync(&q2spi->slave_sleep_timer); atomic_set(&q2spi->sma_wr_pending, 0); atomic_set(&q2spi->sma_rd_pending, 0); - if (q2spi->hw_state_is_bad) { - Q2SPI_DEBUG(q2spi, "%s Err check HW state\n", __func__); - mutex_unlock(&q2spi->port_lock); - return -EPIPE; + q2spi->hw_state_is_bad = false; + + if (mutex_is_locked(&q2spi->send_msgs_lock)) { + Q2SPI_DEBUG(q2spi, "%s q2spi_transfer is in progress\n", __func__); + usleep_range(200000, 250000); } - ret = pm_runtime_get_sync(q2spi->dev); - if (ret < 0) - Q2SPI_ERROR(q2spi, "%s Err for PM get ret:%d\n", __func__, ret); - - q2spi->port_release = true; q2spi_flush_pending_crs(q2spi); + atomic_set(&q2spi->rx_avail, 0); q2spi->doorbell_setup = false; - q2spi_geni_resources_off(q2spi); q2spi_tx_queue_status(q2spi); atomic_set(&q2spi->doorbell_pending, 0); + atomic_set(&q2spi->retry, 0); + while (retries--) { + if (q2spi->sys_mem_read_in_progress) { + /* sleep sometime to complete pending system memory read requests */ + usleep_range(150000, 200000); + } else { + break; + } + } mutex_unlock(&q2spi->port_lock); - ret = pm_runtime_put_sync_suspend(q2spi->dev); - Q2SPI_DEBUG(q2spi, "%s PM put sync suspend ret:%d\n", __func__, ret); + if (!atomic_read(&q2spi->is_suspend)) { + ret = pm_runtime_suspend(q2spi->dev); + Q2SPI_DEBUG(q2spi, "%s suspend ret:%d sys_mem_read_in_progress:%d\n", + __func__, ret, q2spi->sys_mem_read_in_progress); + } + q2spi->port_release = true; ret = pinctrl_select_state(q2spi->geni_pinctrl, q2spi->geni_gpio_shutdown); if (ret) { @@ -2469,7 +2556,9 @@ static int q2spi_release(struct inode *inode, struct file *filp) __func__, ret); } - Q2SPI_DEBUG(q2spi, "%s End allocs:%d\n", __func__, atomic_read(&q2spi->alloc_count)); + Q2SPI_DEBUG(q2spi, "%s End allocs:%d rx_avail:%d retry:%d slave_in_sleep:%d\n", + __func__, atomic_read(&q2spi->alloc_count), atomic_read(&q2spi->rx_avail), + atomic_read(&q2spi->retry), atomic_read(&q2spi->slave_in_sleep)); return 0; } @@ -2603,9 +2692,9 @@ void q2spi_geni_se_dump_regs(struct q2spi_geni *q2spi) geni_read_reg(q2spi->base, SE_DMA_TX_IRQ_STAT)); Q2SPI_DEBUG(q2spi, "DMA_TX_IRQ_EN: 0x%x\n", geni_read_reg(q2spi->base, SE_DMA_TX_IRQ_EN)); + Q2SPI_DEBUG(q2spi, "DMA_TX_LEN_IN: 0x%x\n", geni_read_reg(q2spi->base, SE_DMA_TX_LEN_IN)); Q2SPI_DEBUG(q2spi, "DMA_RX_IRQ_EN: 0x%x\n", geni_read_reg(q2spi->base, SE_DMA_RX_IRQ_EN)); - Q2SPI_DEBUG(q2spi, "DMA_TX_LEN_IN: 0x%x\n", geni_read_reg(q2spi->base, SE_DMA_TX_LEN_IN)); Q2SPI_DEBUG(q2spi, "DMA_RX_PTR_L: 0x%x\n", geni_read_reg(q2spi->base, SE_DMA_RX_PTR_L)); Q2SPI_DEBUG(q2spi, "DMA_RX_PTR_H: 0x%x\n", geni_read_reg(q2spi->base, SE_DMA_RX_PTR_H)); Q2SPI_DEBUG(q2spi, "DMA_RX_ATTR: 0x%x\n", geni_read_reg(q2spi->base, SE_DMA_RX_ATTR)); @@ -2625,6 +2714,7 @@ static irqreturn_t q2spi_geni_wakeup_isr(int irq, void *data) struct q2spi_geni *q2spi = data; Q2SPI_DEBUG(q2spi, "%s PID:%d\n", __func__, current->pid); + atomic_set(&q2spi->slave_in_sleep, 0); schedule_work(&q2spi->q2spi_wakeup_work); return IRQ_HANDLED; } @@ -2664,11 +2754,11 @@ void q2spi_dump_client_error_regs(struct q2spi_geni *q2spi) ret = q2spi_read_reg(q2spi, Q2SPI_SLAVE_ERROR); if (ret) - Q2SPI_ERROR(q2spi, "Err SLAVE_ERROR Reg read failed: %d\n", ret); + Q2SPI_DEBUG(q2spi, "Err SLAVE_ERROR Reg read failed: %d\n", ret); ret = q2spi_read_reg(q2spi, Q2SPI_HDR_ERROR); if (ret) - Q2SPI_ERROR(q2spi, "Err HDR_ERROR Reg read failed: %d\n", ret); + Q2SPI_DEBUG(q2spi, "Err HDR_ERROR Reg read failed: %d\n", ret); } static int q2spi_gsi_submit(struct q2spi_packet *q2spi_pkt) @@ -2683,24 +2773,25 @@ static int q2spi_gsi_submit(struct q2spi_packet *q2spi_pkt) Q2SPI_DEBUG(q2spi, "%s PID=%d acquired gsi_lock 2\n", __func__, current->pid); ret = q2spi_setup_gsi_xfer(q2spi_pkt); if (ret) { - Q2SPI_ERROR(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->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; } Q2SPI_DEBUG(q2spi, "%s PID:%d waiting check_gsi_transfer_completion\n", __func__, current->pid); ret = check_gsi_transfer_completion(q2spi); if (ret) { - Q2SPI_ERROR(q2spi, "%s PID:%d Err completion timeout: %d\n", + 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); - dev_err(q2spi->dev, "%s Err dump gsi regs\n", __func__); gpi_dump_for_geni(q2spi->gsi->tx_c); + del_timer_sync(&q2spi->slave_sleep_timer); goto unmap_buf; } @@ -2740,7 +2831,7 @@ static int q2spi_prep_soft_reset_request(struct q2spi_geni *q2spi, struct q2spi_ Q2SPI_DEBUG(q2spi, "%s tx_buf:%p tx_dma:%p\n", __func__, reset_xfer->tx_buf, (void *)reset_xfer->tx_dma); - q2spi_dump_ipc(q2spi, q2spi->ipc, "Preparing soft reset tx_buf DMA TX", + q2spi_dump_ipc(q2spi, "Preparing soft reset tx_buf DMA TX", (char *)reset_xfer->tx_buf, reset_xfer->tx_len); return 0; } @@ -2785,7 +2876,7 @@ static int q2spi_prep_var1_request(struct q2spi_geni *q2spi, struct q2spi_packet Q2SPI_DEBUG(q2spi, "%s tx_buf:%p tx_dma:%p rx_buf:%p rx_dma:%p\n", __func__, var1_xfer->tx_buf, (void *)var1_xfer->tx_dma, var1_xfer->rx_buf, (void *)var1_xfer->rx_dma); - q2spi_dump_ipc(q2spi, q2spi->ipc, "Preparing var1 tx_buf DMA TX", + q2spi_dump_ipc(q2spi, "Preparing var1 tx_buf DMA TX", (char *)var1_xfer->tx_buf, var1_xfer->tx_len); return 0; } @@ -2834,12 +2925,12 @@ static int q2spi_prep_var5_request(struct q2spi_geni *q2spi, struct q2spi_packet Q2SPI_DEBUG(q2spi, "%s tx_buf:%p tx_dma:%p rx_buf:%p rx_dma:%p\n", __func__, var5_xfer->tx_buf, (void *)var5_xfer->tx_dma, var5_xfer->rx_buf, (void *)var5_xfer->rx_dma); - q2spi_dump_ipc(q2spi, q2spi->ipc, "Preparing var5 tx_buf DMA TX", + q2spi_dump_ipc(q2spi, "Preparing var5 tx_buf DMA TX", (char *)var5_xfer->tx_buf, Q2SPI_HEADER_LEN); - if (q2spi_pkt->m_cmd_param == Q2SPI_TX_ONLY) { - q2spi_dump_ipc(q2spi, q2spi->ipc, "Preparing var5 data_buf DMA TX", + if (q2spi_pkt->m_cmd_param == Q2SPI_TX_ONLY) + q2spi_dump_ipc(q2spi, "Preparing var5 data_buf DMA TX", (void *)q2spi_pkt->var5_pkt->data_buf, var5_xfer->tx_data_len); - } + return 0; } @@ -2874,7 +2965,7 @@ static int q2spi_prep_hrf_request(struct q2spi_geni *q2spi, struct q2spi_packet Q2SPI_DEBUG(q2spi, "%s tx_buf:%p tx_dma:%p rx_buf:%p rx_dma:%p\n", __func__, var1_xfer->tx_buf, (void *)var1_xfer->tx_dma, var1_xfer->rx_buf, (void *)var1_xfer->rx_dma); - q2spi_dump_ipc(q2spi, q2spi->ipc, "Preparing var1_HRF DMA TX", + q2spi_dump_ipc(q2spi, "Preparing var1_HRF DMA TX", (char *)var1_xfer->tx_buf, var1_xfer->tx_len); return 0; } @@ -2890,7 +2981,7 @@ int q2spi_process_hrf_flow_after_lra(struct q2spi_geni *q2spi, struct q2spi_pack xfer_timeout = msecs_to_jiffies(XFER_TIMEOUT_OFFSET); timeout = wait_for_completion_interruptible_timeout(&q2spi_pkt->wait_for_db, xfer_timeout); if (timeout <= 0) { - Q2SPI_ERROR(q2spi, "%s Err timeout for doorbell_wait timeout:%ld\n", + Q2SPI_DEBUG(q2spi, "%s Err timeout for doorbell_wait timeout:%ld\n", __func__, timeout); if (timeout == -ERESTARTSYS) { q2spi_sys_restart = true; @@ -2908,7 +2999,7 @@ int q2spi_process_hrf_flow_after_lra(struct q2spi_geni *q2spi, struct q2spi_pack return ret; ret = q2spi_gsi_submit(q2spi_pkt); if (ret) { - Q2SPI_ERROR(q2spi, "%s Err q2spi_gsi_submit failed: %d\n", __func__, ret); + Q2SPI_DEBUG(q2spi, "%s Err q2spi_gsi_submit failed: %d\n", __func__, ret); return ret; } Q2SPI_DEBUG(q2spi, "%s wakeup sma_wr_comp\n", __func__); @@ -2942,6 +3033,11 @@ int __q2spi_send_messages(struct q2spi_geni *q2spi, void *ptr) else Q2SPI_DEBUG(q2spi, "Enter %s PID %d\n", __func__, current->pid); + if (q2spi->port_release) { + Q2SPI_DEBUG(q2spi, "%s Err Port in closed state, return\n", __func__); + return -ENOENT; + } + mutex_lock(&q2spi->send_msgs_lock); /* Check if the queue is idle */ if (list_empty(&q2spi->tx_queue_list)) { @@ -3007,7 +3103,7 @@ int __q2spi_send_messages(struct q2spi_geni *q2spi, void *ptr) } ret = q2spi_gsi_submit(q2spi_pkt); if (ret) { - Q2SPI_ERROR(q2spi, "%s Err q2spi_gsi_submit failed: %d\n", __func__, ret); + Q2SPI_DEBUG(q2spi, "%s Err q2spi_gsi_submit failed: %d\n", __func__, ret); q2spi_unmap_var_bufs(q2spi, q2spi_pkt); goto send_msg_exit; } @@ -3126,7 +3222,7 @@ static int q2spi_geni_init(struct q2spi_geni *q2spi) /* make sure to turn on the resources before this ex: pm_runtime_get_sync(q2spi->dev); */ proto = geni_se_read_proto(&q2spi->se); - if (proto != GENI_SE_Q2SPI) { + if (proto != GENI_SE_Q2SPI_PROTO) { Q2SPI_ERROR(q2spi, "Err Invalid proto %d\n", proto); return -EINVAL; } @@ -3175,7 +3271,7 @@ void q2spi_geni_resources_off(struct q2spi_geni *q2spi) se = &q2spi->se; mutex_lock(&q2spi->geni_resource_lock); if (!q2spi->resources_on) { - Q2SPI_DEBUG(q2spi, "%s: Err Resources already off\n", __func__); + Q2SPI_DEBUG(q2spi, "%s: Resources already off\n", __func__); goto exit_resource_off; } @@ -3215,8 +3311,9 @@ int q2spi_geni_resources_on(struct q2spi_geni *q2spi) int ret = 0; mutex_lock(&q2spi->geni_resource_lock); + Q2SPI_DEBUG(q2spi, "%s PID=%d\n", __func__, current->pid); if (q2spi->resources_on) { - Q2SPI_DEBUG(q2spi, "%s: Err Resources already on\n", __func__); + Q2SPI_DEBUG(q2spi, "%s: Resources already on\n", __func__); goto exit_resource_on; } @@ -3459,12 +3556,12 @@ int q2spi_read_reg(struct q2spi_geni *q2spi, int reg_offset) __func__, xfer->tx_buf, (void *)xfer->tx_dma, xfer->rx_buf, (void *)xfer->rx_dma, xfer->tx_len, xfer->rx_len); - q2spi_dump_ipc(q2spi, q2spi->ipc, "q2spi read reg tx_buf DMA TX", + q2spi_dump_ipc(q2spi, "q2spi read reg tx_buf DMA TX", (char *)xfer->tx_buf, xfer->tx_len); ret = q2spi_gsi_submit(q2spi_pkt); if (ret) { - Q2SPI_ERROR(q2spi, "%s Err q2spi_gsi_submit failed: %d\n", __func__, ret); + Q2SPI_DEBUG(q2spi, "%s Err q2spi_gsi_submit failed: %d\n", __func__, ret); return ret; } @@ -3498,7 +3595,7 @@ static int q2spi_write_reg(struct q2spi_geni *q2spi, int reg_offset, unsigned lo q2spi_req.data_buff = &data; ret = q2spi_frame_lra(q2spi, q2spi_req, &q2spi_pkt, VARIANT_1_LRA); if (ret < 0) { - Q2SPI_ERROR(q2spi, "%s Err q2spi_frame_lra failed ret:%d\n", __func__, ret); + Q2SPI_DEBUG(q2spi, "%s Err q2spi_frame_lra failed ret:%d\n", __func__, ret); return ret; } Q2SPI_DEBUG(q2spi, "%s q2spi_pkt:%p\n", __func__, q2spi_pkt); @@ -3515,12 +3612,11 @@ static int q2spi_write_reg(struct q2spi_geni *q2spi, int reg_offset, unsigned lo xfer->rx_buf, (void *)xfer->rx_dma, xfer->tx_len, xfer->rx_len); Q2SPI_DEBUG(q2spi, "%s q2spi_pkt->var1_pkt_add:%p\n", __func__, q2spi_pkt->var1_pkt); - q2spi_dump_ipc(q2spi, q2spi->ipc, "q2spi_read_reg tx_buf DMA TX", - (char *)xfer->tx_buf, xfer->tx_len); + q2spi_dump_ipc(q2spi, "q2spi_read_reg tx_buf DMA TX", (char *)xfer->tx_buf, xfer->tx_len); ret = q2spi_gsi_submit(q2spi_pkt); if (ret) { - Q2SPI_ERROR(q2spi, "%s Err q2spi_gsi_submit failed: %d\n", __func__, ret); + Q2SPI_DEBUG(q2spi, "%s Err q2spi_gsi_submit failed: %d\n", __func__, ret); return ret; } @@ -3532,6 +3628,7 @@ static int q2spi_write_reg(struct q2spi_geni *q2spi, int reg_offset, unsigned lo /** * q2spi_slave_init - Initialization sequence * @q2spi: Pointer to main q2spi_geni structure + * @slave_init: Slave_init flag for slave initialization * * This function performs init sequence with q2spi slave * send host command to check client enabled or not @@ -3540,19 +3637,21 @@ static int q2spi_write_reg(struct q2spi_geni *q2spi, int reg_offset, unsigned lo * * Return: 0 for success, negative number for error condition. */ -static int q2spi_slave_init(struct q2spi_geni *q2spi) +static int q2spi_slave_init(struct q2spi_geni *q2spi, bool slave_init) { unsigned long scratch_data = 0xAAAAAAAA; unsigned long error_en_data = 0xFFFFFFFF; int ret = 0, value = 0; int retries = RETRIES; + if (!slave_init) + return 0; + Q2SPI_DEBUG(q2spi, "%s reg:0x%x\n", __func__, Q2SPI_SCRATCH0); - return 0; /* Dummy SCRATCH register write */ ret = q2spi_write_reg(q2spi, Q2SPI_SCRATCH0, scratch_data); if (ret) { - Q2SPI_ERROR(q2spi, "scratch0 write failed: %d\n", ret); + Q2SPI_DEBUG(q2spi, "scratch0 write failed: %d\n", ret); return ret; } @@ -3560,7 +3659,7 @@ static int q2spi_slave_init(struct q2spi_geni *q2spi) Q2SPI_DEBUG(q2spi, "%s reg: 0x%x\n", __func__, Q2SPI_SCRATCH0); ret = q2spi_read_reg(q2spi, Q2SPI_SCRATCH0); if (ret) { - Q2SPI_ERROR(q2spi, "Err scratch0 read failed: %d\n", ret); + Q2SPI_DEBUG(q2spi, "Err scratch0 read failed: %d\n", ret); return ret; } @@ -3580,21 +3679,21 @@ static int q2spi_slave_init(struct q2spi_geni *q2spi) Q2SPI_DEBUG(q2spi, "%s reg:0x%x\n", __func__, Q2SPI_HOST_CFG); ret = q2spi_read_reg(q2spi, Q2SPI_HOST_CFG); if (ret) { - Q2SPI_ERROR(q2spi, "Err HOST CFG read failed: %d\n", ret); + Q2SPI_DEBUG(q2spi, "Err HOST CFG read failed: %d\n", ret); return ret; } Q2SPI_DEBUG(q2spi, "%s reg:0x%x\n", __func__, Q2SPI_ERROR_EN); ret = q2spi_write_reg(q2spi, Q2SPI_ERROR_EN, error_en_data); if (ret) { - Q2SPI_ERROR(q2spi, "Err Error_en reg write failed: %d\n", ret); + Q2SPI_DEBUG(q2spi, "Err Error_en reg write failed: %d\n", ret); return ret; } Q2SPI_DEBUG(q2spi, "%s reg:0x%x\n", __func__, Q2SPI_ERROR_EN); ret = q2spi_read_reg(q2spi, Q2SPI_ERROR_EN); if (ret) { - Q2SPI_ERROR(q2spi, "Err HOST CFG read failed: %d\n", ret); + Q2SPI_DEBUG(q2spi, "Err HOST CFG read failed: %d\n", ret); return ret; } return 0; @@ -3676,6 +3775,7 @@ int q2spi_send_system_mem_access(struct q2spi_geni *q2spi, struct q2spi_packet * unsigned int dw_len; u8 flow_id = cr_pkt->var3_pkt[idx].flow_id; + q2spi->sys_mem_read_in_progress = true; dw_len = ((cr_pkt->var3_pkt[idx].dw_len_part3 << 12) & 0xFF) | ((cr_pkt->var3_pkt[idx].dw_len_part2 << 4) & 0xFF) | cr_pkt->var3_pkt[idx].dw_len_part1; @@ -3693,7 +3793,7 @@ int q2spi_send_system_mem_access(struct q2spi_geni *q2spi, struct q2spi_packet * ret = q2spi_add_req_to_tx_queue(q2spi, q2spi_req, q2spi_pkt); mutex_unlock(&q2spi->queue_lock); if (ret == -ENOMEM) { - Q2SPI_ERROR(q2spi, "%s Err ret:%d\n", __func__, ret); + Q2SPI_DEBUG(q2spi, "%s Err ret:%d\n", __func__, ret); /* sleep sometime to let application consume the pending rx buffers */ usleep_range(125000, 150000); } else { @@ -3701,7 +3801,8 @@ int q2spi_send_system_mem_access(struct q2spi_geni *q2spi, struct q2spi_packet * } } if (ret < 0) { - Q2SPI_ERROR(q2spi, "%s Err ret:%d\n", __func__, ret); + q2spi->sys_mem_read_in_progress = false; + Q2SPI_DEBUG(q2spi, "%s Err ret:%d\n", __func__, ret); return ret; } @@ -3713,17 +3814,20 @@ int q2spi_send_system_mem_access(struct q2spi_geni *q2spi, struct q2spi_packet * timeout = wait_for_completion_interruptible_timeout(&q2spi->sma_wr_comp, xfer_timeout); if (timeout <= 0) { - Q2SPI_ERROR(q2spi, "%s Err timeout %ld for sma write complete\n", + Q2SPI_DEBUG(q2spi, "%s Err timeout %ld for sma write complete\n", __func__, timeout); atomic_set(&q2spi->doorbell_pending, 0); if (timeout == -ERESTARTSYS) { q2spi_sys_restart = true; + q2spi->sys_mem_read_in_progress = false; return -ERESTARTSYS; } + q2spi->sys_mem_read_in_progress = false; return -ETIMEDOUT; } } ret = __q2spi_send_messages(q2spi, (void *)*q2spi_pkt); + q2spi->sys_mem_read_in_progress = false; Q2SPI_DEBUG(q2spi, "%s End ret:%d %d\n", __func__, ret, __LINE__); return ret; } @@ -3848,7 +3952,26 @@ static void q2spi_handle_wakeup_work(struct work_struct *work) ret = q2spi_geni_runtime_resume(q2spi->dev); if (ret) - Q2SPI_ERROR(q2spi, "%s Runtime resume Failed:%d\n", __func__, ret); + Q2SPI_DEBUG(q2spi, "%s Runtime resume Failed:%d\n", __func__, ret); +} + +/* + * q2spi_sleep_work_func() - worker function which handles client sleep sequence for q2spi + * @work: pointer to work_struct + * + * Return: None + */ +static void q2spi_sleep_work_func(struct work_struct *work) +{ + struct q2spi_geni *q2spi = + container_of(work, struct q2spi_geni, q2spi_sleep_work); + + Q2SPI_DEBUG(q2spi, "%s: PID=%d\n", __func__, current->pid); + if (q2spi_sys_restart || q2spi->port_release) { + Q2SPI_DEBUG(q2spi, "%s Err Port in closed state or sys_restart\n", __func__); + return; + } + q2spi_put_slave_to_sleep(q2spi); } /* @@ -3872,7 +3995,7 @@ static void q2spi_handle_doorbell_work(struct work_struct *work) current->pid, q2spi, atomic_read(&q2spi->dev->power.usage_count)); ret = pm_runtime_get_sync(q2spi->dev); if (ret < 0) { - Q2SPI_ERROR(q2spi, "%s Err for PM get\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err for PM get\n", __func__); pm_runtime_put_noidle(q2spi->dev); pm_runtime_set_suspended(q2spi->dev); return; @@ -3883,6 +4006,12 @@ static void q2spi_handle_doorbell_work(struct work_struct *work) ret = check_gsi_transfer_completion_db_rx(q2spi); if (ret) { Q2SPI_DEBUG(q2spi, "%s db rx completion timeout: %d\n", __func__, ret); + atomic_set(&q2spi->doorbell_pending, 0); + q2spi_unmap_doorbell_rx_buf(q2spi); + 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); goto exit_doorbell_work; } @@ -3890,6 +4019,8 @@ static void q2spi_handle_doorbell_work(struct work_struct *work) q2spi_cr_pkt = q2spi_prepare_cr_pkt(q2spi); if (!q2spi_cr_pkt) { Q2SPI_DEBUG(q2spi, "Err q2spi_prepare_cr_pkt failed\n"); + atomic_set(&q2spi->doorbell_pending, 0); + q2spi_unmap_doorbell_rx_buf(q2spi); goto exit_doorbell_work; } @@ -3936,6 +4067,10 @@ static void q2spi_handle_doorbell_work(struct work_struct *work) __func__); q2spi_set_data_avail_in_pkt(q2spi, q2spi_cr_pkt, i); q2spi_notify_data_avail_for_client(q2spi); + if (!timer_pending(&q2spi->slave_sleep_timer)) { + Q2SPI_DEBUG(q2spi, "%s sleep timer expired\n", __func__); + q2spi_put_slave_to_sleep(q2spi); + } } else { Q2SPI_DEBUG(q2spi, "%s Bulk status with host Flow ID:%d\n", __func__, q2spi_cr_pkt->bulk_pkt[i].flow_id); @@ -4042,6 +4177,13 @@ static int q2spi_sleep_config(struct q2spi_geni *q2spi, struct platform_device * } INIT_WORK(&q2spi->q2spi_wakeup_work, q2spi_handle_wakeup_work); + q2spi->sleep_wq = alloc_workqueue("q2spi_sleep_wq", WQ_UNBOUND | WQ_HIGHPRI, 0); + if (!q2spi->sleep_wq) { + Q2SPI_ERROR(q2spi, "Err failed to allocate sleep_timer workqueue"); + return -ENOMEM; + } + INIT_WORK(&q2spi->q2spi_sleep_work, q2spi_sleep_work_func); + /* To use the Doorbel pin as wakeup irq */ q2spi->doorbell_irq = platform_get_irq(pdev, 1); Q2SPI_DEBUG(q2spi, "%s Q2SPI doorbell_irq:%d\n", __func__, q2spi->doorbell_irq); @@ -4062,6 +4204,63 @@ static int q2spi_sleep_config(struct q2spi_geni *q2spi, struct platform_device * return ret; } +/** + * q2spi_client_sleep_timeout_handler - Q2SPI client sleep timeout handler + * @timer_list: timer_list pointer + * + * Return: None + */ +void q2spi_client_sleep_timeout_handler(struct timer_list *t) +{ + struct q2spi_geni *q2spi = from_timer(q2spi, t, slave_sleep_timer); + + Q2SPI_DEBUG(q2spi, "%s: PID=%d\n", __func__, current->pid); + if (q2spi_sys_restart || q2spi->port_release) { + Q2SPI_DEBUG(q2spi, "%s Err Port in closed state or sys_restart\n", __func__); + return; + } + queue_work(q2spi->sleep_wq, &q2spi->q2spi_sleep_work); +} + +/** + * q2spi_destroy_workqueue - Destroy q2spi work queues + * @q2spi: Pointer to main q2spi_geni structure. + * + * Return: None + */ +void q2spi_destroy_workqueue(struct q2spi_geni *q2spi) +{ + if (q2spi->sleep_wq) + destroy_workqueue(q2spi->sleep_wq); + if (q2spi->wakeup_wq) + destroy_workqueue(q2spi->wakeup_wq); + if (q2spi->doorbell_wq) + destroy_workqueue(q2spi->doorbell_wq); +} + +/** + * q2spi_geni_restart_cb - callback routine for reboot notifier + * @nb: pointer to reboot notifier block chain + * @action: value passed unmodified to notifier function + * @data: pointer passed unmodified to notifier function + * + * Returns 0 for success and non-zero for failure. + */ +static int q2spi_geni_restart_cb(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct q2spi_geni *q2spi = container_of(nb, struct q2spi_geni, restart_handler); + + if (!q2spi) { + Q2SPI_ERROR(q2spi, "%s Err q2spi is NULL, PID=%d\n", __func__, current->pid); + return -EINVAL; + } + Q2SPI_INFO(q2spi, "%s PID=%d\n", __func__, current->pid); + q2spi_sys_restart = true; + + return 0; +} + /** * q2spi_geni_probe - Q2SPI interface driver probe function * @pdev: Q2SPI Serial Engine to probe. @@ -4136,7 +4335,7 @@ static int q2spi_geni_probe(struct platform_device *pdev) q2spi->max_speed_hz = q2spi_max_speed; } else { if (of_property_read_u32(pdev->dev.of_node, "q2spi-max-frequency", - &q2spi->max_speed_hz)) { + &q2spi->max_speed_hz)) { Q2SPI_ERROR(q2spi, "Err Max frequency not specified\n"); ret = -EINVAL; goto q2spi_err; @@ -4144,8 +4343,8 @@ static int q2spi_geni_probe(struct platform_device *pdev) } q2spi->wrapper_dev = dev->parent; - Q2SPI_DEBUG(q2spi, "%s q2spi:0x%p q2spi_cdev:0x%p dev:0x%p, p_dev:0x%p", - __func__, q2spi, q2spi->chrdev, dev, &pdev->dev); + Q2SPI_DEBUG(q2spi, "%s q2spi:0x%p w_dev:0x%p dev:0x%p, p_dev:0x%p", + __func__, q2spi, q2spi->wrapper_dev, dev, &pdev->dev); Q2SPI_INFO(q2spi, "%s dev:%s q2spi_max_freq:%uhz\n", __func__, dev_name(q2spi->dev), q2spi->max_speed_hz); @@ -4184,6 +4383,7 @@ static int q2spi_geni_probe(struct platform_device *pdev) goto resources_off; } + idr_init(&q2spi->tid_idr); init_waitqueue_head(&q2spi->readq); init_waitqueue_head(&q2spi->read_wq); INIT_LIST_HEAD(&q2spi->tx_queue_list); @@ -4194,6 +4394,7 @@ static int q2spi_geni_probe(struct platform_device *pdev) mutex_init(&q2spi->send_msgs_lock); spin_lock_init(&q2spi->cr_queue_lock); q2spi->port_release = true; + q2spi->q2spi_sleep_cmd_enable = false; q2spi->kworker = kthread_create_worker(0, "kthread_q2spi"); if (IS_ERR(q2spi->kworker)) { @@ -4244,6 +4445,7 @@ static int q2spi_geni_probe(struct platform_device *pdev) } INIT_WORK(&q2spi->q2spi_doorbell_work, q2spi_handle_doorbell_work); + timer_setup(&q2spi->slave_sleep_timer, q2spi_client_sleep_timeout_handler, 0); dev_dbg(dev, "Q2SPI GENI SE Driver probed\n"); platform_set_drvdata(pdev, q2spi); @@ -4262,10 +4464,19 @@ static int q2spi_geni_probe(struct platform_device *pdev) goto free_buf; } + q2spi->restart_handler.notifier_call = q2spi_geni_restart_cb; + ret = register_reboot_notifier(&q2spi->restart_handler); + if (ret) { + Q2SPI_ERROR(q2spi, "%s: Err failed to register reboot notifier, ret:%d\n", + __func__, ret); + goto free_buf; + } + Q2SPI_INFO(q2spi, "%s Q2SPI GENI SE Driver probe\n", __func__); pr_info("boot_kpi: M - DRIVER GENI_Q2SPI Ready\n"); return 0; free_buf: + q2spi_destroy_workqueue(q2spi); q2spi_free_dma_buf(q2spi); destroy_worker: idr_destroy(&q2spi->tid_idr); @@ -4280,8 +4491,10 @@ resources_off: chardev_destroy: q2spi_chardev_destroy(q2spi); q2spi_err: - if (q2spi) + if (q2spi && q2spi->ipc) { q2spi->base = NULL; + ipc_log_context_destroy(q2spi->ipc); + } pr_err("%s: failed ret:%d\n", __func__, ret); return ret; } @@ -4295,8 +4508,10 @@ static int q2spi_geni_remove(struct platform_device *pdev) if (!q2spi || !q2spi->base) return 0; + unregister_reboot_notifier(&q2spi->restart_handler); device_remove_file(&pdev->dev, &dev_attr_max_dump_size); + destroy_workqueue(q2spi->sleep_wq); destroy_workqueue(q2spi->wakeup_wq); destroy_workqueue(q2spi->doorbell_wq); @@ -4336,19 +4551,20 @@ static struct q2spi_geni *get_q2spi(struct device *dev) } /* - * q2spi_wakeup_hw_through_gpio - Preparing HW wake up through Mosi and clock GPIO's + * q2spi_wakeup_slave_through_gpio - Preparing HW wake up through Mosi and clock GPIO's * * @q2spi: Pointer to main q2spi_geni structure * * Return: 0 for succes, else returns linux error codes */ -int q2spi_wakeup_hw_through_gpio(struct q2spi_geni *q2spi) +int q2spi_wakeup_slave_through_gpio(struct q2spi_geni *q2spi) { int ret = 0; - q2spi_unmap_doorbell_rx_buf(q2spi); Q2SPI_DEBUG(q2spi, "%s Sending disconnect doorbell only\n", __func__); - geni_gsi_disconnect_doorbell_stop_ch(q2spi->gsi->tx_c, false); + 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) { @@ -4387,9 +4603,9 @@ int q2spi_wakeup_hw_through_gpio(struct q2spi_geni *q2spi) __func__, ret); return ret; } + geni_gsi_ch_start(q2spi->gsi->tx_c); ret = q2spi_map_doorbell_rx_buf(q2spi); - return ret; } @@ -4400,13 +4616,26 @@ int q2spi_wakeup_hw_through_gpio(struct q2spi_geni *q2spi) * * Return: 0 for succes; */ -static int q2spi_put_slave_to_sleep(struct q2spi_geni *q2spi) +int q2spi_put_slave_to_sleep(struct q2spi_geni *q2spi) { struct q2spi_packet *q2spi_pkt; struct q2spi_request q2spi_req; int ret = 0; - Q2SPI_DEBUG(q2spi, "%s: PID=%d\n", __func__, current->pid); + Q2SPI_DEBUG(q2spi, "%s: PID=%d q2spi_sleep_cmd_enable:%d\n", + __func__, current->pid, q2spi->q2spi_sleep_cmd_enable); + if (!q2spi->q2spi_sleep_cmd_enable) + return 0; + + if (atomic_read(&q2spi->slave_in_sleep)) { + Q2SPI_DEBUG(q2spi, "%s: Client in sleep\n", __func__); + return 0; + } + if (mutex_is_locked(&q2spi->port_lock) || q2spi->port_release) { + Q2SPI_DEBUG(q2spi, "%s: port_lock acquired or release is in progress\n", __func__); + return 0; + } + q2spi_req.cmd = Q2SPI_HRF_SLEEP_CMD; q2spi_req.sync = 1; @@ -4414,17 +4643,30 @@ static int q2spi_put_slave_to_sleep(struct q2spi_geni *q2spi) ret = q2spi_add_req_to_tx_queue(q2spi, q2spi_req, &q2spi_pkt); mutex_unlock(&q2spi->queue_lock); if (ret < 0) { - Q2SPI_ERROR(q2spi, "%s Err failed ret:%d\n", __func__, ret); - return ret; + Q2SPI_DEBUG(q2spi, "%s Err failed ret:%d\n", __func__, ret); + goto err; } Q2SPI_DEBUG(q2spi, "%s q2spi_pkt:%p tid:%d\n", __func__, q2spi_pkt, q2spi_pkt->xfer->tid); q2spi_pkt->is_client_sleep_pkt = true; - __q2spi_transfer(q2spi, q2spi_req, q2spi_pkt, 0); + ret = __q2spi_transfer(q2spi, q2spi_req, q2spi_pkt, 0); + if (ret) { + Q2SPI_DEBUG(q2spi, "%s __q2spi_transfer q2spi_pkt:%p ret%d\n", + __func__, q2spi_pkt, ret); + if (q2spi->port_release) { + Q2SPI_DEBUG(q2spi, "%s Err Port in closed state, return\n", __func__); + return -ENOENT; + } + } q2spi_pkt->state = IN_DELETION; q2spi_free_xfer_tid(q2spi, q2spi_pkt->xfer->tid); q2spi_del_pkt_from_tx_queue(q2spi, q2spi_pkt); q2spi_free_q2spi_pkt(q2spi_pkt, __LINE__); - Q2SPI_DEBUG(q2spi, "%s: PID=%d End\n", __func__, current->pid); + atomic_set(&q2spi->slave_in_sleep, 1); + /* add 2msec delay for slave to process the sleep packet */ + usleep_range(2000, 3000); + Q2SPI_DEBUG(q2spi, "%s: PID=%d End slave_in_sleep:%d\n", __func__, current->pid, + atomic_read(&q2spi->slave_in_sleep)); +err: return ret; } @@ -4455,14 +4697,17 @@ static int q2spi_geni_runtime_suspend(struct device *dev) return -EINVAL; } - Q2SPI_INFO(q2spi, "%s PID=%d\n", __func__, current->pid); + Q2SPI_DEBUG(q2spi, "%s PID=%d\n", __func__, current->pid); + if (atomic_read(&q2spi->doorbell_pending)) { + Q2SPI_DEBUG(q2spi, "%s CR Doorbell Pending\n", __func__); + /* Update last access time of a device for autosuspend */ + pm_runtime_mark_last_busy(q2spi->dev); + return -EBUSY; + } + if (!atomic_read(&q2spi->is_suspend)) { - Q2SPI_DEBUG(q2spi, "%s: PID=%d\n", __func__, current->pid); - q2spi_geni_resources_on(q2spi); q2spi_put_slave_to_sleep(q2spi); - /* Delay to ensure any pending CRs in progress are consumed */ - usleep_range(10000, 20000); q2spi_tx_queue_status(q2spi); q2spi_unmap_doorbell_rx_buf(q2spi); @@ -4470,13 +4715,13 @@ static int q2spi_geni_runtime_suspend(struct device *dev) geni_gsi_disconnect_doorbell_stop_ch(q2spi->gsi->tx_c, true); ret = irq_set_irq_wake(q2spi->doorbell_irq, 1); if (unlikely(ret)) - Q2SPI_ERROR(q2spi, "%s Err Failed to set IRQ wake\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err Failed to set IRQ wake\n", __func__); q2spi_geni_resources_off(q2spi); atomic_set(&q2spi->is_suspend, 1); if (!ret) enable_irq(q2spi->doorbell_irq); else - Q2SPI_ERROR(q2spi, "%s Err Failed to enable_irq\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Err Failed to enable_irq\n", __func__); } return ret; } @@ -4495,7 +4740,7 @@ static int q2spi_geni_runtime_resume(struct device *dev) return -EINVAL; } - Q2SPI_INFO(q2spi, "%s PID=%d\n", __func__, current->pid); + Q2SPI_DEBUG(q2spi, "%s PID=%d\n", __func__, current->pid); if (atomic_read(&q2spi->is_suspend)) { Q2SPI_DEBUG(q2spi, "%s: PID=%d\n", __func__, current->pid); if (q2spi_geni_resources_on(q2spi)) @@ -4503,9 +4748,8 @@ static int q2spi_geni_runtime_resume(struct device *dev) disable_irq(q2spi->doorbell_irq); ret = irq_set_irq_wake(q2spi->doorbell_irq, 0); if (unlikely(ret)) - Q2SPI_ERROR(q2spi, "%s Failed to set IRQ wake\n", __func__); + Q2SPI_DEBUG(q2spi, "%s Failed to set IRQ wake\n", __func__); - Q2SPI_DEBUG(q2spi, "%s Sending start channel\n", __func__); geni_gsi_ch_start(q2spi->gsi->tx_c); /* Clear is_suspend to map doorbell buffers */ diff --git a/drivers/spi/q2spi-msm.h b/drivers/spi/q2spi-msm.h index e173ac57457f..55cf9529a538 100644 --- a/drivers/spi/q2spi-msm.h +++ b/drivers/spi/q2spi-msm.h @@ -11,13 +11,17 @@ #include #include #include +#include #include #include #include +#include #include #include #include "q2spi-gsi.h" +#define GENI_SE_Q2SPI_PROTO (0xE) + #define DATA_WORD_LEN 4 #define SMA_BUF_SIZE (4096) #define MAX_CR_SIZE 24 /* Max CR size is 24 bytes per CR */ @@ -32,7 +36,7 @@ #define TIMEOUT_MSECONDS 10 /* 10 milliseconds */ #define RETRIES 1 #define Q2SPI_MAX_DATA_LEN 4096 -#define Q2SPI_MAX_TX_RETRIES 5 +#define Q2SPI_MAX_TX_RETRIES 3 /* Host commands */ #define HC_DB_REPORT_LEN_READ 1 #define HC_DB_REPORT_BODY_READ 2 @@ -163,7 +167,14 @@ #define CR_EXTENSION_DATA_BYTES 5 /* 1 for EXTID + 4 Bytes for one 1DW */ #define Q2SPI_HRF_SLEEP_CMD 0x100 -#define Q2SPI_AUTOSUSPEND_DELAY (XFER_TIMEOUT_OFFSET + 3000) +#define Q2SPI_AUTOSUSPEND_DELAY (XFER_TIMEOUT_OFFSET + 50) +#define Q2SPI_SLAVE_SLEEP_TIME_MSECS 100 + +#define Q2SPI_SOFT_RESET_CMD_BIT BIT(0) +#define Q2SPI_SLEEP_CMD_BIT BIT(1) + +#define Q2SPI_CR_TRANSACTION_ERROR 1 + #define PINCTRL_DEFAULT "default" #define PINCTRL_ACTIVE "active" #define PINCTRL_SLEEP "sleep" @@ -430,7 +441,6 @@ struct q2spi_dma_transfer { * q2spi_chrdev: cdev structure * @geni_se: stores info parsed from device tree * @gsi: stores GSI structure information - * @qup_gsi_err: flahg to set incase of gsi errors * @db_xfer: reference to q2spi_dma_transfer structure for doorbell * @req: reference to q2spi request structure * @c_req: reference to q2spi client request structure @@ -455,8 +465,9 @@ struct q2spi_dma_transfer { * @tx_cb: completion for tx dma * @rx_cb: completion for rx dma * @db_rx_cb: completion for doobell rx dma + * @restart_handler: notifier callback for restart * @wait_for_ext_cr: completion for extension cr - * @rx_avail: used to notify the client for avaialble rx data + * @rx_avail: used to notify the client for available rx data * @tid_idr: tid id allocator * @readq: waitqueue for rx data * @hrf_flow: flag to indicate HRF flow @@ -480,9 +491,11 @@ struct q2spi_dma_transfer { * @sma_wait: completion for SMA * @ipc: pointer for ipc * @q2spi_doorbell_work: work to queue for doorbell process - * @doorbell_wq: workqueue pointer fir doorbell + * @doorbell_wq: workqueue pointer for doorbell * @q2spi_wakeup_work: work to queue for wakeup process * @wakeup_wq: workqueue pointer for wakeup + * @q2spi_sleep_work: work to queue for client sleep + * @sleep_wq: workqueue pointer for client_sleep * @hw_state_is_bad: used when HW is in un-recoverable state * @max_dump_data_size: max size of data to be dumped as part of dump_ipc function * @doorbell_pending: Set when independent doorbell CR received @@ -497,6 +510,12 @@ struct q2spi_dma_transfer { * @doorbell_irq: doorbell irq * @wake_clk_gpio: GPIO for clk pin * @wake_mosi_gpio: GPIO for mosi pin + * @slave_sleep_timer: used for initiating sleep command to slave + * @slave_in_sleep: reflects sleep command sent to slave + * @sys_mem_read_in_progress: reflects system memory read request is in progress + * @q2spi_cr_txn_err: reflects Q2SPI_CR_TRANSACTION_ERROR in CR body + * @q2spi_sleep_cmd_enable: reflects start sending the sleep command to slave + * @q2spi_cr_hdr_err: reflects CR Header incorrect in CR Header */ struct q2spi_geni { struct device *wrapper_dev; @@ -513,7 +532,6 @@ struct q2spi_geni { struct q2spi_chrdev chrdev; struct geni_se se; struct q2spi_gsi *gsi; - bool qup_gsi_err; struct q2spi_dma_transfer *db_xfer; struct q2spi_request *req; struct q2spi_client_request *c_req; @@ -545,6 +563,7 @@ struct q2spi_geni { struct completion tx_cb; struct completion rx_cb; struct completion db_rx_cb; + struct notifier_block restart_handler; struct completion wait_for_ext_cr; atomic_t rx_avail; struct idr tid_idr; @@ -576,6 +595,8 @@ struct q2spi_geni { struct workqueue_struct *doorbell_wq; struct work_struct q2spi_wakeup_work; struct workqueue_struct *wakeup_wq; + struct work_struct q2spi_sleep_work; + struct workqueue_struct *sleep_wq; bool doorbell_setup; struct qup_q2spi_cr_header_event q2spi_cr_hdr_event; wait_queue_head_t read_wq; @@ -595,6 +616,12 @@ struct q2spi_geni { int doorbell_irq; int wake_clk_gpio; int wake_mosi_gpio; + struct timer_list slave_sleep_timer; + atomic_t slave_in_sleep; + bool sys_mem_read_in_progress; + bool q2spi_cr_txn_err; + bool q2spi_sleep_cmd_enable; + bool q2spi_cr_hdr_err; }; /** @@ -703,7 +730,7 @@ struct q2spi_packet { void q2spi_doorbell(struct q2spi_geni *q2spi, const struct qup_q2spi_cr_header_event *event); void q2spi_gsi_ch_ev_cb(struct dma_chan *ch, struct msm_gpi_cb const *cb, void *ptr); void q2spi_geni_se_dump_regs(struct q2spi_geni *q2spi); -void q2spi_dump_ipc(struct q2spi_geni *q2spi, void *ipc_ctx, char *prefix, char *str, int size); +void q2spi_dump_ipc(struct q2spi_geni *q2spi, char *prefix, char *str, int size); void q2spi_trace_log(struct device *dev, const char *fmt, ...); void dump_ipc(struct q2spi_geni *q2spi, void *ctx, char *prefix, char *str, int size); void *q2spi_kzalloc(struct q2spi_geni *q2spi, int size, int line); @@ -719,8 +746,10 @@ void q2spi_dump_client_error_regs(struct q2spi_geni *q2spi); int q2spi_geni_resources_on(struct q2spi_geni *q2spi); void q2spi_geni_resources_off(struct q2spi_geni *q2spi); int __q2spi_send_messages(struct q2spi_geni *q2spi, void *ptr); -int q2spi_wakeup_hw_through_gpio(struct q2spi_geni *q2spi); +int q2spi_wakeup_slave_through_gpio(struct q2spi_geni *q2spi); int q2spi_process_hrf_flow_after_lra(struct q2spi_geni *q2spi, struct q2spi_packet *q2spi_pkt); void q2spi_transfer_soft_reset(struct q2spi_geni *q2spi); +void q2spi_transfer_abort(struct q2spi_geni *q2spi); +int q2spi_put_slave_to_sleep(struct q2spi_geni *q2spi); #endif /* _SPI_Q2SPI_MSM_H_ */ diff --git a/include/linux/msm_gpi.h b/include/linux/msm_gpi.h index e7beb18ccf4e..b4322f7f1d79 100644 --- a/include/linux/msm_gpi.h +++ b/include/linux/msm_gpi.h @@ -254,6 +254,12 @@ enum msm_gpi_ctrl_cmd { MSM_GPI_DEEP_SLEEP_INIT, }; +enum Q2SPI_CR_HEADER_CODE { + Q2SPI_CR_CODE_SUCCESS = 0x1, + Q2SPI_CR_HEADER_LEN_ZERO = 0xB, + Q2SPI_CR_HEADER_INCORRECT = 0xC, +}; + enum msm_gpi_cb_event { /* These events are hardware generated events */ MSM_GPI_QUP_NOTIFY,