ath10k-firmware: remove dependency on kmod-ath10k so that it can be selected instead
[15.05/openwrt.git] / package / kernel / mac80211 / patches / 372-0002-brcmfmac-Fix-race-condition-between-USB-probe-load-a.patch
1 From: Hante Meuleman <meuleman@broadcom.com>
2 Date: Thu, 8 Oct 2015 20:33:12 +0200
3 Subject: [PATCH] brcmfmac: Fix race condition between USB probe/load and
4  disconnect.
5
6 When a USB device gets disconnected due to for example removal
7 then it is possible that it is still in the loading phase due to
8 the asynchronous load routines. These routines can then possible
9 access memory which has been freed. Fix this by mutex locking the
10 device init phase.
11
12 Reviewed-by: Arend Van Spriel <arend@broadcom.com>
13 Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
14 Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
15 Signed-off-by: Arend van Spriel <arend@broadcom.com>
16 Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
17 ---
18
19 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
20 +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
21 @@ -144,6 +144,7 @@ struct brcmf_usbdev_info {
22  
23         struct usb_device *usbdev;
24         struct device *dev;
25 +       struct mutex dev_init_lock;
26  
27         int ctl_in_pipe, ctl_out_pipe;
28         struct urb *ctl_urb; /* URB for control endpoint */
29 @@ -1204,6 +1205,8 @@ static void brcmf_usb_probe_phase2(struc
30         int ret;
31  
32         brcmf_dbg(USB, "Start fw downloading\n");
33 +
34 +       devinfo = bus->bus_priv.usb->devinfo;
35         ret = check_file(fw->data);
36         if (ret < 0) {
37                 brcmf_err("invalid firmware\n");
38 @@ -1211,7 +1214,6 @@ static void brcmf_usb_probe_phase2(struc
39                 goto error;
40         }
41  
42 -       devinfo = bus->bus_priv.usb->devinfo;
43         devinfo->image = fw->data;
44         devinfo->image_len = fw->size;
45  
46 @@ -1224,9 +1226,11 @@ static void brcmf_usb_probe_phase2(struc
47         if (ret)
48                 goto error;
49  
50 +       mutex_unlock(&devinfo->dev_init_lock);
51         return;
52  error:
53         brcmf_dbg(TRACE, "failed: dev=%s, err=%d\n", dev_name(dev), ret);
54 +       mutex_unlock(&devinfo->dev_init_lock);
55         device_release_driver(dev);
56  }
57  
58 @@ -1264,6 +1268,7 @@ static int brcmf_usb_probe_cb(struct brc
59                 if (ret)
60                         goto fail;
61                 /* we are done */
62 +               mutex_unlock(&devinfo->dev_init_lock);
63                 return 0;
64         }
65         bus->chip = bus_pub->devid;
66 @@ -1317,6 +1322,12 @@ brcmf_usb_probe(struct usb_interface *in
67  
68         devinfo->usbdev = usb;
69         devinfo->dev = &usb->dev;
70 +       /* Take an init lock, to protect for disconnect while still loading.
71 +        * Necessary because of the asynchronous firmware load construction
72 +        */
73 +       mutex_init(&devinfo->dev_init_lock);
74 +       mutex_lock(&devinfo->dev_init_lock);
75 +
76         usb_set_intfdata(intf, devinfo);
77  
78         /* Check that the device supports only one configuration */
79 @@ -1391,6 +1402,7 @@ brcmf_usb_probe(struct usb_interface *in
80         return 0;
81  
82  fail:
83 +       mutex_unlock(&devinfo->dev_init_lock);
84         kfree(devinfo);
85         usb_set_intfdata(intf, NULL);
86         return ret;
87 @@ -1403,8 +1415,19 @@ brcmf_usb_disconnect(struct usb_interfac
88  
89         brcmf_dbg(USB, "Enter\n");
90         devinfo = (struct brcmf_usbdev_info *)usb_get_intfdata(intf);
91 -       brcmf_usb_disconnect_cb(devinfo);
92 -       kfree(devinfo);
93 +
94 +       if (devinfo) {
95 +               mutex_lock(&devinfo->dev_init_lock);
96 +               /* Make sure that devinfo still exists. Firmware probe routines
97 +                * may have released the device and cleared the intfdata.
98 +                */
99 +               if (!usb_get_intfdata(intf))
100 +                       goto done;
101 +
102 +               brcmf_usb_disconnect_cb(devinfo);
103 +               kfree(devinfo);
104 +       }
105 +done:
106         brcmf_dbg(USB, "Exit\n");
107  }
108