1 From b50ddfa8530e9b5f52e873fdd6ff04f327a88799 Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
3 Date: Fri, 17 Jun 2016 12:29:21 +0200
4 Subject: [PATCH] brcmfmac: fix lockup when removing P2P interface after event
7 Content-Type: text/plain; charset=UTF-8
8 Content-Transfer-Encoding: 8bit
10 Removing P2P interface is handled by sending a proper request to the
11 firmware. On success firmware triggers an event and driver's handler
12 removes a matching interface.
14 However on event timeout we remove interface directly from the cfg80211
15 callback. Current code doesn't handle this case correctly as it always
16 assumes rtnl to be unlocked.
18 Fix it by adding an extra rtnl_locked parameter to functions and calling
19 unregister_netdevice when needed.
21 Signed-off-by: RafaÅ
\82 MiÅ
\82ecki <zajec5@gmail.com>
22 Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
24 .../wireless/broadcom/brcm80211/brcmfmac/core.c | 29 +++++++++++++---------
25 .../wireless/broadcom/brcm80211/brcmfmac/core.h | 2 +-
26 .../wireless/broadcom/brcm80211/brcmfmac/fweh.c | 2 +-
27 .../net/wireless/broadcom/brcm80211/brcmfmac/p2p.c | 4 +--
28 4 files changed, 21 insertions(+), 16 deletions(-)
30 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
31 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
32 @@ -733,12 +733,16 @@ fail:
36 -static void brcmf_net_detach(struct net_device *ndev)
37 +static void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked)
39 - if (ndev->reg_state == NETREG_REGISTERED)
40 - unregister_netdev(ndev);
42 + if (ndev->reg_state == NETREG_REGISTERED) {
44 + unregister_netdevice(ndev);
46 + unregister_netdev(ndev);
48 brcmf_cfg80211_free_netdev(ndev);
52 void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on)
53 @@ -836,7 +840,7 @@ struct brcmf_if *brcmf_add_if(struct brc
54 brcmf_err("ERROR: netdev:%s already exists\n",
56 netif_stop_queue(ifp->ndev);
57 - brcmf_net_detach(ifp->ndev);
58 + brcmf_net_detach(ifp->ndev, false);
59 drvr->iflist[bsscfgidx] = NULL;
61 brcmf_dbg(INFO, "netdev:%s ignore IF event\n",
62 @@ -884,7 +888,8 @@ struct brcmf_if *brcmf_add_if(struct brc
66 -static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx)
67 +static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx,
72 @@ -914,7 +919,7 @@ static void brcmf_del_if(struct brcmf_pu
73 cancel_work_sync(&ifp->multicast_work);
74 cancel_work_sync(&ifp->ndoffload_work);
76 - brcmf_net_detach(ifp->ndev);
77 + brcmf_net_detach(ifp->ndev, rtnl_locked);
79 /* Only p2p device interfaces which get dynamically created
80 * end up here. In this case the p2p module should be informed
81 @@ -928,14 +933,14 @@ static void brcmf_del_if(struct brcmf_pu
85 -void brcmf_remove_interface(struct brcmf_if *ifp)
86 +void brcmf_remove_interface(struct brcmf_if *ifp, bool rtnl_locked)
88 if (!ifp || WARN_ON(ifp->drvr->iflist[ifp->bsscfgidx] != ifp))
90 brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, ifidx=%d\n", ifp->bsscfgidx,
92 brcmf_fws_del_interface(ifp);
93 - brcmf_del_if(ifp->drvr, ifp->bsscfgidx);
94 + brcmf_del_if(ifp->drvr, ifp->bsscfgidx, rtnl_locked);
98 @@ -1242,9 +1247,9 @@ fail:
99 brcmf_fws_deinit(drvr);
102 - brcmf_net_detach(ifp->ndev);
103 + brcmf_net_detach(ifp->ndev, false);
105 - brcmf_net_detach(p2p_ifp->ndev);
106 + brcmf_net_detach(p2p_ifp->ndev, false);
107 drvr->iflist[0] = NULL;
108 drvr->iflist[1] = NULL;
109 if (drvr->settings->ignore_probe_fail)
110 @@ -1313,7 +1318,7 @@ void brcmf_detach(struct device *dev)
112 /* make sure primary interface removed last */
113 for (i = BRCMF_MAX_IFS-1; i > -1; i--)
114 - brcmf_remove_interface(drvr->iflist[i]);
115 + brcmf_remove_interface(drvr->iflist[i], false);
117 brcmf_cfg80211_detach(drvr->config);
119 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
120 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
121 @@ -220,7 +220,7 @@ struct brcmf_if *brcmf_get_ifp(struct br
122 int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);
123 struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx,
124 bool is_p2pdev, char *name, u8 *mac_addr);
125 -void brcmf_remove_interface(struct brcmf_if *ifp);
126 +void brcmf_remove_interface(struct brcmf_if *ifp, bool rtnl_locked);
127 void brcmf_txflowblock_if(struct brcmf_if *ifp,
128 enum brcmf_netif_stop_reason reason, bool state);
129 void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
130 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
131 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
132 @@ -183,7 +183,7 @@ static void brcmf_fweh_handle_if_event(s
133 err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
135 if (ifp && ifevent->action == BRCMF_E_IF_DEL)
136 - brcmf_remove_interface(ifp);
137 + brcmf_remove_interface(ifp, false);
141 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
142 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
143 @@ -2289,7 +2289,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiph
147 - brcmf_remove_interface(vif->ifp);
148 + brcmf_remove_interface(vif->ifp, true);
150 brcmf_cfg80211_arm_vif_event(cfg, NULL);
151 if (vif->wdev.iftype != NL80211_IFTYPE_P2P_DEVICE)
152 @@ -2395,7 +2395,7 @@ void brcmf_p2p_detach(struct brcmf_p2p_i
154 brcmf_p2p_cancel_remain_on_channel(vif->ifp);
155 brcmf_p2p_deinit_discovery(p2p);
156 - brcmf_remove_interface(vif->ifp);
157 + brcmf_remove_interface(vif->ifp, false);
159 /* just set it all to zero */
160 memset(p2p, 0, sizeof(*p2p));