diff options
author | Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com> | 2015-02-01 03:55:13 -0500 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2015-02-03 08:36:34 -0500 |
commit | 5933a06dc96cad21b7c125995791c93a86be7915 (patch) | |
tree | cee8a4f99f6329f43595c9d03df5120d9b40daf8 /drivers/net/wireless | |
parent | e59d16c08b3aa147f5c3c664d5dfda77fa93a827 (diff) |
wil6210: fix race between xmit and Tx vring de-allocation
Use spinlock, this should not impact Tx as lock is always free
except for de-allocation.
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/ath/wil6210/txrx.c | 25 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/wil6210.h | 1 |
2 files changed, 23 insertions, 3 deletions
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index e37cab1c5a53..85ecea2e6a67 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c | |||
@@ -671,6 +671,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, | |||
671 | } | 671 | } |
672 | 672 | ||
673 | memset(txdata, 0, sizeof(*txdata)); | 673 | memset(txdata, 0, sizeof(*txdata)); |
674 | spin_lock_init(&txdata->lock); | ||
674 | vring->size = size; | 675 | vring->size = size; |
675 | rc = wil_vring_alloc(wil, vring); | 676 | rc = wil_vring_alloc(wil, vring); |
676 | if (rc) | 677 | if (rc) |
@@ -718,8 +719,10 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id) | |||
718 | 719 | ||
719 | wil_dbg_misc(wil, "%s() id=%d\n", __func__, id); | 720 | wil_dbg_misc(wil, "%s() id=%d\n", __func__, id); |
720 | 721 | ||
722 | spin_lock_bh(&txdata->lock); | ||
723 | txdata->enabled = 0; /* no Tx can be in progress or start anew */ | ||
724 | spin_unlock_bh(&txdata->lock); | ||
721 | /* make sure NAPI won't touch this vring */ | 725 | /* make sure NAPI won't touch this vring */ |
722 | wil->vring_tx_data[id].enabled = 0; | ||
723 | if (test_bit(wil_status_napi_en, wil->status)) | 726 | if (test_bit(wil_status_napi_en, wil->status)) |
724 | napi_synchronize(&wil->napi_tx); | 727 | napi_synchronize(&wil->napi_tx); |
725 | 728 | ||
@@ -935,8 +938,8 @@ static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil, | |||
935 | return 0; | 938 | return 0; |
936 | } | 939 | } |
937 | 940 | ||
938 | static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | 941 | static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, |
939 | struct sk_buff *skb) | 942 | struct sk_buff *skb) |
940 | { | 943 | { |
941 | struct device *dev = wil_to_dev(wil); | 944 | struct device *dev = wil_to_dev(wil); |
942 | struct vring_tx_desc dd, *d = ⅆ | 945 | struct vring_tx_desc dd, *d = ⅆ |
@@ -952,6 +955,9 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | |||
952 | 955 | ||
953 | wil_dbg_txrx(wil, "%s()\n", __func__); | 956 | wil_dbg_txrx(wil, "%s()\n", __func__); |
954 | 957 | ||
958 | if (unlikely(!txdata->enabled)) | ||
959 | return -EINVAL; | ||
960 | |||
955 | if (avail < 1 + nr_frags) { | 961 | if (avail < 1 + nr_frags) { |
956 | wil_err_ratelimited(wil, | 962 | wil_err_ratelimited(wil, |
957 | "Tx ring full. No space for %d fragments\n", | 963 | "Tx ring full. No space for %d fragments\n", |
@@ -1050,6 +1056,19 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | |||
1050 | return -EINVAL; | 1056 | return -EINVAL; |
1051 | } | 1057 | } |
1052 | 1058 | ||
1059 | static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | ||
1060 | struct sk_buff *skb) | ||
1061 | { | ||
1062 | int vring_index = vring - wil->vring_tx; | ||
1063 | struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index]; | ||
1064 | int rc; | ||
1065 | |||
1066 | spin_lock(&txdata->lock); | ||
1067 | rc = __wil_tx_vring(wil, vring, skb); | ||
1068 | spin_unlock(&txdata->lock); | ||
1069 | return rc; | ||
1070 | } | ||
1071 | |||
1053 | netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) | 1072 | netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) |
1054 | { | 1073 | { |
1055 | struct wil6210_priv *wil = ndev_to_wil(ndev); | 1074 | struct wil6210_priv *wil = ndev_to_wil(ndev); |
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 90dc24fb60f8..94611568fc9a 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h | |||
@@ -385,6 +385,7 @@ struct vring_tx_data { | |||
385 | u16 agg_timeout; | 385 | u16 agg_timeout; |
386 | u8 agg_amsdu; | 386 | u8 agg_amsdu; |
387 | bool addba_in_progress; /* if set, agg_xxx is for request in progress */ | 387 | bool addba_in_progress; /* if set, agg_xxx is for request in progress */ |
388 | spinlock_t lock; | ||
388 | }; | 389 | }; |
389 | 390 | ||
390 | enum { /* for wil6210_priv.status */ | 391 | enum { /* for wil6210_priv.status */ |