From dfa193fcfccefd7a0a4700e2b870d03e6f71c65c Mon Sep 17 00:00:00 2001 From: Ashok Vuyyuru Date: Thu, 4 Jun 2020 17:43:26 +0530 Subject: [PATCH] msm: ipa3: Fix to avoid gsi/sys len stats mismatch In suspend just before stopping the channel possible to receive the IEOB interrupt and xfer pointer will not be processed in this mode but gsi stats are updated. In resume after starting the channel will receive the IEOB interrupt and xfer pointer will be overwritten because of this observing the gsi/sys len stats are not matching and buffers won't be replinished properly leading to HW stall. To avoid this process all data in polling context, gsi/sys len stats are updated properly. Change-Id: Id665448165b6aa51b251cddd72573c6df64ee541 Signed-off-by: Ashok Vuyyuru --- drivers/platform/msm/gsi/gsi.c | 32 ++++++++++++++++++++---- drivers/platform/msm/ipa/ipa_v3/ipa_dp.c | 12 ++++++--- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index 7519f1dc08b1..1978bad08468 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -537,9 +537,14 @@ static void gsi_process_chan(struct gsi_xfer_compl_evt *evt, ch_ctx->ring.rp_local = rp; } - - /* the element at RP is also processed */ - gsi_incr_ring_rp(&ch_ctx->ring); + /* + * Increment RP local only in polling context to avoid + * sys len mismatch. + */ + if (!(callback && ch_ctx->props.dir == + GSI_CHAN_DIR_FROM_GSI)) + /* the element at RP is also processed */ + gsi_incr_ring_rp(&ch_ctx->ring); ch_ctx->ring.rp = ch_ctx->ring.rp_local; rp_idx = gsi_find_idx_from_addr(&ch_ctx->ring, rp); @@ -549,11 +554,20 @@ static void gsi_process_chan(struct gsi_xfer_compl_evt *evt, notify->veid = evt->veid; } - ch_ctx->stats.completed++; WARN_ON(!ch_ctx->user_data[rp_idx].valid); notify->xfer_user_data = ch_ctx->user_data[rp_idx].p; - ch_ctx->user_data[rp_idx].valid = false; + /* + * In suspend just before stopping the channel possible to receive + * the IEOB interrupt and xfer pointer will not be processed in this + * mode and moving channel poll mode. In resume after starting the + * channel will receive the IEOB interrupt and xfer pointer will be + * overwritten. To avoid this process all data in polling context. + */ + if (!(callback && ch_ctx->props.dir == GSI_CHAN_DIR_FROM_GSI)) { + ch_ctx->stats.completed++; + ch_ctx->user_data[rp_idx].valid = false; + } notify->chan_user_data = ch_ctx->props.chan_user_data; notify->evt_id = evt->code; @@ -572,10 +586,18 @@ static void gsi_process_evt_re(struct gsi_evt_ctx *ctx, struct gsi_chan_xfer_notify *notify, bool callback) { struct gsi_xfer_compl_evt *evt; + struct gsi_chan_ctx *ch_ctx; evt = (struct gsi_xfer_compl_evt *)(ctx->ring.base_va + ctx->ring.rp_local - ctx->ring.base); gsi_process_chan(evt, notify, callback); + /* + * Increment RP local only in polling context to avoid + * sys len mismatch. + */ + ch_ctx = &gsi_ctx->chan[evt->chid]; + if (callback && ch_ctx->props.dir == GSI_CHAN_DIR_FROM_GSI) + return; gsi_incr_ring_rp(&ctx->ring); /* recycle this element */ gsi_incr_ring_wp(&ctx->ring); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 4ba8cc8667cc..d56551d9de92 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -4594,8 +4594,14 @@ static void ipa_gsi_irq_rx_notify_cb(struct gsi_chan_xfer_notify *notify) sys = (struct ipa3_sys_context *)notify->chan_user_data; - - sys->ep->xfer_notify_valid = true; + /* + * In suspend just before stopping the channel possible to receive + * the IEOB interrupt and xfer pointer will not be processed in this + * mode and moving channel poll mode. In resume after starting the + * channel will receive the IEOB interrupt and xfer pointer will be + * overwritten. To avoid this process all data in polling context. + */ + sys->ep->xfer_notify_valid = false; sys->ep->xfer_notify = *notify; switch (notify->evt_id) { @@ -4630,7 +4636,7 @@ static void ipa_dma_gsi_irq_rx_notify_cb(struct gsi_chan_xfer_notify *notify) return; } - sys->ep->xfer_notify_valid = true; + sys->ep->xfer_notify_valid = false; sys->ep->xfer_notify = *notify; switch (notify->evt_id) {