aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
authorMichal Kazior <michal.kazior@tieto.com>2015-01-29 07:29:52 -0500
committerKalle Valo <kvalo@qca.qualcomm.com>2015-02-04 02:17:06 -0500
commitaf21319fcda4c43aa89186e0d6001432c5d6000e (patch)
treefe9b5cb9253eb4be726929027e83d4addae7fd1e /drivers/net/wireless/ath
parent9ad501827bd153dc2865dd60a456e3e43283b507 (diff)
ath10k: fix beacon deadlock
This should fix a very rare occurrence of the following deadlock: [<ffffffffa018265e>] ath10k_wmi_tx_beacons_nowait+0x1e/0x50 [ath10k_core] [<ffffffffa01829b6>] ath10k_wmi_op_ep_tx_credits+0x16/0x40 [ath10k_core] [<ffffffffa017d685>] ath10k_htc_send+0x285/0x3d0 [ath10k_core] [<ffffffffa0184b81>] ath10k_wmi_cmd_send_nowait+0x81/0x110 [ath10k_core] [<ffffffffa0184c61>] ath10k_wmi_tx_beacon_nowait.part.33+0x51/0x90 [ath10k_core] [<ffffffffa0184cd0>] ath10k_wmi_tx_beacons_iter+0x30/0x40 [ath10k_core] [<ffffffff81882246>] __iterate_active_interfaces+0xa6/0x100 [<ffffffffa0184ca0>] ? ath10k_wmi_tx_beacon_nowait.part.33+0x90/0x90 [ath10k_core] [<ffffffff818822ae>] ieee80211_iterate_active_interfaces_atomic+0xe/0x10 [<ffffffffa0182676>] ath10k_wmi_tx_beacons_nowait+0x36/0x50 [ath10k_core] [<ffffffffa01829b6>] ath10k_wmi_op_ep_tx_credits+0x16/0x40 [ath10k_core] [<ffffffffa017d140>] ath10k_htc_rx+0x280/0x410 [ath10k_core] [<ffffffffa01bcbf0>] ? ath10k_ce_completed_recv_next+0x60/0x80 [ath10k_pci] [<ffffffffa01bc6ab>] ath10k_pci_ce_recv_data+0x11b/0x1d0 [ath10k_pci] [<ffffffffa01bcf44>] ath10k_ce_per_engine_service+0x64/0xc0 [ath10k_pci] [<ffffffffa01bcfc2>] ath10k_ce_per_engine_service_any+0x22/0x50 [ath10k_pci] [<ffffffffa01bc4d0>] ath10k_pci_tasklet+0x30/0x90 [ath10k_pci] [<ffffffff81055a55>] tasklet_action+0xc5/0x100 To prevent this make sure to release ar->data_lock while calling to ath10k_wmi_beacon_send_ref_nowait(). Signed-off-by: Michal Kazior <michal.kazior@tieto.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h8
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c6
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c68
3 files changed, 58 insertions, 24 deletions
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index a47b41dd966f..c8ba6bd4b968 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -262,6 +262,12 @@ struct ath10k_sta {
262 262
263#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ) 263#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ)
264 264
265enum ath10k_beacon_state {
266 ATH10K_BEACON_SCHEDULED = 0,
267 ATH10K_BEACON_SENDING,
268 ATH10K_BEACON_SENT,
269};
270
265struct ath10k_vif { 271struct ath10k_vif {
266 struct list_head list; 272 struct list_head list;
267 273
@@ -272,7 +278,7 @@ struct ath10k_vif {
272 u32 dtim_period; 278 u32 dtim_period;
273 struct sk_buff *beacon; 279 struct sk_buff *beacon;
274 /* protected by data_lock */ 280 /* protected by data_lock */
275 bool beacon_sent; 281 enum ath10k_beacon_state beacon_state;
276 void *beacon_buf; 282 void *beacon_buf;
277 dma_addr_t beacon_paddr; 283 dma_addr_t beacon_paddr;
278 284
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index d3fe1a378e8b..d0d882d632d1 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -531,10 +531,14 @@ void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif)
531 dma_unmap_single(ar->dev, ATH10K_SKB_CB(arvif->beacon)->paddr, 531 dma_unmap_single(ar->dev, ATH10K_SKB_CB(arvif->beacon)->paddr,
532 arvif->beacon->len, DMA_TO_DEVICE); 532 arvif->beacon->len, DMA_TO_DEVICE);
533 533
534 if (WARN_ON(arvif->beacon_state != ATH10K_BEACON_SCHEDULED &&
535 arvif->beacon_state != ATH10K_BEACON_SENT))
536 return;
537
534 dev_kfree_skb_any(arvif->beacon); 538 dev_kfree_skb_any(arvif->beacon);
535 539
536 arvif->beacon = NULL; 540 arvif->beacon = NULL;
537 arvif->beacon_sent = false; 541 arvif->beacon_state = ATH10K_BEACON_SCHEDULED;
538} 542}
539 543
540static void ath10k_mac_vif_beacon_cleanup(struct ath10k_vif *arvif) 544static void ath10k_mac_vif_beacon_cleanup(struct ath10k_vif *arvif)
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 01c0230cbf9b..d6c5b423b836 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -956,30 +956,45 @@ err_pull:
956 956
957static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) 957static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif)
958{ 958{
959 struct sk_buff *bcn; 959 struct ath10k *ar = arvif->ar;
960 struct ath10k_skb_cb *cb; 960 struct ath10k_skb_cb *cb;
961 struct sk_buff *bcn;
961 int ret; 962 int ret;
962 963
963 lockdep_assert_held(&arvif->ar->data_lock); 964 spin_lock_bh(&ar->data_lock);
964 965
965 if (arvif->beacon == NULL) 966 bcn = arvif->beacon;
966 return;
967 967
968 if (arvif->beacon_sent) 968 if (!bcn)
969 return; 969 goto unlock;
970 970
971 bcn = arvif->beacon;
972 cb = ATH10K_SKB_CB(bcn); 971 cb = ATH10K_SKB_CB(bcn);
973 ret = ath10k_wmi_beacon_send_ref_nowait(arvif->ar, arvif->vdev_id,
974 bcn->data, bcn->len, cb->paddr,
975 cb->bcn.dtim_zero,
976 cb->bcn.deliver_cab);
977 if (ret)
978 return;
979 972
980 /* We need to retain the arvif->beacon reference for DMA unmapping and 973 switch (arvif->beacon_state) {
981 * freeing the skbuff later. */ 974 case ATH10K_BEACON_SENDING:
982 arvif->beacon_sent = true; 975 case ATH10K_BEACON_SENT:
976 break;
977 case ATH10K_BEACON_SCHEDULED:
978 arvif->beacon_state = ATH10K_BEACON_SENDING;
979 spin_unlock_bh(&ar->data_lock);
980
981 ret = ath10k_wmi_beacon_send_ref_nowait(arvif->ar,
982 arvif->vdev_id,
983 bcn->data, bcn->len,
984 cb->paddr,
985 cb->bcn.dtim_zero,
986 cb->bcn.deliver_cab);
987
988 spin_lock_bh(&ar->data_lock);
989
990 if (ret == 0)
991 arvif->beacon_state = ATH10K_BEACON_SENT;
992 else
993 arvif->beacon_state = ATH10K_BEACON_SCHEDULED;
994 }
995
996unlock:
997 spin_unlock_bh(&ar->data_lock);
983} 998}
984 999
985static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac, 1000static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac,
@@ -992,12 +1007,10 @@ static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac,
992 1007
993static void ath10k_wmi_tx_beacons_nowait(struct ath10k *ar) 1008static void ath10k_wmi_tx_beacons_nowait(struct ath10k *ar)
994{ 1009{
995 spin_lock_bh(&ar->data_lock);
996 ieee80211_iterate_active_interfaces_atomic(ar->hw, 1010 ieee80211_iterate_active_interfaces_atomic(ar->hw,
997 IEEE80211_IFACE_ITER_NORMAL, 1011 IEEE80211_IFACE_ITER_NORMAL,
998 ath10k_wmi_tx_beacons_iter, 1012 ath10k_wmi_tx_beacons_iter,
999 NULL); 1013 NULL);
1000 spin_unlock_bh(&ar->data_lock);
1001} 1014}
1002 1015
1003static void ath10k_wmi_op_ep_tx_credits(struct ath10k *ar) 1016static void ath10k_wmi_op_ep_tx_credits(struct ath10k *ar)
@@ -2459,9 +2472,19 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
2459 spin_lock_bh(&ar->data_lock); 2472 spin_lock_bh(&ar->data_lock);
2460 2473
2461 if (arvif->beacon) { 2474 if (arvif->beacon) {
2462 if (!arvif->beacon_sent) 2475 switch (arvif->beacon_state) {
2463 ath10k_warn(ar, "SWBA overrun on vdev %d\n", 2476 case ATH10K_BEACON_SENT:
2477 break;
2478 case ATH10K_BEACON_SCHEDULED:
2479 ath10k_warn(ar, "SWBA overrun on vdev %d, skipped old beacon\n",
2480 arvif->vdev_id);
2481 break;
2482 case ATH10K_BEACON_SENDING:
2483 ath10k_warn(ar, "SWBA overrun on vdev %d, skipped new beacon\n",
2464 arvif->vdev_id); 2484 arvif->vdev_id);
2485 dev_kfree_skb(bcn);
2486 goto skip;
2487 }
2465 2488
2466 ath10k_mac_vif_beacon_free(arvif); 2489 ath10k_mac_vif_beacon_free(arvif);
2467 } 2490 }
@@ -2489,15 +2512,16 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
2489 } 2512 }
2490 2513
2491 arvif->beacon = bcn; 2514 arvif->beacon = bcn;
2492 arvif->beacon_sent = false; 2515 arvif->beacon_state = ATH10K_BEACON_SCHEDULED;
2493 2516
2494 trace_ath10k_tx_hdr(ar, bcn->data, bcn->len); 2517 trace_ath10k_tx_hdr(ar, bcn->data, bcn->len);
2495 trace_ath10k_tx_payload(ar, bcn->data, bcn->len); 2518 trace_ath10k_tx_payload(ar, bcn->data, bcn->len);
2496 2519
2497 ath10k_wmi_tx_beacon_nowait(arvif);
2498skip: 2520skip:
2499 spin_unlock_bh(&ar->data_lock); 2521 spin_unlock_bh(&ar->data_lock);
2500 } 2522 }
2523
2524 ath10k_wmi_tx_beacons_nowait(ar);
2501} 2525}
2502 2526
2503void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb) 2527void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb)