Merge 4cf3b875af6a040663d63811788ff5241b9346f9 on remote branch
Change-Id: Ib75e12ab2bad0144523eeb57796ba1ca717f9201
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 56ddeb9..ccd7dfc 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -102,6 +102,8 @@
#define IPA_QMAP_ID_BYTE 0
+#define IPA_TX_MAX_DESC (50)
+
#define IPA_MEM_ALLOC_RETRY 5
static int ipa3_tx_switch_to_intr_mode(struct ipa3_sys_context *sys);
@@ -391,6 +393,15 @@
ipa3_write_done_common(sys, tx_pkt);
}
+static void ipa3_tasklet_schd_work(struct work_struct *work)
+{
+ struct ipa3_sys_context *sys;
+
+ sys = container_of(work, struct ipa3_sys_context, tasklet_work);
+ if (atomic_read(&sys->xmit_eot_cnt))
+ tasklet_schedule(&sys->tasklet);
+}
+
/**
* ipa_write_done() - this function will be (eventually) called when a Tx
* operation is complete
@@ -408,6 +419,7 @@
struct ipa3_sys_context *sys;
struct ipa3_tx_pkt_wrapper *this_pkt;
bool xmit_done = false;
+ unsigned int max_tx_pkt = 0;
sys = (struct ipa3_sys_context *)data;
spin_lock_bh(&sys->spinlock);
@@ -419,11 +431,22 @@
spin_unlock_bh(&sys->spinlock);
ipa3_write_done_common(sys, this_pkt);
spin_lock_bh(&sys->spinlock);
+ max_tx_pkt++;
if (xmit_done)
break;
}
+ /* If TX packets processing continuously in tasklet other
+ * softirqs are not able to run on that core which is leading
+ * to watchdog bark. For avoiding these scenarios exit from
+ * tasklet after reaching max limit.
+ */
+ if (max_tx_pkt >= IPA_TX_MAX_DESC)
+ break;
}
spin_unlock_bh(&sys->spinlock);
+
+ if (max_tx_pkt >= IPA_TX_MAX_DESC)
+ queue_work(sys->tasklet_wq, &sys->tasklet_work);
}
static int ipa3_napi_poll_tx_complete(struct ipa3_sys_context *sys, int budget)
@@ -1525,6 +1548,18 @@
goto fail_wq2;
}
+ snprintf(buff, IPA_RESOURCE_NAME_MAX, "ipataskletwq%d",
+ sys_in->client);
+
+ ep->sys->tasklet_wq = alloc_workqueue(buff,
+ WQ_MEM_RECLAIM | WQ_UNBOUND | WQ_SYSFS, 1);
+ if (!ep->sys->tasklet_wq) {
+ IPAERR("failed to create rep wq for client %d\n",
+ sys_in->client);
+ result = -EFAULT;
+ goto fail_wq_tasklet;
+ }
+
snprintf(buff, IPA_RESOURCE_NAME_MAX, "ipafreepagewq%d",
sys_in->client);
@@ -1596,9 +1631,12 @@
tx_completion_func = &ipa3_aux_napi_tx_complete;
atomic_set(&ep->sys->xmit_eot_cnt, 0);
- if (IPA_CLIENT_IS_PROD(sys_in->client))
+ if (IPA_CLIENT_IS_PROD(sys_in->client)) {
tasklet_init(&ep->sys->tasklet, ipa3_tasklet_write_done,
(unsigned long) ep->sys);
+ INIT_WORK(&ep->sys->tasklet_work,
+ ipa3_tasklet_schd_work);
+ }
if (sys_in->client == IPA_CLIENT_APPS_WAN_LOW_LAT_CONS)
tasklet_init(&ep->sys->tasklet, ipa3_tasklet_rx_notify,
(unsigned long) ep->sys);
@@ -1910,6 +1948,8 @@
if (ep->sys->freepage_wq)
destroy_workqueue(ep->sys->freepage_wq);
fail_wq3:
+ destroy_workqueue(ep->sys->tasklet_wq);
+fail_wq_tasklet:
destroy_workqueue(ep->sys->repl_wq);
fail_wq2:
destroy_workqueue(ep->sys->wq);
@@ -2118,7 +2158,8 @@
}
if (ep->sys->repl_wq)
flush_workqueue(ep->sys->repl_wq);
-
+ if (ep->sys->tasklet_wq)
+ flush_workqueue(ep->sys->tasklet_wq);
if (ep->sys->repl_hdlr == ipa3_replenish_rx_page_recycle) {
cancel_delayed_work_sync(&ep->sys->common_sys->freepage_work);
tasklet_kill(&ep->sys->common_sys->tasklet_find_freepage);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 36223f1..28a9dab 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -1220,6 +1220,7 @@
struct list_head pending_pkts[GSI_VEID_MAX];
atomic_t xmit_eot_cnt;
struct tasklet_struct tasklet;
+ struct work_struct tasklet_work;
bool skip_eot;
u32 eob_drop_cnt;
struct napi_struct napi_tx;
@@ -1253,6 +1254,7 @@
struct workqueue_struct *freepage_wq;
struct delayed_work freepage_work;
struct tasklet_struct tasklet_find_freepage;
+ struct workqueue_struct *tasklet_wq;
/* ordering is important - other immutable fields go below */
};