]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-4.4/brcmfmac-screening-firmware-event-packet.patch
drop drm-rockchip-shutdown-drm-subsystem-on-shutdown.patch from 4.4.y and 4.9.y
[thirdparty/kernel/stable-queue.git] / queue-4.4 / brcmfmac-screening-firmware-event-packet.patch
1 From foo@baz Tue 04 Jun 2019 04:46:27 PM CEST
2 From: Franky Lin <franky.lin@broadcom.com>
3 Date: Mon, 11 Apr 2016 11:35:25 +0200
4 Subject: brcmfmac: screening firmware event packet
5
6 From: Franky Lin <franky.lin@broadcom.com>
7
8 commit c56caa9db8abbbfb9e31325e0897705aa897db37 upstream.
9
10 Firmware uses asynchronized events as a communication method to the
11 host. The event packets are marked as ETH_P_LINK_CTL protocol type. For
12 SDIO and PCIe bus, this kind of packets are delivered through virtual
13 event channel not data channel. This patch adds a screening logic to
14 make sure the event handler only processes the events coming from the
15 correct channel.
16
17 Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
18 Signed-off-by: Franky Lin <franky.lin@broadcom.com>
19 Signed-off-by: Arend van Spriel <arend@broadcom.com>
20 Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
21 [bwh: Backported to 4.4 adjust filenames]
22 Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
23 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
24 ---
25 drivers/net/wireless/brcm80211/brcmfmac/bus.h | 4 +-
26 drivers/net/wireless/brcm80211/brcmfmac/core.c | 46 ++++++++++++++++++-----
27 drivers/net/wireless/brcm80211/brcmfmac/core.h | 3 +
28 drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c | 42 ++++++++++++---------
29 drivers/net/wireless/brcm80211/brcmfmac/sdio.c | 32 ++++++++++++----
30 drivers/net/wireless/brcm80211/brcmfmac/usb.c | 2 -
31 6 files changed, 90 insertions(+), 39 deletions(-)
32
33 --- a/drivers/net/wireless/brcm80211/brcmfmac/bus.h
34 +++ b/drivers/net/wireless/brcm80211/brcmfmac/bus.h
35 @@ -214,7 +214,9 @@ bool brcmf_c_prec_enq(struct device *dev
36 int prec);
37
38 /* Receive frame for delivery to OS. Callee disposes of rxp. */
39 -void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp);
40 +void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp, bool handle_evnt);
41 +/* Receive async event packet from firmware. Callee disposes of rxp. */
42 +void brcmf_rx_event(struct device *dev, struct sk_buff *rxp);
43
44 /* Indication from bus module regarding presence/insertion of dongle. */
45 int brcmf_attach(struct device *dev);
46 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
47 +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
48 @@ -301,16 +301,17 @@ void brcmf_txflowblock(struct device *de
49 brcmf_fws_bus_blocked(drvr, state);
50 }
51
52 -void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
53 +void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb,
54 + bool handle_event)
55 {
56 - skb->dev = ifp->ndev;
57 - skb->protocol = eth_type_trans(skb, skb->dev);
58 + skb->protocol = eth_type_trans(skb, ifp->ndev);
59
60 if (skb->pkt_type == PACKET_MULTICAST)
61 ifp->stats.multicast++;
62
63 /* Process special event packets */
64 - brcmf_fweh_process_skb(ifp->drvr, skb);
65 + if (handle_event)
66 + brcmf_fweh_process_skb(ifp->drvr, skb);
67
68 if (!(ifp->ndev->flags & IFF_UP)) {
69 brcmu_pkt_buf_free_skb(skb);
70 @@ -371,7 +372,7 @@ static void brcmf_rxreorder_process_info
71 /* validate flags and flow id */
72 if (flags == 0xFF) {
73 brcmf_err("invalid flags...so ignore this packet\n");
74 - brcmf_netif_rx(ifp, pkt);
75 + brcmf_netif_rx(ifp, pkt, false);
76 return;
77 }
78
79 @@ -383,7 +384,7 @@ static void brcmf_rxreorder_process_info
80 if (rfi == NULL) {
81 brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n",
82 flow_id);
83 - brcmf_netif_rx(ifp, pkt);
84 + brcmf_netif_rx(ifp, pkt, false);
85 return;
86 }
87
88 @@ -408,7 +409,7 @@ static void brcmf_rxreorder_process_info
89 rfi = kzalloc(buf_size, GFP_ATOMIC);
90 if (rfi == NULL) {
91 brcmf_err("failed to alloc buffer\n");
92 - brcmf_netif_rx(ifp, pkt);
93 + brcmf_netif_rx(ifp, pkt, false);
94 return;
95 }
96
97 @@ -522,11 +523,11 @@ static void brcmf_rxreorder_process_info
98 netif_rx:
99 skb_queue_walk_safe(&reorder_list, pkt, pnext) {
100 __skb_unlink(pkt, &reorder_list);
101 - brcmf_netif_rx(ifp, pkt);
102 + brcmf_netif_rx(ifp, pkt, false);
103 }
104 }
105
106 -void brcmf_rx_frame(struct device *dev, struct sk_buff *skb)
107 +void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_evnt)
108 {
109 struct brcmf_if *ifp;
110 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
111 @@ -550,7 +551,32 @@ void brcmf_rx_frame(struct device *dev,
112 if (rd->reorder)
113 brcmf_rxreorder_process_info(ifp, rd->reorder, skb);
114 else
115 - brcmf_netif_rx(ifp, skb);
116 + brcmf_netif_rx(ifp, skb, handle_evnt);
117 +}
118 +
119 +void brcmf_rx_event(struct device *dev, struct sk_buff *skb)
120 +{
121 + struct brcmf_if *ifp;
122 + struct brcmf_bus *bus_if = dev_get_drvdata(dev);
123 + struct brcmf_pub *drvr = bus_if->drvr;
124 + int ret;
125 +
126 + brcmf_dbg(EVENT, "Enter: %s: rxp=%p\n", dev_name(dev), skb);
127 +
128 + /* process and remove protocol-specific header */
129 + ret = brcmf_proto_hdrpull(drvr, true, skb, &ifp);
130 +
131 + if (ret || !ifp || !ifp->ndev) {
132 + if (ret != -ENODATA && ifp)
133 + ifp->stats.rx_errors++;
134 + brcmu_pkt_buf_free_skb(skb);
135 + return;
136 + }
137 +
138 + skb->protocol = eth_type_trans(skb, ifp->ndev);
139 +
140 + brcmf_fweh_process_skb(ifp->drvr, skb);
141 + brcmu_pkt_buf_free_skb(skb);
142 }
143
144 void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)
145 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.h
146 +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h
147 @@ -215,7 +215,8 @@ int brcmf_get_next_free_bsscfgidx(struct
148 void brcmf_txflowblock_if(struct brcmf_if *ifp,
149 enum brcmf_netif_stop_reason reason, bool state);
150 void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
151 -void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
152 +void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb,
153 + bool handle_event);
154 void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on);
155
156 #endif /* BRCMFMAC_CORE_H */
157 --- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
158 +++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
159 @@ -20,6 +20,7 @@
160
161 #include <linux/types.h>
162 #include <linux/netdevice.h>
163 +#include <linux/etherdevice.h>
164
165 #include <brcmu_utils.h>
166 #include <brcmu_wifi.h>
167 @@ -1076,28 +1077,13 @@ static void brcmf_msgbuf_rxbuf_event_pos
168 }
169
170
171 -static void
172 -brcmf_msgbuf_rx_skb(struct brcmf_msgbuf *msgbuf, struct sk_buff *skb,
173 - u8 ifidx)
174 -{
175 - struct brcmf_if *ifp;
176 -
177 - ifp = brcmf_get_ifp(msgbuf->drvr, ifidx);
178 - if (!ifp || !ifp->ndev) {
179 - brcmf_err("Received pkt for invalid ifidx %d\n", ifidx);
180 - brcmu_pkt_buf_free_skb(skb);
181 - return;
182 - }
183 - brcmf_netif_rx(ifp, skb);
184 -}
185 -
186 -
187 static void brcmf_msgbuf_process_event(struct brcmf_msgbuf *msgbuf, void *buf)
188 {
189 struct msgbuf_rx_event *event;
190 u32 idx;
191 u16 buflen;
192 struct sk_buff *skb;
193 + struct brcmf_if *ifp;
194
195 event = (struct msgbuf_rx_event *)buf;
196 idx = le32_to_cpu(event->msg.request_id);
197 @@ -1117,7 +1103,19 @@ static void brcmf_msgbuf_process_event(s
198
199 skb_trim(skb, buflen);
200
201 - brcmf_msgbuf_rx_skb(msgbuf, skb, event->msg.ifidx);
202 + ifp = brcmf_get_ifp(msgbuf->drvr, event->msg.ifidx);
203 + if (!ifp || !ifp->ndev) {
204 + brcmf_err("Received pkt for invalid ifidx %d\n",
205 + event->msg.ifidx);
206 + goto exit;
207 + }
208 +
209 + skb->protocol = eth_type_trans(skb, ifp->ndev);
210 +
211 + brcmf_fweh_process_skb(ifp->drvr, skb);
212 +
213 +exit:
214 + brcmu_pkt_buf_free_skb(skb);
215 }
216
217
218 @@ -1129,6 +1127,7 @@ brcmf_msgbuf_process_rx_complete(struct
219 u16 data_offset;
220 u16 buflen;
221 u32 idx;
222 + struct brcmf_if *ifp;
223
224 brcmf_msgbuf_update_rxbufpost_count(msgbuf, 1);
225
226 @@ -1149,7 +1148,14 @@ brcmf_msgbuf_process_rx_complete(struct
227
228 skb_trim(skb, buflen);
229
230 - brcmf_msgbuf_rx_skb(msgbuf, skb, rx_complete->msg.ifidx);
231 + ifp = brcmf_get_ifp(msgbuf->drvr, rx_complete->msg.ifidx);
232 + if (!ifp || !ifp->ndev) {
233 + brcmf_err("Received pkt for invalid ifidx %d\n",
234 + rx_complete->msg.ifidx);
235 + brcmu_pkt_buf_free_skb(skb);
236 + return;
237 + }
238 + brcmf_netif_rx(ifp, skb, false);
239 }
240
241
242 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
243 +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
244 @@ -1394,6 +1394,17 @@ static inline u8 brcmf_sdio_getdatoffset
245 return (u8)((hdrvalue & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT);
246 }
247
248 +static inline bool brcmf_sdio_fromevntchan(u8 *swheader)
249 +{
250 + u32 hdrvalue;
251 + u8 ret;
252 +
253 + hdrvalue = *(u32 *)swheader;
254 + ret = (u8)((hdrvalue & SDPCM_CHANNEL_MASK) >> SDPCM_CHANNEL_SHIFT);
255 +
256 + return (ret == SDPCM_EVENT_CHANNEL);
257 +}
258 +
259 static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header,
260 struct brcmf_sdio_hdrinfo *rd,
261 enum brcmf_sdio_frmtype type)
262 @@ -1754,7 +1765,11 @@ static u8 brcmf_sdio_rxglom(struct brcmf
263 pfirst->len, pfirst->next,
264 pfirst->prev);
265 skb_unlink(pfirst, &bus->glom);
266 - brcmf_rx_frame(bus->sdiodev->dev, pfirst);
267 + if (brcmf_sdio_fromevntchan(pfirst->data))
268 + brcmf_rx_event(bus->sdiodev->dev, pfirst);
269 + else
270 + brcmf_rx_frame(bus->sdiodev->dev, pfirst,
271 + false);
272 bus->sdcnt.rxglompkts++;
273 }
274
275 @@ -2081,18 +2096,19 @@ static uint brcmf_sdio_readframes(struct
276 __skb_trim(pkt, rd->len);
277 skb_pull(pkt, rd->dat_offset);
278
279 + if (pkt->len == 0)
280 + brcmu_pkt_buf_free_skb(pkt);
281 + else if (rd->channel == SDPCM_EVENT_CHANNEL)
282 + brcmf_rx_event(bus->sdiodev->dev, pkt);
283 + else
284 + brcmf_rx_frame(bus->sdiodev->dev, pkt,
285 + false);
286 +
287 /* prepare the descriptor for the next read */
288 rd->len = rd->len_nxtfrm << 4;
289 rd->len_nxtfrm = 0;
290 /* treat all packet as event if we don't know */
291 rd->channel = SDPCM_EVENT_CHANNEL;
292 -
293 - if (pkt->len == 0) {
294 - brcmu_pkt_buf_free_skb(pkt);
295 - continue;
296 - }
297 -
298 - brcmf_rx_frame(bus->sdiodev->dev, pkt);
299 }
300
301 rxcount = maxframes - rxleft;
302 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
303 +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
304 @@ -502,7 +502,7 @@ static void brcmf_usb_rx_complete(struct
305
306 if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
307 skb_put(skb, urb->actual_length);
308 - brcmf_rx_frame(devinfo->dev, skb);
309 + brcmf_rx_frame(devinfo->dev, skb, true);
310 brcmf_usb_rx_refill(devinfo, req);
311 } else {
312 brcmu_pkt_buf_free_skb(skb);