Commit 0f8b5cc5 authored by Arend van Spriel's avatar Arend van Spriel Committed by John W. Linville

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: default avatarHante Meuleman <meuleman@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: default avatarPiotr Haber <phaber@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 3edc1cff
...@@ -388,11 +388,13 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success) ...@@ -388,11 +388,13 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr; struct brcmf_pub *drvr = bus_if->drvr;
/* await txstatus signal for firmware is active */ /* await txstatus signal for firmware if active */
if (success && brcmf_fws_fc_active(drvr->fws)) if (brcmf_fws_fc_active(drvr->fws)) {
return; if (!success)
brcmf_fws_bustxfail(drvr->fws, txp);
brcmf_txfinalize(drvr, txp, success); } else {
brcmf_txfinalize(drvr, txp, success);
}
} }
static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev) static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
......
...@@ -810,20 +810,12 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data) ...@@ -810,20 +810,12 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
} }
static int static int
brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data) brcmf_fws_txstatus_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot)
{ {
u8 flags;
u32 status;
u32 hslot;
int ret; int ret;
struct sk_buff *skb; struct sk_buff *skb;
struct brcmf_fws_mac_descriptor *entry = NULL; struct brcmf_fws_mac_descriptor *entry = NULL;
status = le32_to_cpu(*(__le32 *)data);
flags = brcmf_txstatus_get_field(status, FLAGS);
hslot = brcmf_txstatus_get_field(status, HSLOT);
fws->stats.txs_indicate++;
brcmf_dbg(TRACE, "status: flags=0x%X, hslot=%d\n", brcmf_dbg(TRACE, "status: flags=0x%X, hslot=%d\n",
flags, hslot); flags, hslot);
...@@ -854,6 +846,20 @@ brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data) ...@@ -854,6 +846,20 @@ brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data)
return ret; return ret;
} }
static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data)
{
u32 status;
u32 hslot;
u8 flags;
fws->stats.txs_indicate++;
status = le32_to_cpu(*(__le32 *)data);
flags = brcmf_txstatus_get_field(status, FLAGS);
hslot = brcmf_txstatus_get_field(status, HSLOT);
return brcmf_fws_txstatus_process(fws, flags, hslot);
}
static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data) static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data)
{ {
__le32 timestamp; __le32 timestamp;
...@@ -1289,3 +1295,13 @@ bool brcmf_fws_fc_active(struct brcmf_fws_info *fws) ...@@ -1289,3 +1295,13 @@ bool brcmf_fws_fc_active(struct brcmf_fws_info *fws)
brcmf_dbg(TRACE, "enter: mode=%d\n", fws->fcmode); brcmf_dbg(TRACE, "enter: mode=%d\n", fws->fcmode);
return fws->fcmode != BRCMF_FWS_FCMODE_NONE; return fws->fcmode != BRCMF_FWS_FCMODE_NONE;
} }
void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb)
{
ulong flags;
brcmf_fws_lock(fws->drvr, flags);
brcmf_fws_txstatus_process(fws, BRCMF_FWS_TXSTATUS_FW_TOSSED,
brcmf_skb_htod_tag_get_field(skb, HSLOT));
brcmf_fws_unlock(fws->drvr, flags);
}
...@@ -28,5 +28,6 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb); ...@@ -28,5 +28,6 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb);
void brcmf_fws_reset_interface(struct brcmf_if *ifp); void brcmf_fws_reset_interface(struct brcmf_if *ifp);
void brcmf_fws_add_interface(struct brcmf_if *ifp); void brcmf_fws_add_interface(struct brcmf_if *ifp);
void brcmf_fws_del_interface(struct brcmf_if *ifp); void brcmf_fws_del_interface(struct brcmf_if *ifp);
void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb);
#endif /* FWSIGNAL_H_ */ #endif /* FWSIGNAL_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment