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
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
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
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).
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.
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).
28 Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
30 This was successfully tested with 4366b1. Can someone give it a try with
31 some USB/SDIO device, please?
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(-)
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
49 +static int brcmf_proto_bcdc_hdr_get_ifidx(struct brcmf_pub *drvr,
50 + struct sk_buff *skb)
52 + struct brcmf_proto_bcdc_header *h;
54 + h = (struct brcmf_proto_bcdc_header *)(skb->data);
56 + return BCDC_GET_IF_IDX(h);
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
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
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)
84 + struct brcmf_pub *pub = sdiodev->bus_if->drvr;
86 u32 addr = sdiodev->sbwad;
88 @@ -782,10 +784,18 @@ int brcmf_sdiod_send_pkt(struct brcmf_sd
90 if (pktq->qlen == 1 || !sdiodev->sg_support)
91 skb_queue_walk(pktq, skb) {
92 + struct brcmf_if *ifp;
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,
102 + brcmf_tx_regained_skb(ifp, skb);
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
114 - if (eh->h_proto == htons(ETH_P_PAE))
115 - atomic_inc(&ifp->pend_8021x_cnt);
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);
124 -void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)
126 + * brcmf_tx_passing_skb - Let core know skb is being passed to the firmware
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.
131 +void brcmf_tx_passing_skb(struct brcmf_if *ifp, struct sk_buff *skb)
135 + struct ethhdr *eh = (struct ethhdr *)(skb->data);
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);
143 - if (type == ETH_P_PAE) {
145 + * brcmf_tx_regained_skb - Let core know skb is not being fw processed anymore
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.
151 +void brcmf_tx_regained_skb(struct brcmf_if *ifp, struct sk_buff *skb)
153 + struct ethhdr *eh = (struct ethhdr *)(skb->data);
155 + if (eh->h_proto == htons(ETH_P_PAE)) {
156 atomic_dec(&ifp->pend_8021x_cnt);
158 if (waitqueue_active(&ifp->pend_8021x_wait))
159 wake_up(&ifp->pend_8021x_wait);
163 +void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)
166 ifp->stats.tx_errors++;
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
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);
188 skb = brcmf_flowring_dequeue(flow, flowid);
190 brcmf_err("No SKB, but qlen %d\n",
191 brcmf_flowring_qlen(flow, flowid));
194 + brcmf_tx_passing_skb(ifp, 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");
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);
212 @@ -728,7 +734,7 @@ static void brcmf_msgbuf_txflow(struct b
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
223 brcmf_msgbuf_process_txstatus(struct brcmf_msgbuf *msgbuf, void *buf)
225 + struct brcmf_if *ifp;
226 struct brcmf_commonring *commonring;
227 struct msgbuf_tx_status *tx_status;
229 @@ -876,8 +883,9 @@ brcmf_msgbuf_process_txstatus(struct brc
230 commonring = msgbuf->flowrings[flowid];
231 atomic_dec(&commonring->outstanding_tx);
233 - brcmf_txfinalize(brcmf_get_ifp(msgbuf->drvr, tx_status->msg.ifidx),
235 + ifp = brcmf_get_ifp(msgbuf->drvr, tx_status->msg.ifidx);
236 + brcmf_tx_regained_skb(ifp, skb);
237 + brcmf_txfinalize(ifp, skb, true);
241 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
242 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
244 #ifndef BRCMFMAC_PROTO_H
245 #define BRCMFMAC_PROTO_H
249 enum proto_addr_mode {
251 @@ -29,6 +30,7 @@ struct brcmf_skb_reorder_data {
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
261 return drvr->proto->hdrpull(drvr, do_fws, skb, ifp);
264 +static inline int brcmf_proto_hdr_get_ifidx(struct brcmf_pub *drvr,
265 + struct sk_buff *skb)
267 + if (!drvr->proto->hdr_get_ifidx)
269 + return drvr->proto->hdr_get_ifidx(drvr, skb);
272 static inline int brcmf_proto_query_dcmd(struct brcmf_pub *drvr, int ifidx,
273 uint cmd, void *buf, uint len)
275 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
276 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
280 #include "firmware.h"
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,
289 + struct brcmf_pub *pub = bus->sdiodev->bus_if->drvr;
291 struct sk_buff *pkt_next, *tmp;
293 @@ -2256,7 +2258,13 @@ done:
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;
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);
307 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
308 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
312 #include "firmware.h"
317 @@ -476,12 +477,16 @@ static void brcmf_usb_tx_complete(struct
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;
325 brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status,
327 brcmf_usb_del_fromq(devinfo, req);
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);
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)
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;
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);
352 brcmf_err("brcmf_usb_tx usb_submit_urb FAILED\n");
353 @@ -629,6 +638,7 @@ static int brcmf_usb_tx(struct device *d
355 brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req,
356 &devinfo->tx_freecount);
357 + brcmf_tx_regained_skb(ifp, skb);