aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
authorDedy Lansky <qca_dlansky@qca.qualcomm.com>2016-11-23 09:06:40 -0500
committerKalle Valo <kvalo@qca.qualcomm.com>2016-11-23 09:49:43 -0500
commitf9e3033ff7eb9a0018856f5295312f78828a34f2 (patch)
tree73189fafbe5cde02938e99dd0515c686e25f31aa /drivers/net/wireless/ath
parent40bea976c72b9ee60f8d097852deb53ccbeaffbe (diff)
wil6210: fix net queue stop/wake
Driver calls to netif_tx_stop_all_queues/netif_tx_wake_all_queues are inconsistent. In several cases, driver can get to a situation where net queues are stopped forever and data cannot be sent. The fix is to stop net queues if there is at least one vring which is "full" and to wake net queues if all vrings are not "full". Signed-off-by: Dedy Lansky <qca_dlansky@qca.qualcomm.com> Signed-off-by: Maya Erez <qca_merez@qca.qualcomm.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c12
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c2
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c110
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h6
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c3
5 files changed, 117 insertions, 16 deletions
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index e7130b54d1d8..b04ff87d6682 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -213,7 +213,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
213 memset(&sta->stats, 0, sizeof(sta->stats)); 213 memset(&sta->stats, 0, sizeof(sta->stats));
214} 214}
215 215
216static bool wil_ap_is_connected(struct wil6210_priv *wil) 216static bool wil_is_connected(struct wil6210_priv *wil)
217{ 217{
218 int i; 218 int i;
219 219
@@ -267,7 +267,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
267 case NL80211_IFTYPE_STATION: 267 case NL80211_IFTYPE_STATION:
268 case NL80211_IFTYPE_P2P_CLIENT: 268 case NL80211_IFTYPE_P2P_CLIENT:
269 wil_bcast_fini(wil); 269 wil_bcast_fini(wil);
270 netif_tx_stop_all_queues(ndev); 270 wil_update_net_queues_bh(wil, NULL, true);
271 netif_carrier_off(ndev); 271 netif_carrier_off(ndev);
272 272
273 if (test_bit(wil_status_fwconnected, wil->status)) { 273 if (test_bit(wil_status_fwconnected, wil->status)) {
@@ -283,8 +283,12 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
283 break; 283 break;
284 case NL80211_IFTYPE_AP: 284 case NL80211_IFTYPE_AP:
285 case NL80211_IFTYPE_P2P_GO: 285 case NL80211_IFTYPE_P2P_GO:
286 if (!wil_ap_is_connected(wil)) 286 if (!wil_is_connected(wil)) {
287 wil_update_net_queues_bh(wil, NULL, true);
287 clear_bit(wil_status_fwconnected, wil->status); 288 clear_bit(wil_status_fwconnected, wil->status);
289 } else {
290 wil_update_net_queues_bh(wil, NULL, false);
291 }
288 break; 292 break;
289 default: 293 default:
290 break; 294 break;
@@ -516,6 +520,8 @@ int wil_priv_init(struct wil6210_priv *wil)
516 INIT_LIST_HEAD(&wil->pending_wmi_ev); 520 INIT_LIST_HEAD(&wil->pending_wmi_ev);
517 INIT_LIST_HEAD(&wil->probe_client_pending); 521 INIT_LIST_HEAD(&wil->probe_client_pending);
518 spin_lock_init(&wil->wmi_ev_lock); 522 spin_lock_init(&wil->wmi_ev_lock);
523 spin_lock_init(&wil->net_queue_lock);
524 wil->net_queue_stopped = 1;
519 init_waitqueue_head(&wil->wq); 525 init_waitqueue_head(&wil->wq);
520 526
521 wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi"); 527 wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi");
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index d18372cdc8ca..6676001dcbca 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -214,7 +214,7 @@ int wil_if_add(struct wil6210_priv *wil)
214 netif_tx_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx, 214 netif_tx_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx,
215 WIL6210_NAPI_BUDGET); 215 WIL6210_NAPI_BUDGET);
216 216
217 netif_tx_stop_all_queues(ndev); 217 wil_update_net_queues_bh(wil, NULL, true);
218 218
219 rc = register_netdev(ndev); 219 rc = register_netdev(ndev);
220 if (rc < 0) { 220 if (rc < 0) {
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 4c38520d4dd2..4ac9ba04afed 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -88,6 +88,18 @@ static inline int wil_vring_wmark_high(struct vring *vring)
88 return vring->size/4; 88 return vring->size/4;
89} 89}
90 90
91/* returns true if num avail descriptors is lower than wmark_low */
92static inline int wil_vring_avail_low(struct vring *vring)
93{
94 return wil_vring_avail_tx(vring) < wil_vring_wmark_low(vring);
95}
96
97/* returns true if num avail descriptors is higher than wmark_high */
98static inline int wil_vring_avail_high(struct vring *vring)
99{
100 return wil_vring_avail_tx(vring) > wil_vring_wmark_high(vring);
101}
102
91/* wil_val_in_range - check if value in [min,max) */ 103/* wil_val_in_range - check if value in [min,max) */
92static inline bool wil_val_in_range(int val, int min, int max) 104static inline bool wil_val_in_range(int val, int min, int max)
93{ 105{
@@ -1780,6 +1792,89 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
1780 return rc; 1792 return rc;
1781} 1793}
1782 1794
1795/**
1796 * Check status of tx vrings and stop/wake net queues if needed
1797 *
1798 * This function does one of two checks:
1799 * In case check_stop is true, will check if net queues need to be stopped. If
1800 * the conditions for stopping are met, netif_tx_stop_all_queues() is called.
1801 * In case check_stop is false, will check if net queues need to be waked. If
1802 * the conditions for waking are met, netif_tx_wake_all_queues() is called.
1803 * vring is the vring which is currently being modified by either adding
1804 * descriptors (tx) into it or removing descriptors (tx complete) from it. Can
1805 * be null when irrelevant (e.g. connect/disconnect events).
1806 *
1807 * The implementation is to stop net queues if modified vring has low
1808 * descriptor availability. Wake if all vrings are not in low descriptor
1809 * availability and modified vring has high descriptor availability.
1810 */
1811static inline void __wil_update_net_queues(struct wil6210_priv *wil,
1812 struct vring *vring,
1813 bool check_stop)
1814{
1815 int i;
1816
1817 if (vring)
1818 wil_dbg_txrx(wil, "vring %d, check_stop=%d, stopped=%d",
1819 (int)(vring - wil->vring_tx), check_stop,
1820 wil->net_queue_stopped);
1821 else
1822 wil_dbg_txrx(wil, "check_stop=%d, stopped=%d",
1823 check_stop, wil->net_queue_stopped);
1824
1825 if (check_stop == wil->net_queue_stopped)
1826 /* net queues already in desired state */
1827 return;
1828
1829 if (check_stop) {
1830 if (!vring || unlikely(wil_vring_avail_low(vring))) {
1831 /* not enough room in the vring */
1832 netif_tx_stop_all_queues(wil_to_ndev(wil));
1833 wil->net_queue_stopped = true;
1834 wil_dbg_txrx(wil, "netif_tx_stop called\n");
1835 }
1836 return;
1837 }
1838
1839 /* check wake */
1840 for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
1841 struct vring *cur_vring = &wil->vring_tx[i];
1842 struct vring_tx_data *txdata = &wil->vring_tx_data[i];
1843
1844 if (!cur_vring->va || !txdata->enabled || cur_vring == vring)
1845 continue;
1846
1847 if (wil_vring_avail_low(cur_vring)) {
1848 wil_dbg_txrx(wil, "vring %d full, can't wake\n",
1849 (int)(cur_vring - wil->vring_tx));
1850 return;
1851 }
1852 }
1853
1854 if (!vring || wil_vring_avail_high(vring)) {
1855 /* enough room in the vring */
1856 wil_dbg_txrx(wil, "calling netif_tx_wake\n");
1857 netif_tx_wake_all_queues(wil_to_ndev(wil));
1858 wil->net_queue_stopped = false;
1859 }
1860}
1861
1862void wil_update_net_queues(struct wil6210_priv *wil, struct vring *vring,
1863 bool check_stop)
1864{
1865 spin_lock(&wil->net_queue_lock);
1866 __wil_update_net_queues(wil, vring, check_stop);
1867 spin_unlock(&wil->net_queue_lock);
1868}
1869
1870void wil_update_net_queues_bh(struct wil6210_priv *wil, struct vring *vring,
1871 bool check_stop)
1872{
1873 spin_lock_bh(&wil->net_queue_lock);
1874 __wil_update_net_queues(wil, vring, check_stop);
1875 spin_unlock_bh(&wil->net_queue_lock);
1876}
1877
1783netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) 1878netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
1784{ 1879{
1785 struct wil6210_priv *wil = ndev_to_wil(ndev); 1880 struct wil6210_priv *wil = ndev_to_wil(ndev);
@@ -1822,14 +1917,10 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
1822 /* set up vring entry */ 1917 /* set up vring entry */
1823 rc = wil_tx_vring(wil, vring, skb); 1918 rc = wil_tx_vring(wil, vring, skb);
1824 1919
1825 /* do we still have enough room in the vring? */
1826 if (unlikely(wil_vring_avail_tx(vring) < wil_vring_wmark_low(vring))) {
1827 netif_tx_stop_all_queues(wil_to_ndev(wil));
1828 wil_dbg_txrx(wil, "netif_tx_stop : ring full\n");
1829 }
1830
1831 switch (rc) { 1920 switch (rc) {
1832 case 0: 1921 case 0:
1922 /* shall we stop net queues? */
1923 wil_update_net_queues_bh(wil, vring, true);
1833 /* statistics will be updated on the tx_complete */ 1924 /* statistics will be updated on the tx_complete */
1834 dev_kfree_skb_any(skb); 1925 dev_kfree_skb_any(skb);
1835 return NETDEV_TX_OK; 1926 return NETDEV_TX_OK;
@@ -1978,10 +2069,9 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
1978 txdata->last_idle = get_cycles(); 2069 txdata->last_idle = get_cycles();
1979 } 2070 }
1980 2071
1981 if (wil_vring_avail_tx(vring) > wil_vring_wmark_high(vring)) { 2072 /* shall we wake net queues? */
1982 wil_dbg_txrx(wil, "netif_tx_wake : ring not full\n"); 2073 if (done)
1983 netif_tx_wake_all_queues(wil_to_ndev(wil)); 2074 wil_update_net_queues(wil, vring, false);
1984 }
1985 2075
1986 return done; 2076 return done;
1987} 2077}
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index a949cd62bc4e..12cd81bccb47 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -624,6 +624,8 @@ struct wil6210_priv {
624 * - consumed in thread by wmi_event_worker 624 * - consumed in thread by wmi_event_worker
625 */ 625 */
626 spinlock_t wmi_ev_lock; 626 spinlock_t wmi_ev_lock;
627 spinlock_t net_queue_lock; /* guarding stop/wake netif queue */
628 int net_queue_stopped; /* netif_tx_stop_all_queues invoked */
627 struct napi_struct napi_rx; 629 struct napi_struct napi_rx;
628 struct napi_struct napi_tx; 630 struct napi_struct napi_tx;
629 /* keep alive */ 631 /* keep alive */
@@ -886,6 +888,10 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size);
886int wil_bcast_init(struct wil6210_priv *wil); 888int wil_bcast_init(struct wil6210_priv *wil);
887void wil_bcast_fini(struct wil6210_priv *wil); 889void wil_bcast_fini(struct wil6210_priv *wil);
888 890
891void wil_update_net_queues(struct wil6210_priv *wil, struct vring *vring,
892 bool should_stop);
893void wil_update_net_queues_bh(struct wil6210_priv *wil, struct vring *vring,
894 bool check_stop);
889netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev); 895netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev);
890int wil_tx_complete(struct wil6210_priv *wil, int ringid); 896int wil_tx_complete(struct wil6210_priv *wil, int ringid);
891void wil6210_unmask_irq_tx(struct wil6210_priv *wil); 897void wil6210_unmask_irq_tx(struct wil6210_priv *wil);
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index fae4f1285d08..890960e9b1d3 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -548,7 +548,6 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
548 if ((wdev->iftype == NL80211_IFTYPE_STATION) || 548 if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
549 (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { 549 (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
550 if (rc) { 550 if (rc) {
551 netif_tx_stop_all_queues(ndev);
552 netif_carrier_off(ndev); 551 netif_carrier_off(ndev);
553 wil_err(wil, 552 wil_err(wil,
554 "%s: cfg80211_connect_result with failure\n", 553 "%s: cfg80211_connect_result with failure\n",
@@ -588,7 +587,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
588 587
589 wil->sta[evt->cid].status = wil_sta_connected; 588 wil->sta[evt->cid].status = wil_sta_connected;
590 set_bit(wil_status_fwconnected, wil->status); 589 set_bit(wil_status_fwconnected, wil->status);
591 netif_tx_wake_all_queues(ndev); 590 wil_update_net_queues_bh(wil, NULL, false);
592 591
593out: 592out:
594 if (rc) 593 if (rc)