mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-06 08:46:46 +00:00
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>
This commit is contained in:
parent
3edc1cff02
commit
0f8b5cc521
3 changed files with 33 additions and 14 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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);
|
||||||
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_ */
|
||||||
|
|
Loading…
Reference in a new issue