aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArend van Spriel <arend@broadcom.com>2013-04-03 06:40:41 -0400
committerJohn W. Linville <linville@tuxdriver.com>2013-04-03 15:07:06 -0400
commit0f8b5cc5214b0c8c772d9ba0a41f5b1f07aff274 (patch)
treeae50467fa33d4f2c7858514fd922afa66386b8fc
parent3edc1cff02a40a76ad6a5e2b9cb00a29584f33ad (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.c12
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c34
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h1
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
398static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev) 400static 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
812static int 812static int
813brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data) 813brcmf_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
849static 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
857static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data) 863static 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
1299void 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);
28void brcmf_fws_reset_interface(struct brcmf_if *ifp); 28void brcmf_fws_reset_interface(struct brcmf_if *ifp);
29void brcmf_fws_add_interface(struct brcmf_if *ifp); 29void brcmf_fws_add_interface(struct brcmf_if *ifp);
30void brcmf_fws_del_interface(struct brcmf_if *ifp); 30void brcmf_fws_del_interface(struct brcmf_if *ifp);
31void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb);
31 32
32#endif /* FWSIGNAL_H_ */ 33#endif /* FWSIGNAL_H_ */