diff options
author | Arend van Spriel <arend@broadcom.com> | 2013-04-03 06:40:41 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-04-03 15:07:06 -0400 |
commit | 0f8b5cc5214b0c8c772d9ba0a41f5b1f07aff274 (patch) | |
tree | ae50467fa33d4f2c7858514fd922afa66386b8fc | |
parent | 3edc1cff02a40a76ad6a5e2b9cb00a29584f33ad (diff) |
brcmfmac: fix handling sk_buff cleanup upon bus tx failure
When firmware-signalling is active the brcmf_txcomplete() does
a free of the sk_buff when transfer to firmware fails in the
bus-specific driver code. However, it should also cleanup the
packet from the hanger. This patch fixes that.
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: Piotr Haber <phaber@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c | 12 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | 34 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h | 1 |
3 files changed, 33 insertions, 14 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 0299ab6731b2..d37620e93e61 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c | |||
@@ -388,11 +388,13 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success) | |||
388 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); | 388 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); |
389 | struct brcmf_pub *drvr = bus_if->drvr; | 389 | struct brcmf_pub *drvr = bus_if->drvr; |
390 | 390 | ||
391 | /* await txstatus signal for firmware is active */ | 391 | /* await txstatus signal for firmware if active */ |
392 | if (success && brcmf_fws_fc_active(drvr->fws)) | 392 | if (brcmf_fws_fc_active(drvr->fws)) { |
393 | return; | 393 | if (!success) |
394 | 394 | brcmf_fws_bustxfail(drvr->fws, txp); | |
395 | brcmf_txfinalize(drvr, txp, success); | 395 | } else { |
396 | brcmf_txfinalize(drvr, txp, success); | ||
397 | } | ||
396 | } | 398 | } |
397 | 399 | ||
398 | static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev) | 400 | static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev) |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c index 9389bf7b7696..eb63419cece0 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | |||
@@ -810,20 +810,12 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data) | |||
810 | } | 810 | } |
811 | 811 | ||
812 | static int | 812 | static int |
813 | brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data) | 813 | brcmf_fws_txstatus_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot) |
814 | { | 814 | { |
815 | u8 flags; | ||
816 | u32 status; | ||
817 | u32 hslot; | ||
818 | int ret; | 815 | int ret; |
819 | struct sk_buff *skb; | 816 | struct sk_buff *skb; |
820 | struct brcmf_fws_mac_descriptor *entry = NULL; | 817 | struct brcmf_fws_mac_descriptor *entry = NULL; |
821 | 818 | ||
822 | status = le32_to_cpu(*(__le32 *)data); | ||
823 | flags = brcmf_txstatus_get_field(status, FLAGS); | ||
824 | hslot = brcmf_txstatus_get_field(status, HSLOT); | ||
825 | fws->stats.txs_indicate++; | ||
826 | |||
827 | brcmf_dbg(TRACE, "status: flags=0x%X, hslot=%d\n", | 819 | brcmf_dbg(TRACE, "status: flags=0x%X, hslot=%d\n", |
828 | flags, hslot); | 820 | flags, hslot); |
829 | 821 | ||
@@ -854,6 +846,20 @@ done: | |||
854 | return ret; | 846 | return ret; |
855 | } | 847 | } |
856 | 848 | ||
849 | static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data) | ||
850 | { | ||
851 | u32 status; | ||
852 | u32 hslot; | ||
853 | u8 flags; | ||
854 | |||
855 | fws->stats.txs_indicate++; | ||
856 | status = le32_to_cpu(*(__le32 *)data); | ||
857 | flags = brcmf_txstatus_get_field(status, FLAGS); | ||
858 | hslot = brcmf_txstatus_get_field(status, HSLOT); | ||
859 | |||
860 | return brcmf_fws_txstatus_process(fws, flags, hslot); | ||
861 | } | ||
862 | |||
857 | static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data) | 863 | static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data) |
858 | { | 864 | { |
859 | __le32 timestamp; | 865 | __le32 timestamp; |
@@ -1289,3 +1295,13 @@ bool brcmf_fws_fc_active(struct brcmf_fws_info *fws) | |||
1289 | brcmf_dbg(TRACE, "enter: mode=%d\n", fws->fcmode); | 1295 | brcmf_dbg(TRACE, "enter: mode=%d\n", fws->fcmode); |
1290 | return fws->fcmode != BRCMF_FWS_FCMODE_NONE; | 1296 | return fws->fcmode != BRCMF_FWS_FCMODE_NONE; |
1291 | } | 1297 | } |
1298 | |||
1299 | void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb) | ||
1300 | { | ||
1301 | ulong flags; | ||
1302 | |||
1303 | brcmf_fws_lock(fws->drvr, flags); | ||
1304 | brcmf_fws_txstatus_process(fws, BRCMF_FWS_TXSTATUS_FW_TOSSED, | ||
1305 | brcmf_skb_htod_tag_get_field(skb, HSLOT)); | ||
1306 | brcmf_fws_unlock(fws->drvr, flags); | ||
1307 | } | ||
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h index 7778e02d7581..fbe483d23752 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h | |||
@@ -28,5 +28,6 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb); | |||
28 | void brcmf_fws_reset_interface(struct brcmf_if *ifp); | 28 | void brcmf_fws_reset_interface(struct brcmf_if *ifp); |
29 | void brcmf_fws_add_interface(struct brcmf_if *ifp); | 29 | void brcmf_fws_add_interface(struct brcmf_if *ifp); |
30 | void brcmf_fws_del_interface(struct brcmf_if *ifp); | 30 | void brcmf_fws_del_interface(struct brcmf_if *ifp); |
31 | void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb); | ||
31 | 32 | ||
32 | #endif /* FWSIGNAL_H_ */ | 33 | #endif /* FWSIGNAL_H_ */ |