@@ -933,6 +933,10 @@ struct ieee80211_local {
struct net_device napi_dev;
struct napi_struct napi;
+
+ struct timer_list iface_work_timer;
+ unsigned long iface_work_tstmp;
+ unsigned int iface_work_runcnt;
};
static inline struct ieee80211_sub_if_data *
@@ -715,6 +715,14 @@ static void ieee80211_if_setup(struct net_device *dev)
dev->destructor = free_netdev;
}
+static void dbg_watchdog_timer(unsigned long __arg)
+{
+ struct ieee80211_local *local = (void *)__arg;
+
+ pr_warning("ieee80211_iface_work ran for > 5secs, processed %u\n",
+ local->iface_work_runcnt);
+}
+
static void ieee80211_iface_work(struct work_struct *work)
{
struct ieee80211_sub_if_data *sdata =
@@ -738,10 +746,21 @@ static void ieee80211_iface_work(struct work_struct *work)
"interface work scheduled while going to suspend\n"))
return;
+ local->iface_work_tstmp = jiffies;
+ local->iface_work_runcnt = 0;
+
+ init_timer(&local->iface_work_timer);
+ local->iface_work_timer.function = dbg_watchdog_timer;
+ local->iface_work_timer.data = (unsigned long)local;
+ local->iface_work_timer.expires = local->iface_work_tstmp + 5 * HZ;
+ add_timer(&local->iface_work_timer);
+
/* first process frames */
while ((skb = skb_dequeue(&sdata->skb_queue))) {
struct ieee80211_mgmt *mgmt = (void *)skb->data;
+ local->iface_work_runcnt++;
+
if (skb->pkt_type == IEEE80211_SDATA_QUEUE_AGG_START) {
ra_tid = (void *)&skb->cb;
ieee80211_start_tx_ba_cb(&sdata->vif, ra_tid->ra,
@@ -843,6 +862,12 @@ static void ieee80211_iface_work(struct work_struct *work)
default:
break;
}
+
+ del_timer_sync(&local->iface_work_timer);
+ if (time_after(jiffies, local->iface_work_tstmp + 4 * HZ))
+ pr_warning("iee80211_iface_work ran for %lu seconds, runcnt=%u\n",
+ (jiffies - local->iface_work_tstmp) / HZ,
+ local->iface_work_runcnt);
}