cb4b5c924f7578e78e38bb558a8a6d569f3a630a
[oweals/openwrt.git] /
1 From c80d26e81ef1802f30364b4ad1955c1443a592b9 Mon Sep 17 00:00:00 2001
2 From: Piotr Figiel <p.figiel@camlintechnologies.com>
3 Date: Mon, 4 Mar 2019 15:42:49 +0000
4 Subject: [PATCH] brcmfmac: fix WARNING during USB disconnect in case of
5  unempty psq
6
7 brcmu_pkt_buf_free_skb emits WARNING when attempting to free a sk_buff
8 which is part of any queue. After USB disconnect this may have happened
9 when brcmf_fws_hanger_cleanup() is called as per-interface psq was never
10 cleaned when removing the interface.
11 Change brcmf_fws_macdesc_cleanup() in a way that it removes the
12 corresponding packets from hanger table (to avoid double-free when
13 brcmf_fws_hanger_cleanup() is called) and add a call to clean-up the
14 interface specific packet queue.
15
16 Below is a WARNING during USB disconnect with Raspberry Pi WiFi dongle
17 running in AP mode. This was reproducible when the interface was
18 transmitting during the disconnect and is fixed with this commit.
19
20 ------------[ cut here ]------------
21 WARNING: CPU: 0 PID: 1171 at drivers/net/wireless/broadcom/brcm80211/brcmutil/utils.c:49 brcmu_pkt_buf_free_skb+0x3c/0x40
22 Modules linked in: nf_log_ipv4 nf_log_common xt_LOG xt_limit iptable_mangle xt_connmark xt_tcpudp xt_conntrack nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 iptable_filter ip_tables x_tables usb_f_mass_storage usb_f_rndis u_ether cdc_acm smsc95xx usbnet ci_hdrc_imx ci_hdrc ulpi usbmisc_imx 8250_exar 8250_pci 8250 8250_base libcomposite configfs udc_core
23 CPU: 0 PID: 1171 Comm: kworker/0:0 Not tainted 4.19.23-00075-gde33ed8 #99
24 Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
25 Workqueue: usb_hub_wq hub_event
26 [<8010ff84>] (unwind_backtrace) from [<8010bb64>] (show_stack+0x10/0x14)
27 [<8010bb64>] (show_stack) from [<80840278>] (dump_stack+0x88/0x9c)
28 [<80840278>] (dump_stack) from [<8011f5ec>] (__warn+0xfc/0x114)
29 [<8011f5ec>] (__warn) from [<8011f71c>] (warn_slowpath_null+0x40/0x48)
30 [<8011f71c>] (warn_slowpath_null) from [<805a476c>] (brcmu_pkt_buf_free_skb+0x3c/0x40)
31 [<805a476c>] (brcmu_pkt_buf_free_skb) from [<805bb6c4>] (brcmf_fws_cleanup+0x1e4/0x22c)
32 [<805bb6c4>] (brcmf_fws_cleanup) from [<805bc854>] (brcmf_fws_del_interface+0x58/0x68)
33 [<805bc854>] (brcmf_fws_del_interface) from [<805b66ac>] (brcmf_remove_interface+0x40/0x150)
34 [<805b66ac>] (brcmf_remove_interface) from [<805b6870>] (brcmf_detach+0x6c/0xb0)
35 [<805b6870>] (brcmf_detach) from [<805bdbb8>] (brcmf_usb_disconnect+0x30/0x4c)
36 [<805bdbb8>] (brcmf_usb_disconnect) from [<805e5d64>] (usb_unbind_interface+0x5c/0x1e0)
37 [<805e5d64>] (usb_unbind_interface) from [<804aab10>] (device_release_driver_internal+0x154/0x1ec)
38 [<804aab10>] (device_release_driver_internal) from [<804a97f4>] (bus_remove_device+0xcc/0xf8)
39 [<804a97f4>] (bus_remove_device) from [<804a6fc0>] (device_del+0x118/0x308)
40 [<804a6fc0>] (device_del) from [<805e488c>] (usb_disable_device+0xa0/0x1c8)
41 [<805e488c>] (usb_disable_device) from [<805dcf98>] (usb_disconnect+0x70/0x1d8)
42 [<805dcf98>] (usb_disconnect) from [<805ddd84>] (hub_event+0x464/0xf50)
43 [<805ddd84>] (hub_event) from [<80135a70>] (process_one_work+0x138/0x3f8)
44 [<80135a70>] (process_one_work) from [<80135d5c>] (worker_thread+0x2c/0x554)
45 [<80135d5c>] (worker_thread) from [<8013b1a0>] (kthread+0x124/0x154)
46 [<8013b1a0>] (kthread) from [<801010e8>] (ret_from_fork+0x14/0x2c)
47 Exception stack(0xecf8dfb0 to 0xecf8dff8)
48 dfa0:                                     00000000 00000000 00000000 00000000
49 dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
50 dfe0: 00000000 00000000 00000000 00000000 00000013 00000000
51 ---[ end trace 38d234018e9e2a90 ]---
52 ------------[ cut here ]------------
53
54 Signed-off-by: Piotr Figiel <p.figiel@camlintechnologies.com>
55 Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
56 ---
57  .../broadcom/brcm80211/brcmfmac/fwsignal.c    | 42 +++++++++++--------
58  1 file changed, 24 insertions(+), 18 deletions(-)
59
60 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
61 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
62 @@ -580,24 +580,6 @@ static bool brcmf_fws_ifidx_match(struct
63         return ifidx == *(int *)arg;
64  }
65  
66 -static void brcmf_fws_psq_flush(struct brcmf_fws_info *fws, struct pktq *q,
67 -                               int ifidx)
68 -{
69 -       bool (*matchfn)(struct sk_buff *, void *) = NULL;
70 -       struct sk_buff *skb;
71 -       int prec;
72 -
73 -       if (ifidx != -1)
74 -               matchfn = brcmf_fws_ifidx_match;
75 -       for (prec = 0; prec < q->num_prec; prec++) {
76 -               skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
77 -               while (skb) {
78 -                       brcmu_pkt_buf_free_skb(skb);
79 -                       skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
80 -               }
81 -       }
82 -}
83 -
84  static void brcmf_fws_hanger_init(struct brcmf_fws_hanger *hanger)
85  {
86         int i;
87 @@ -669,6 +651,28 @@ static inline int brcmf_fws_hanger_poppk
88         return 0;
89  }
90  
91 +static void brcmf_fws_psq_flush(struct brcmf_fws_info *fws, struct pktq *q,
92 +                               int ifidx)
93 +{
94 +       bool (*matchfn)(struct sk_buff *, void *) = NULL;
95 +       struct sk_buff *skb;
96 +       int prec;
97 +       u32 hslot;
98 +
99 +       if (ifidx != -1)
100 +               matchfn = brcmf_fws_ifidx_match;
101 +       for (prec = 0; prec < q->num_prec; prec++) {
102 +               skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
103 +               while (skb) {
104 +                       hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
105 +                       brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
106 +                                               true);
107 +                       brcmu_pkt_buf_free_skb(skb);
108 +                       skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
109 +               }
110 +       }
111 +}
112 +
113  static int brcmf_fws_hanger_mark_suppressed(struct brcmf_fws_hanger *h,
114                                             u32 slot_id)
115  {
116 @@ -2200,6 +2204,8 @@ void brcmf_fws_del_interface(struct brcm
117         brcmf_fws_lock(fws);
118         ifp->fws_desc = NULL;
119         brcmf_dbg(TRACE, "deleting %s\n", entry->name);
120 +       brcmf_fws_macdesc_cleanup(fws, &fws->desc.iface[ifp->ifidx],
121 +                                 ifp->ifidx);
122         brcmf_fws_macdesc_deinit(entry);
123         brcmf_fws_cleanup(fws, ifp->ifidx);
124         brcmf_fws_unlock(fws);