Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / net / wireless / broadcom / brcm80211 / brcmfmac / bcdc.c
1 // SPDX-License-Identifier: ISC
2 /*
3  * Copyright (c) 2010 Broadcom Corporation
4  */
5
6 /*******************************************************************************
7  * Communicates with the dongle by using dcmd codes.
8  * For certain dcmd codes, the dongle interprets string data from the host.
9  ******************************************************************************/
10
11 #include <linux/types.h>
12 #include <linux/netdevice.h>
13
14 #include <brcmu_utils.h>
15 #include <brcmu_wifi.h>
16
17 #include "core.h"
18 #include "bus.h"
19 #include "fwsignal.h"
20 #include "debug.h"
21 #include "tracepoint.h"
22 #include "proto.h"
23 #include "bcdc.h"
24
25 struct brcmf_proto_bcdc_dcmd {
26         __le32 cmd;     /* dongle command value */
27         __le32 len;     /* lower 16: output buflen;
28                          * upper 16: input buflen (excludes header) */
29         __le32 flags;   /* flag defns given below */
30         __le32 status;  /* status code returned from the device */
31 };
32
33 /* BCDC flag definitions */
34 #define BCDC_DCMD_ERROR         0x01            /* 1=cmd failed */
35 #define BCDC_DCMD_SET           0x02            /* 0=get, 1=set cmd */
36 #define BCDC_DCMD_IF_MASK       0xF000          /* I/F index */
37 #define BCDC_DCMD_IF_SHIFT      12
38 #define BCDC_DCMD_ID_MASK       0xFFFF0000      /* id an cmd pairing */
39 #define BCDC_DCMD_ID_SHIFT      16              /* ID Mask shift bits */
40 #define BCDC_DCMD_ID(flags)     \
41         (((flags) & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT)
42
43 /*
44  * BCDC header - Broadcom specific extension of CDC.
45  * Used on data packets to convey priority across USB.
46  */
47 #define BCDC_HEADER_LEN         4
48 #define BCDC_PROTO_VER          2       /* Protocol version */
49 #define BCDC_FLAG_VER_MASK      0xf0    /* Protocol version mask */
50 #define BCDC_FLAG_VER_SHIFT     4       /* Protocol version shift */
51 #define BCDC_FLAG_SUM_GOOD      0x04    /* Good RX checksums */
52 #define BCDC_FLAG_SUM_NEEDED    0x08    /* Dongle needs to do TX checksums */
53 #define BCDC_PRIORITY_MASK      0x7
54 #define BCDC_FLAG2_IF_MASK      0x0f    /* packet rx interface in APSTA */
55 #define BCDC_FLAG2_IF_SHIFT     0
56
57 #define BCDC_GET_IF_IDX(hdr) \
58         ((int)((((hdr)->flags2) & BCDC_FLAG2_IF_MASK) >> BCDC_FLAG2_IF_SHIFT))
59 #define BCDC_SET_IF_IDX(hdr, idx) \
60         ((hdr)->flags2 = (((hdr)->flags2 & ~BCDC_FLAG2_IF_MASK) | \
61         ((idx) << BCDC_FLAG2_IF_SHIFT)))
62
63 /**
64  * struct brcmf_proto_bcdc_header - BCDC header format
65  *
66  * @flags: flags contain protocol and checksum info.
67  * @priority: 802.1d priority and USB flow control info (bit 4:7).
68  * @flags2: additional flags containing dongle interface index.
69  * @data_offset: start of packet data. header is following by firmware signals.
70  */
71 struct brcmf_proto_bcdc_header {
72         u8 flags;
73         u8 priority;
74         u8 flags2;
75         u8 data_offset;
76 };
77
78 /*
79  * maximum length of firmware signal data between
80  * the BCDC header and packet data in the tx path.
81  */
82 #define BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES        12
83
84 #define RETRIES 2 /* # of retries to retrieve matching dcmd response */
85 #define BUS_HEADER_LEN  (16+64)         /* Must be atleast SDPCM_RESERVE
86                                          * (amount of header tha might be added)
87                                          * plus any space that might be needed
88                                          * for bus alignment padding.
89                                          */
90 struct brcmf_bcdc {
91         u16 reqid;
92         u8 bus_header[BUS_HEADER_LEN];
93         struct brcmf_proto_bcdc_dcmd msg;
94         unsigned char buf[BRCMF_DCMD_MAXLEN];
95         struct brcmf_fws_info *fws;
96 };
97
98
99 struct brcmf_fws_info *drvr_to_fws(struct brcmf_pub *drvr)
100 {
101         struct brcmf_bcdc *bcdc = drvr->proto->pd;
102
103         return bcdc->fws;
104 }
105
106 static int
107 brcmf_proto_bcdc_msg(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf,
108                      uint len, bool set)
109 {
110         struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
111         struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;
112         u32 flags;
113
114         brcmf_dbg(BCDC, "Enter\n");
115
116         memset(msg, 0, sizeof(struct brcmf_proto_bcdc_dcmd));
117
118         msg->cmd = cpu_to_le32(cmd);
119         msg->len = cpu_to_le32(len);
120         flags = (++bcdc->reqid << BCDC_DCMD_ID_SHIFT);
121         if (set)
122                 flags |= BCDC_DCMD_SET;
123         flags = (flags & ~BCDC_DCMD_IF_MASK) |
124                 (ifidx << BCDC_DCMD_IF_SHIFT);
125         msg->flags = cpu_to_le32(flags);
126
127         if (buf)
128                 memcpy(bcdc->buf, buf, len);
129
130         len += sizeof(*msg);
131         if (len > BRCMF_TX_IOCTL_MAX_MSG_SIZE)
132                 len = BRCMF_TX_IOCTL_MAX_MSG_SIZE;
133
134         /* Send request */
135         return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&bcdc->msg, len);
136 }
137
138 static int brcmf_proto_bcdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len)
139 {
140         int ret;
141         struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
142
143         brcmf_dbg(BCDC, "Enter\n");
144         len += sizeof(struct brcmf_proto_bcdc_dcmd);
145         do {
146                 ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&bcdc->msg,
147                                       len);
148                 if (ret < 0)
149                         break;
150         } while (BCDC_DCMD_ID(le32_to_cpu(bcdc->msg.flags)) != id);
151
152         return ret;
153 }
154
155 static int
156 brcmf_proto_bcdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
157                             void *buf, uint len, int *fwerr)
158 {
159         struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
160         struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;
161         void *info;
162         int ret = 0, retries = 0;
163         u32 id, flags;
164
165         brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);
166
167         *fwerr = 0;
168         ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, false);
169         if (ret < 0) {
170                 bphy_err(drvr, "brcmf_proto_bcdc_msg failed w/status %d\n",
171                          ret);
172                 goto done;
173         }
174
175 retry:
176         /* wait for interrupt and get first fragment */
177         ret = brcmf_proto_bcdc_cmplt(drvr, bcdc->reqid, len);
178         if (ret < 0)
179                 goto done;
180
181         flags = le32_to_cpu(msg->flags);
182         id = (flags & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT;
183
184         if ((id < bcdc->reqid) && (++retries < RETRIES))
185                 goto retry;
186         if (id != bcdc->reqid) {
187                 bphy_err(drvr, "%s: unexpected request id %d (expected %d)\n",
188                          brcmf_ifname(brcmf_get_ifp(drvr, ifidx)), id,
189                          bcdc->reqid);
190                 ret = -EINVAL;
191                 goto done;
192         }
193
194         /* Check info buffer */
195         info = (void *)&bcdc->buf[0];
196
197         /* Copy info buffer */
198         if (buf) {
199                 if (ret < (int)len)
200                         len = ret;
201                 memcpy(buf, info, len);
202         }
203
204         ret = 0;
205
206         /* Check the ERROR flag */
207         if (flags & BCDC_DCMD_ERROR)
208                 *fwerr = le32_to_cpu(msg->status);
209 done:
210         return ret;
211 }
212
213 static int
214 brcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
215                           void *buf, uint len, int *fwerr)
216 {
217         struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
218         struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;
219         int ret;
220         u32 flags, id;
221
222         brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);
223
224         *fwerr = 0;
225         ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, true);
226         if (ret < 0)
227                 goto done;
228
229         ret = brcmf_proto_bcdc_cmplt(drvr, bcdc->reqid, len);
230         if (ret < 0)
231                 goto done;
232
233         flags = le32_to_cpu(msg->flags);
234         id = (flags & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT;
235
236         if (id != bcdc->reqid) {
237                 bphy_err(drvr, "%s: unexpected request id %d (expected %d)\n",
238                          brcmf_ifname(brcmf_get_ifp(drvr, ifidx)), id,
239                          bcdc->reqid);
240                 ret = -EINVAL;
241                 goto done;
242         }
243
244         ret = 0;
245
246         /* Check the ERROR flag */
247         if (flags & BCDC_DCMD_ERROR)
248                 *fwerr = le32_to_cpu(msg->status);
249
250 done:
251         return ret;
252 }
253
254 static void
255 brcmf_proto_bcdc_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset,
256                          struct sk_buff *pktbuf)
257 {
258         struct brcmf_proto_bcdc_header *h;
259
260         brcmf_dbg(BCDC, "Enter\n");
261
262         /* Push BDC header used to convey priority for buses that don't */
263         skb_push(pktbuf, BCDC_HEADER_LEN);
264
265         h = (struct brcmf_proto_bcdc_header *)(pktbuf->data);
266
267         h->flags = (BCDC_PROTO_VER << BCDC_FLAG_VER_SHIFT);
268         if (pktbuf->ip_summed == CHECKSUM_PARTIAL)
269                 h->flags |= BCDC_FLAG_SUM_NEEDED;
270
271         h->priority = (pktbuf->priority & BCDC_PRIORITY_MASK);
272         h->flags2 = 0;
273         h->data_offset = offset;
274         BCDC_SET_IF_IDX(h, ifidx);
275         trace_brcmf_bcdchdr(pktbuf->data);
276 }
277
278 static int
279 brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws,
280                          struct sk_buff *pktbuf, struct brcmf_if **ifp)
281 {
282         struct brcmf_proto_bcdc_header *h;
283         struct brcmf_if *tmp_if;
284
285         brcmf_dbg(BCDC, "Enter\n");
286
287         /* Pop BCDC header used to convey priority for buses that don't */
288         if (pktbuf->len <= BCDC_HEADER_LEN) {
289                 brcmf_dbg(INFO, "rx data too short (%d <= %d)\n",
290                           pktbuf->len, BCDC_HEADER_LEN);
291                 return -EBADE;
292         }
293
294         trace_brcmf_bcdchdr(pktbuf->data);
295         h = (struct brcmf_proto_bcdc_header *)(pktbuf->data);
296
297         tmp_if = brcmf_get_ifp(drvr, BCDC_GET_IF_IDX(h));
298         if (!tmp_if) {
299                 brcmf_dbg(INFO, "no matching ifp found\n");
300                 return -EBADE;
301         }
302         if (((h->flags & BCDC_FLAG_VER_MASK) >> BCDC_FLAG_VER_SHIFT) !=
303             BCDC_PROTO_VER) {
304                 bphy_err(drvr, "%s: non-BCDC packet received, flags 0x%x\n",
305                          brcmf_ifname(tmp_if), h->flags);
306                 return -EBADE;
307         }
308
309         if (h->flags & BCDC_FLAG_SUM_GOOD) {
310                 brcmf_dbg(BCDC, "%s: BDC rcv, good checksum, flags 0x%x\n",
311                           brcmf_ifname(tmp_if), h->flags);
312                 pktbuf->ip_summed = CHECKSUM_UNNECESSARY;
313         }
314
315         pktbuf->priority = h->priority & BCDC_PRIORITY_MASK;
316
317         skb_pull(pktbuf, BCDC_HEADER_LEN);
318         if (do_fws)
319                 brcmf_fws_hdrpull(tmp_if, h->data_offset << 2, pktbuf);
320         else
321                 skb_pull(pktbuf, h->data_offset << 2);
322
323         if (pktbuf->len == 0)
324                 return -ENODATA;
325
326         if (ifp != NULL)
327                 *ifp = tmp_if;
328         return 0;
329 }
330
331 static int brcmf_proto_bcdc_tx_queue_data(struct brcmf_pub *drvr, int ifidx,
332                                           struct sk_buff *skb)
333 {
334         struct brcmf_if *ifp = brcmf_get_ifp(drvr, ifidx);
335         struct brcmf_bcdc *bcdc = drvr->proto->pd;
336
337         if (!brcmf_fws_queue_skbs(bcdc->fws))
338                 return brcmf_proto_txdata(drvr, ifidx, 0, skb);
339
340         return brcmf_fws_process_skb(ifp, skb);
341 }
342
343 static int
344 brcmf_proto_bcdc_txdata(struct brcmf_pub *drvr, int ifidx, u8 offset,
345                         struct sk_buff *pktbuf)
346 {
347         brcmf_proto_bcdc_hdrpush(drvr, ifidx, offset, pktbuf);
348         return brcmf_bus_txdata(drvr->bus_if, pktbuf);
349 }
350
351 void brcmf_proto_bcdc_txflowblock(struct device *dev, bool state)
352 {
353         struct brcmf_bus *bus_if = dev_get_drvdata(dev);
354         struct brcmf_pub *drvr = bus_if->drvr;
355
356         brcmf_dbg(TRACE, "Enter\n");
357
358         brcmf_fws_bus_blocked(drvr, state);
359 }
360
361 void
362 brcmf_proto_bcdc_txcomplete(struct device *dev, struct sk_buff *txp,
363                             bool success)
364 {
365         struct brcmf_bus *bus_if = dev_get_drvdata(dev);
366         struct brcmf_bcdc *bcdc = bus_if->drvr->proto->pd;
367         struct brcmf_if *ifp;
368
369         /* await txstatus signal for firmware if active */
370         if (brcmf_fws_fc_active(bcdc->fws)) {
371                 if (!success)
372                         brcmf_fws_bustxfail(bcdc->fws, txp);
373         } else {
374                 if (brcmf_proto_bcdc_hdrpull(bus_if->drvr, false, txp, &ifp))
375                         brcmu_pkt_buf_free_skb(txp);
376                 else
377                         brcmf_txfinalize(ifp, txp, success);
378         }
379 }
380
381 static void
382 brcmf_proto_bcdc_configure_addr_mode(struct brcmf_pub *drvr, int ifidx,
383                                      enum proto_addr_mode addr_mode)
384 {
385 }
386
387 static void
388 brcmf_proto_bcdc_delete_peer(struct brcmf_pub *drvr, int ifidx,
389                              u8 peer[ETH_ALEN])
390 {
391 }
392
393 static void
394 brcmf_proto_bcdc_add_tdls_peer(struct brcmf_pub *drvr, int ifidx,
395                                u8 peer[ETH_ALEN])
396 {
397 }
398
399 static void brcmf_proto_bcdc_rxreorder(struct brcmf_if *ifp,
400                                        struct sk_buff *skb)
401 {
402         brcmf_fws_rxreorder(ifp, skb);
403 }
404
405 static void
406 brcmf_proto_bcdc_add_if(struct brcmf_if *ifp)
407 {
408         brcmf_fws_add_interface(ifp);
409 }
410
411 static void
412 brcmf_proto_bcdc_del_if(struct brcmf_if *ifp)
413 {
414         brcmf_fws_del_interface(ifp);
415 }
416
417 static void
418 brcmf_proto_bcdc_reset_if(struct brcmf_if *ifp)
419 {
420         brcmf_fws_reset_interface(ifp);
421 }
422
423 static int
424 brcmf_proto_bcdc_init_done(struct brcmf_pub *drvr)
425 {
426         struct brcmf_bcdc *bcdc = drvr->proto->pd;
427         struct brcmf_fws_info *fws;
428
429         fws = brcmf_fws_attach(drvr);
430         if (IS_ERR(fws))
431                 return PTR_ERR(fws);
432
433         bcdc->fws = fws;
434         return 0;
435 }
436
437 static void brcmf_proto_bcdc_debugfs_create(struct brcmf_pub *drvr)
438 {
439         brcmf_fws_debugfs_create(drvr);
440 }
441
442 int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr)
443 {
444         struct brcmf_bcdc *bcdc;
445
446         bcdc = kzalloc(sizeof(*bcdc), GFP_ATOMIC);
447         if (!bcdc)
448                 goto fail;
449
450         /* ensure that the msg buf directly follows the cdc msg struct */
451         if ((unsigned long)(&bcdc->msg + 1) != (unsigned long)bcdc->buf) {
452                 bphy_err(drvr, "struct brcmf_proto_bcdc is not correctly defined\n");
453                 goto fail;
454         }
455
456         drvr->proto->hdrpull = brcmf_proto_bcdc_hdrpull;
457         drvr->proto->query_dcmd = brcmf_proto_bcdc_query_dcmd;
458         drvr->proto->set_dcmd = brcmf_proto_bcdc_set_dcmd;
459         drvr->proto->tx_queue_data = brcmf_proto_bcdc_tx_queue_data;
460         drvr->proto->txdata = brcmf_proto_bcdc_txdata;
461         drvr->proto->configure_addr_mode = brcmf_proto_bcdc_configure_addr_mode;
462         drvr->proto->delete_peer = brcmf_proto_bcdc_delete_peer;
463         drvr->proto->add_tdls_peer = brcmf_proto_bcdc_add_tdls_peer;
464         drvr->proto->rxreorder = brcmf_proto_bcdc_rxreorder;
465         drvr->proto->add_if = brcmf_proto_bcdc_add_if;
466         drvr->proto->del_if = brcmf_proto_bcdc_del_if;
467         drvr->proto->reset_if = brcmf_proto_bcdc_reset_if;
468         drvr->proto->init_done = brcmf_proto_bcdc_init_done;
469         drvr->proto->debugfs_create = brcmf_proto_bcdc_debugfs_create;
470         drvr->proto->pd = bcdc;
471
472         drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES;
473         drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN +
474                         sizeof(struct brcmf_proto_bcdc_dcmd);
475         return 0;
476
477 fail:
478         kfree(bcdc);
479         return -ENOMEM;
480 }
481
482 void brcmf_proto_bcdc_detach_pre_delif(struct brcmf_pub *drvr)
483 {
484         struct brcmf_bcdc *bcdc = drvr->proto->pd;
485
486         brcmf_fws_detach_pre_delif(bcdc->fws);
487 }
488
489 void brcmf_proto_bcdc_detach_post_delif(struct brcmf_pub *drvr)
490 {
491         struct brcmf_bcdc *bcdc = drvr->proto->pd;
492
493         drvr->proto->pd = NULL;
494         brcmf_fws_detach_post_delif(bcdc->fws);
495         kfree(bcdc);
496 }