mac80211: brcmfmac: add patch for better skb tracking
[openwrt/staging/rmilecki.git] / package / kernel / mac80211 / patches / 855-0005-brcmfmac-implement-more-accurate-skb-tracking.patch
1 From 9f94a984b52f19a0d7cca3c87cc83ad4eb98e326 Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
3 Date: Mon, 26 Sep 2016 11:50:41 +0200
4 Subject: [PATCH] brcmfmac: implement more accurate skb tracking
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 We need to track 802.1x packets to know if there are any pending ones
10 for transmission. This is required for performing key update in the
11 firmware.
12
13 Unfortunately our old tracking code wasn't very accurate. It was
14 treating skb as pending as soon as it was passed by the netif. Actual
15 handling packet to the firmware was happening later as brcmfmac
16 internally queues them and uses its own worker(s).
17
18 Other than that it was hard to handle freeing packets. Everytime we had
19 to determine (in more generic funcions) if packet was counted as pending
20 802.1x one or not. It was causing some problems, e.g. it wasn't clear if
21 brcmf_flowring_delete should free skb directly or not.
22
23 This patch introduces 2 separated functions for tracking skbs. This
24 simplifies logic, fixes brcmf_flowring_delete (maybe other hidden bugs
25 as well) and allows further simplifications. Thanks to better accuracy
26 is also increases time window for key update (and lowers timeout risk).
27
28 Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
29 ---
30 This was successfully tested with 4366b1. Can someone give it a try with
31 some USB/SDIO device, please?
32 ---
33 .../wireless/broadcom/brcm80211/brcmfmac/bcdc.c | 11 +++++++
34 .../wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 12 +++++++-
35 .../wireless/broadcom/brcm80211/brcmfmac/core.c | 36 ++++++++++++++++------
36 .../wireless/broadcom/brcm80211/brcmfmac/core.h | 2 ++
37 .../wireless/broadcom/brcm80211/brcmfmac/msgbuf.c | 14 +++++++--
38 .../wireless/broadcom/brcm80211/brcmfmac/proto.h | 11 +++++++
39 .../wireless/broadcom/brcm80211/brcmfmac/sdio.c | 8 +++++
40 .../net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 10 ++++++
41 8 files changed, 91 insertions(+), 13 deletions(-)
42
43 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
44 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
45 @@ -326,6 +326,16 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu
46 return 0;
47 }
48
49 +static int brcmf_proto_bcdc_hdr_get_ifidx(struct brcmf_pub *drvr,
50 + struct sk_buff *skb)
51 +{
52 + struct brcmf_proto_bcdc_header *h;
53 +
54 + h = (struct brcmf_proto_bcdc_header *)(skb->data);
55 +
56 + return BCDC_GET_IF_IDX(h);
57 +}
58 +
59 static int
60 brcmf_proto_bcdc_txdata(struct brcmf_pub *drvr, int ifidx, u8 offset,
61 struct sk_buff *pktbuf)
62 @@ -373,6 +383,7 @@ int brcmf_proto_bcdc_attach(struct brcmf
63 }
64
65 drvr->proto->hdrpull = brcmf_proto_bcdc_hdrpull;
66 + drvr->proto->hdr_get_ifidx = brcmf_proto_bcdc_hdr_get_ifidx;
67 drvr->proto->query_dcmd = brcmf_proto_bcdc_query_dcmd;
68 drvr->proto->set_dcmd = brcmf_proto_bcdc_set_dcmd;
69 drvr->proto->txdata = brcmf_proto_bcdc_txdata;
70 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
71 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
72 @@ -43,6 +43,7 @@
73 #include "chip.h"
74 #include "bus.h"
75 #include "debug.h"
76 +#include "proto.h"
77 #include "sdio.h"
78 #include "core.h"
79 #include "common.h"
80 @@ -770,6 +771,7 @@ int brcmf_sdiod_send_buf(struct brcmf_sd
81 int brcmf_sdiod_send_pkt(struct brcmf_sdio_dev *sdiodev,
82 struct sk_buff_head *pktq)
83 {
84 + struct brcmf_pub *pub = sdiodev->bus_if->drvr;
85 struct sk_buff *skb;
86 u32 addr = sdiodev->sbwad;
87 int err;
88 @@ -782,10 +784,18 @@ int brcmf_sdiod_send_pkt(struct brcmf_sd
89
90 if (pktq->qlen == 1 || !sdiodev->sg_support)
91 skb_queue_walk(pktq, skb) {
92 + struct brcmf_if *ifp;
93 + int ifidx;
94 +
95 + ifidx = brcmf_proto_hdr_get_ifidx(pub, skb);
96 + ifp = brcmf_get_ifp(pub, ifidx);
97 + brcmf_tx_passing_skb(ifp, skb);
98 err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, true,
99 addr, skb);
100 - if (err)
101 + if (err) {
102 + brcmf_tx_regained_skb(ifp, skb);
103 break;
104 + }
105 }
106 else
107 err = brcmf_sdiod_sglist_rw(sdiodev, SDIO_FUNC_2, true, addr,
108 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
109 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
110 @@ -247,9 +247,6 @@ static netdev_tx_t brcmf_netdev_start_xm
111 goto done;
112 }
113
114 - if (eh->h_proto == htons(ETH_P_PAE))
115 - atomic_inc(&ifp->pend_8021x_cnt);
116 -
117 /* determine the priority */
118 if (skb->priority == 0 || skb->priority > 7)
119 skb->priority = cfg80211_classify8021d(skb, NULL);
120 @@ -388,20 +385,41 @@ void brcmf_rx_event(struct device *dev,
121 brcmu_pkt_buf_free_skb(skb);
122 }
123
124 -void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)
125 +/**
126 + * brcmf_tx_passing_skb - Let core know skb is being passed to the firmware
127 + *
128 + * Core code needs to track state of some skbs. This function should be called
129 + * every time skb is going to be passed to the firmware for transmitting.
130 + */
131 +void brcmf_tx_passing_skb(struct brcmf_if *ifp, struct sk_buff *skb)
132 {
133 - struct ethhdr *eh;
134 - u16 type;
135 + struct ethhdr *eh = (struct ethhdr *)(skb->data);
136
137 - eh = (struct ethhdr *)(txp->data);
138 - type = ntohs(eh->h_proto);
139 + if (eh->h_proto == htons(ETH_P_PAE))
140 + atomic_inc(&ifp->pend_8021x_cnt);
141 +}
142
143 - if (type == ETH_P_PAE) {
144 +/**
145 + * brcmf_tx_regained_skb - Let core know skb is not being fw processed anymore
146 + *
147 + * This function should be called every time skb is returned from the firmware
148 + * processing for whatever reason. It usually happens after successful
149 + * transmission but may be also due to some error.
150 + */
151 +void brcmf_tx_regained_skb(struct brcmf_if *ifp, struct sk_buff *skb)
152 +{
153 + struct ethhdr *eh = (struct ethhdr *)(skb->data);
154 +
155 + if (eh->h_proto == htons(ETH_P_PAE)) {
156 atomic_dec(&ifp->pend_8021x_cnt);
157 +
158 if (waitqueue_active(&ifp->pend_8021x_wait))
159 wake_up(&ifp->pend_8021x_wait);
160 }
161 +}
162
163 +void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)
164 +{
165 if (!success)
166 ifp->stats.tx_errors++;
167
168 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
169 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
170 @@ -215,6 +215,8 @@ struct brcmf_if *brcmf_add_if(struct brc
171 void brcmf_remove_interface(struct brcmf_if *ifp, bool rtnl_locked);
172 void brcmf_txflowblock_if(struct brcmf_if *ifp,
173 enum brcmf_netif_stop_reason reason, bool state);
174 +void brcmf_tx_passing_skb(struct brcmf_if *ifp, struct sk_buff *skb);
175 +void brcmf_tx_regained_skb(struct brcmf_if *ifp, struct sk_buff *skb);
176 void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
177 void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
178 void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on);
179 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
180 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
181 @@ -701,17 +701,22 @@ static void brcmf_msgbuf_txflow(struct b
182
183 count = BRCMF_MSGBUF_TX_FLUSH_CNT2 - BRCMF_MSGBUF_TX_FLUSH_CNT1;
184 while (brcmf_flowring_qlen(flow, flowid)) {
185 + u8 ifidx = brcmf_flowring_ifidx_get(flow, flowid);
186 + struct brcmf_if *ifp = brcmf_get_ifp(msgbuf->drvr, ifidx);
187 +
188 skb = brcmf_flowring_dequeue(flow, flowid);
189 if (skb == NULL) {
190 brcmf_err("No SKB, but qlen %d\n",
191 brcmf_flowring_qlen(flow, flowid));
192 break;
193 }
194 + brcmf_tx_passing_skb(ifp, skb);
195 skb_orphan(skb);
196 if (brcmf_msgbuf_alloc_pktid(msgbuf->drvr->bus_if->dev,
197 msgbuf->tx_pktids, skb, ETH_HLEN,
198 &physaddr, &pktid)) {
199 brcmf_flowring_reinsert(flow, flowid, skb);
200 + brcmf_tx_regained_skb(ifp, skb);
201 brcmf_err("No PKTID available !!\n");
202 break;
203 }
204 @@ -720,6 +725,7 @@ static void brcmf_msgbuf_txflow(struct b
205 brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,
206 msgbuf->tx_pktids, pktid);
207 brcmf_flowring_reinsert(flow, flowid, skb);
208 + brcmf_tx_regained_skb(ifp, skb);
209 break;
210 }
211 count++;
212 @@ -728,7 +734,7 @@ static void brcmf_msgbuf_txflow(struct b
213
214 tx_msghdr->msg.msgtype = MSGBUF_TYPE_TX_POST;
215 tx_msghdr->msg.request_id = cpu_to_le32(pktid);
216 - tx_msghdr->msg.ifidx = brcmf_flowring_ifidx_get(flow, flowid);
217 + tx_msghdr->msg.ifidx = ifidx;
218 tx_msghdr->flags = BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_3;
219 tx_msghdr->flags |= (skb->priority & 0x07) <<
220 BRCMF_MSGBUF_PKT_FLAGS_PRIO_SHIFT;
221 @@ -857,6 +863,7 @@ brcmf_msgbuf_process_ioctl_complete(stru
222 static void
223 brcmf_msgbuf_process_txstatus(struct brcmf_msgbuf *msgbuf, void *buf)
224 {
225 + struct brcmf_if *ifp;
226 struct brcmf_commonring *commonring;
227 struct msgbuf_tx_status *tx_status;
228 u32 idx;
229 @@ -876,8 +883,9 @@ brcmf_msgbuf_process_txstatus(struct brc
230 commonring = msgbuf->flowrings[flowid];
231 atomic_dec(&commonring->outstanding_tx);
232
233 - brcmf_txfinalize(brcmf_get_ifp(msgbuf->drvr, tx_status->msg.ifidx),
234 - skb, true);
235 + ifp = brcmf_get_ifp(msgbuf->drvr, tx_status->msg.ifidx);
236 + brcmf_tx_regained_skb(ifp, skb);
237 + brcmf_txfinalize(ifp, skb, true);
238 }
239
240
241 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
242 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
243 @@ -16,6 +16,7 @@
244 #ifndef BRCMFMAC_PROTO_H
245 #define BRCMFMAC_PROTO_H
246
247 +#include "core.h"
248
249 enum proto_addr_mode {
250 ADDR_INDIRECT = 0,
251 @@ -29,6 +30,7 @@ struct brcmf_skb_reorder_data {
252 struct brcmf_proto {
253 int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws,
254 struct sk_buff *skb, struct brcmf_if **ifp);
255 + int (*hdr_get_ifidx)(struct brcmf_pub *drvr, struct sk_buff *skb);
256 int (*query_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd,
257 void *buf, uint len);
258 int (*set_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf,
259 @@ -64,6 +66,15 @@ static inline int brcmf_proto_hdrpull(st
260 ifp = &tmp;
261 return drvr->proto->hdrpull(drvr, do_fws, skb, ifp);
262 }
263 +
264 +static inline int brcmf_proto_hdr_get_ifidx(struct brcmf_pub *drvr,
265 + struct sk_buff *skb)
266 +{
267 + if (!drvr->proto->hdr_get_ifidx)
268 + return -ENOTSUPP;
269 + return drvr->proto->hdr_get_ifidx(drvr, skb);
270 +}
271 +
272 static inline int brcmf_proto_query_dcmd(struct brcmf_pub *drvr, int ifidx,
273 uint cmd, void *buf, uint len)
274 {
275 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
276 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
277 @@ -42,6 +42,7 @@
278 #include "sdio.h"
279 #include "chip.h"
280 #include "firmware.h"
281 +#include "proto.h"
282 #include "core.h"
283 #include "common.h"
284
285 @@ -2233,6 +2234,7 @@ brcmf_sdio_txpkt_postp(struct brcmf_sdio
286 static int brcmf_sdio_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
287 uint chan)
288 {
289 + struct brcmf_pub *pub = bus->sdiodev->bus_if->drvr;
290 int ret;
291 struct sk_buff *pkt_next, *tmp;
292
293 @@ -2256,7 +2258,13 @@ done:
294 if (ret == 0)
295 bus->tx_seq = (bus->tx_seq + pktq->qlen) % SDPCM_SEQ_WRAP;
296 skb_queue_walk_safe(pktq, pkt_next, tmp) {
297 + struct brcmf_if *ifp;
298 + int ifidx;
299 +
300 __skb_unlink(pkt_next, pktq);
301 + ifidx = brcmf_proto_hdr_get_ifidx(pub, pkt_next);
302 + ifp = brcmf_get_ifp(pub, ifidx);
303 + brcmf_tx_regained_skb(ifp, pkt_next);
304 brcmf_txcomplete(bus->sdiodev->dev, pkt_next, ret == 0);
305 }
306 return ret;
307 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
308 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
309 @@ -26,6 +26,7 @@
310 #include "bus.h"
311 #include "debug.h"
312 #include "firmware.h"
313 +#include "proto.h"
314 #include "usb.h"
315 #include "core.h"
316 #include "common.h"
317 @@ -476,12 +477,16 @@ static void brcmf_usb_tx_complete(struct
318 {
319 struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context;
320 struct brcmf_usbdev_info *devinfo = req->devinfo;
321 + struct brcmf_pub *pub = devinfo->bus_pub.bus->drvr;
322 + struct brcmf_if *ifp;
323 unsigned long flags;
324
325 brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status,
326 req->skb);
327 brcmf_usb_del_fromq(devinfo, req);
328
329 + ifp = brcmf_get_ifp(pub, brcmf_proto_hdr_get_ifidx(pub, req->skb));
330 + brcmf_tx_regained_skb(ifp, req->skb);
331 brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0);
332 req->skb = NULL;
333 brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req, &devinfo->tx_freecount);
334 @@ -598,7 +603,9 @@ brcmf_usb_state_change(struct brcmf_usbd
335 static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
336 {
337 struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
338 + struct brcmf_pub *pub = devinfo->bus_pub.bus->drvr;
339 struct brcmf_usbreq *req;
340 + struct brcmf_if *ifp;
341 int ret;
342 unsigned long flags;
343
344 @@ -622,6 +629,8 @@ static int brcmf_usb_tx(struct device *d
345 skb->data, skb->len, brcmf_usb_tx_complete, req);
346 req->urb->transfer_flags |= URB_ZERO_PACKET;
347 brcmf_usb_enq(devinfo, &devinfo->tx_postq, req, NULL);
348 + ifp = brcmf_get_ifp(pub, brcmf_proto_hdr_get_ifidx(pub, skb));
349 + brcmf_tx_passing_skb(ifp, skb);
350 ret = usb_submit_urb(req->urb, GFP_ATOMIC);
351 if (ret) {
352 brcmf_err("brcmf_usb_tx usb_submit_urb FAILED\n");
353 @@ -629,6 +638,7 @@ static int brcmf_usb_tx(struct device *d
354 req->skb = NULL;
355 brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req,
356 &devinfo->tx_freecount);
357 + brcmf_tx_regained_skb(ifp, skb);
358 goto fail;
359 }
360