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