staging: brcm80211: rename fullmac functions
[cascardo/linux.git] / drivers / staging / brcm80211 / brcmfmac / dhd_cdc.c
1 /*
2  * Copyright (c) 2010 Broadcom Corporation
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <linux/types.h>
18 #include <linux/netdevice.h>
19 #include <linux/sched.h>
20 #include <defs.h>
21
22 #include <brcmu_utils.h>
23 #include <brcmu_wifi.h>
24
25 #include "dngl_stats.h"
26 #include "dhd.h"
27 #include "dhd_proto.h"
28 #include "dhd_bus.h"
29 #include "dhd_dbg.h"
30
31 struct cdc_ioctl {
32         u32 cmd;        /* ioctl command value */
33         u32 len;        /* lower 16: output buflen;
34                          * upper 16: input buflen (excludes header) */
35         u32 flags;      /* flag defns given below */
36         u32 status;     /* status code returned from the device */
37 };
38
39 /* Max valid buffer size that can be sent to the dongle */
40 #define CDC_MAX_MSG_SIZE        (ETH_FRAME_LEN+ETH_FCS_LEN)
41
42 /* CDC flag definitions */
43 #define CDCF_IOC_ERROR          0x01            /* 1=ioctl cmd failed */
44 #define CDCF_IOC_SET            0x02            /* 0=get, 1=set cmd */
45 #define CDCF_IOC_IF_MASK        0xF000          /* I/F index */
46 #define CDCF_IOC_IF_SHIFT       12
47 #define CDCF_IOC_ID_MASK        0xFFFF0000      /* id an ioctl pairing */
48 #define CDCF_IOC_ID_SHIFT       16              /* ID Mask shift bits */
49 #define CDC_IOC_ID(flags)       \
50         (((flags) & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT)
51 #define CDC_SET_IF_IDX(hdr, idx) \
52         ((hdr)->flags = (((hdr)->flags & ~CDCF_IOC_IF_MASK) | \
53         ((idx) << CDCF_IOC_IF_SHIFT)))
54
55 /*
56  * BDC header
57  * Used on data packets to convey priority across USB.
58  */
59 #define BDC_HEADER_LEN          4
60 #define BDC_PROTO_VER           1       /* Protocol version */
61 #define BDC_FLAG_VER_MASK       0xf0    /* Protocol version mask */
62 #define BDC_FLAG_VER_SHIFT      4       /* Protocol version shift */
63 #define BDC_FLAG_SUM_GOOD       0x04    /* Good RX checksums */
64 #define BDC_FLAG_SUM_NEEDED     0x08    /* Dongle needs to do TX checksums */
65 #define BDC_PRIORITY_MASK       0x7
66 #define BDC_FLAG2_IF_MASK       0x0f    /* packet rx interface in APSTA */
67 #define BDC_FLAG2_IF_SHIFT      0
68
69 #define BDC_GET_IF_IDX(hdr) \
70         ((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT))
71 #define BDC_SET_IF_IDX(hdr, idx) \
72         ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | \
73         ((idx) << BDC_FLAG2_IF_SHIFT)))
74
75 struct bdc_header {
76         u8 flags;
77         u8 priority;    /* 802.1d Priority, 4:7 flow control info for usb */
78         u8 flags2;
79         u8 rssi;
80 };
81
82
83 #ifdef CUSTOMER_HW2
84 int wifi_get_mac_addr(unsigned char *buf);
85 #endif
86
87 /* Packet alignment for most efficient SDIO (can change based on platform) */
88 #ifndef DHD_SDALIGN
89 #define DHD_SDALIGN     32
90 #endif
91 #if !ISPOWEROF2(DHD_SDALIGN)
92 #error DHD_SDALIGN is not a power of 2!
93 #endif
94
95 #define RETRIES 2       /* # of retries to retrieve matching ioctl response */
96 #define BUS_HEADER_LEN  (16+DHD_SDALIGN) /* Must be atleast SDPCM_RESERVE
97                                          * defined in dhd_sdio.c
98                                          * (amount of header tha might be added)
99                                          * plus any space that might be needed
100                                          * for alignment padding.
101                                          */
102 #define ROUND_UP_MARGIN 2048    /* Biggest SDIO block size possible for
103                                  * round off at the end of buffer
104                                  */
105
106 typedef struct dhd_prot {
107         u16 reqid;
108         u8 pending;
109         u32 lastcmd;
110         u8 bus_header[BUS_HEADER_LEN];
111         struct cdc_ioctl msg;
112         unsigned char buf[BRCMF_C_IOCTL_MAXLEN + ROUND_UP_MARGIN];
113 } dhd_prot_t;
114
115 static int dhdcdc_msg(dhd_pub_t *dhd)
116 {
117         dhd_prot_t *prot = dhd->prot;
118         int len = le32_to_cpu(prot->msg.len) + sizeof(struct cdc_ioctl);
119
120         DHD_TRACE(("%s: Enter\n", __func__));
121
122         /* NOTE : cdc->msg.len holds the desired length of the buffer to be
123          *        returned. Only up to CDC_MAX_MSG_SIZE of this buffer area
124          *        is actually sent to the dongle
125          */
126         if (len > CDC_MAX_MSG_SIZE)
127                 len = CDC_MAX_MSG_SIZE;
128
129         /* Send request */
130         return brcmf_sdbrcm_bus_txctl(dhd->bus, (unsigned char *)&prot->msg,
131                                       len);
132 }
133
134 static int dhdcdc_cmplt(dhd_pub_t *dhd, u32 id, u32 len)
135 {
136         int ret;
137         dhd_prot_t *prot = dhd->prot;
138
139         DHD_TRACE(("%s: Enter\n", __func__));
140
141         do {
142                 ret = brcmf_sdbrcm_bus_rxctl(dhd->bus,
143                                              (unsigned char *)&prot->msg,
144                                              len + sizeof(struct cdc_ioctl));
145                 if (ret < 0)
146                         break;
147         } while (CDC_IOC_ID(le32_to_cpu(prot->msg.flags)) != id);
148
149         return ret;
150 }
151
152 int
153 dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len)
154 {
155         dhd_prot_t *prot = dhd->prot;
156         struct cdc_ioctl *msg = &prot->msg;
157         void *info;
158         int ret = 0, retries = 0;
159         u32 id, flags = 0;
160
161         DHD_TRACE(("%s: Enter\n", __func__));
162         DHD_CTL(("%s: cmd %d len %d\n", __func__, cmd, len));
163
164         /* Respond "bcmerror" and "bcmerrorstr" with local cache */
165         if (cmd == BRCMF_C_GET_VAR && buf) {
166                 if (!strcmp((char *)buf, "bcmerrorstr")) {
167                         strncpy((char *)buf, "bcm_error",
168                                 BCME_STRLEN);
169                         goto done;
170                 } else if (!strcmp((char *)buf, "bcmerror")) {
171                         *(int *)buf = dhd->dongle_error;
172                         goto done;
173                 }
174         }
175
176         memset(msg, 0, sizeof(struct cdc_ioctl));
177
178         msg->cmd = cpu_to_le32(cmd);
179         msg->len = cpu_to_le32(len);
180         msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT);
181         CDC_SET_IF_IDX(msg, ifidx);
182         msg->flags = cpu_to_le32(msg->flags);
183
184         if (buf)
185                 memcpy(prot->buf, buf, len);
186
187         ret = dhdcdc_msg(dhd);
188         if (ret < 0) {
189                 DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status "
190                         "%d\n", ret));
191                 goto done;
192         }
193
194 retry:
195         /* wait for interrupt and get first fragment */
196         ret = dhdcdc_cmplt(dhd, prot->reqid, len);
197         if (ret < 0)
198                 goto done;
199
200         flags = le32_to_cpu(msg->flags);
201         id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT;
202
203         if ((id < prot->reqid) && (++retries < RETRIES))
204                 goto retry;
205         if (id != prot->reqid) {
206                 DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n",
207                            brcmf_ifname(dhd, ifidx), __func__, id,
208                            prot->reqid));
209                 ret = -EINVAL;
210                 goto done;
211         }
212
213         /* Check info buffer */
214         info = (void *)&msg[1];
215
216         /* Copy info buffer */
217         if (buf) {
218                 if (ret < (int)len)
219                         len = ret;
220                 memcpy(buf, info, len);
221         }
222
223         /* Check the ERROR flag */
224         if (flags & CDCF_IOC_ERROR) {
225                 ret = le32_to_cpu(msg->status);
226                 /* Cache error from dongle */
227                 dhd->dongle_error = ret;
228         }
229
230 done:
231         return ret;
232 }
233
234 int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len)
235 {
236         dhd_prot_t *prot = dhd->prot;
237         struct cdc_ioctl *msg = &prot->msg;
238         int ret = 0;
239         u32 flags, id;
240
241         DHD_TRACE(("%s: Enter\n", __func__));
242         DHD_CTL(("%s: cmd %d len %d\n", __func__, cmd, len));
243
244         memset(msg, 0, sizeof(struct cdc_ioctl));
245
246         msg->cmd = cpu_to_le32(cmd);
247         msg->len = cpu_to_le32(len);
248         msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT) | CDCF_IOC_SET;
249         CDC_SET_IF_IDX(msg, ifidx);
250         msg->flags = cpu_to_le32(msg->flags);
251
252         if (buf)
253                 memcpy(prot->buf, buf, len);
254
255         ret = dhdcdc_msg(dhd);
256         if (ret < 0)
257                 goto done;
258
259         ret = dhdcdc_cmplt(dhd, prot->reqid, len);
260         if (ret < 0)
261                 goto done;
262
263         flags = le32_to_cpu(msg->flags);
264         id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT;
265
266         if (id != prot->reqid) {
267                 DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n",
268                            brcmf_ifname(dhd, ifidx), __func__, id,
269                            prot->reqid));
270                 ret = -EINVAL;
271                 goto done;
272         }
273
274         /* Check the ERROR flag */
275         if (flags & CDCF_IOC_ERROR) {
276                 ret = le32_to_cpu(msg->status);
277                 /* Cache error from dongle */
278                 dhd->dongle_error = ret;
279         }
280
281 done:
282         return ret;
283 }
284
285 extern int dhd_bus_interface(struct dhd_bus *bus, uint arg, void *arg2);
286 int
287 dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t *ioc, void *buf, int len)
288 {
289         dhd_prot_t *prot = dhd->prot;
290         int ret = -1;
291
292         if (dhd->busstate == DHD_BUS_DOWN) {
293                 DHD_ERROR(("%s : bus is down. we have nothing to do\n",
294                            __func__));
295                 return ret;
296         }
297         brcmf_os_proto_block(dhd);
298
299         DHD_TRACE(("%s: Enter\n", __func__));
300
301         ASSERT(len <= BRCMF_C_IOCTL_MAXLEN);
302
303         if (len > BRCMF_C_IOCTL_MAXLEN)
304                 goto done;
305
306         if (prot->pending == true) {
307                 DHD_TRACE(("CDC packet is pending!!!! cmd=0x%x (%lu) "
308                         "lastcmd=0x%x (%lu)\n",
309                         ioc->cmd, (unsigned long)ioc->cmd, prot->lastcmd,
310                         (unsigned long)prot->lastcmd));
311                 if ((ioc->cmd == BRCMF_C_SET_VAR) ||
312                     (ioc->cmd == BRCMF_C_GET_VAR))
313                         DHD_TRACE(("iovar cmd=%s\n", (char *)buf));
314
315                 goto done;
316         }
317
318         prot->pending = true;
319         prot->lastcmd = ioc->cmd;
320         if (ioc->set)
321                 ret = dhdcdc_set_ioctl(dhd, ifidx, ioc->cmd, buf, len);
322         else {
323                 ret = dhdcdc_query_ioctl(dhd, ifidx, ioc->cmd, buf, len);
324                 if (ret > 0)
325                         ioc->used = ret - sizeof(struct cdc_ioctl);
326         }
327
328         /* Too many programs assume ioctl() returns 0 on success */
329         if (ret >= 0)
330                 ret = 0;
331         else {
332                 struct cdc_ioctl *msg = &prot->msg;
333                 /* len == needed when set/query fails from dongle */
334                 ioc->needed = le32_to_cpu(msg->len);
335         }
336
337         /* Intercept the wme_dp ioctl here */
338         if (!ret && ioc->cmd == BRCMF_C_SET_VAR &&
339             !strcmp(buf, "wme_dp")) {
340                 int slen, val = 0;
341
342                 slen = strlen("wme_dp") + 1;
343                 if (len >= (int)(slen + sizeof(int)))
344                         memcpy(&val, (char *)buf + slen, sizeof(int));
345                 dhd->wme_dp = (u8) le32_to_cpu(val);
346         }
347
348         prot->pending = false;
349
350 done:
351         brcmf_os_proto_unblock(dhd);
352
353         return ret;
354 }
355
356 #define PKTSUMNEEDED(skb) \
357                 (((struct sk_buff *)(skb))->ip_summed == CHECKSUM_PARTIAL)
358 #define PKTSETSUMGOOD(skb, x) \
359                 (((struct sk_buff *)(skb))->ip_summed = \
360                 ((x) ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE))
361
362 /* PKTSETSUMNEEDED and PKTSUMGOOD are not possible because
363         skb->ip_summed is overloaded */
364
365 int
366 dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name,
367                   void *params, int plen, void *arg, int len, bool set)
368 {
369         return -ENOTSUPP;
370 }
371
372 void dhd_prot_dump(dhd_pub_t *dhdp, struct brcmu_strbuf *strbuf)
373 {
374         brcmu_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid);
375 }
376
377 void dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, struct sk_buff *pktbuf)
378 {
379 #ifdef BDC
380         struct bdc_header *h;
381 #endif                          /* BDC */
382
383         DHD_TRACE(("%s: Enter\n", __func__));
384
385 #ifdef BDC
386         /* Push BDC header used to convey priority for buses that don't */
387
388         skb_push(pktbuf, BDC_HEADER_LEN);
389
390         h = (struct bdc_header *)(pktbuf->data);
391
392         h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT);
393         if (PKTSUMNEEDED(pktbuf))
394                 h->flags |= BDC_FLAG_SUM_NEEDED;
395
396         h->priority = (pktbuf->priority & BDC_PRIORITY_MASK);
397         h->flags2 = 0;
398         h->rssi = 0;
399 #endif                          /* BDC */
400         BDC_SET_IF_IDX(h, ifidx);
401 }
402
403 int dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, struct sk_buff *pktbuf)
404 {
405 #ifdef BDC
406         struct bdc_header *h;
407 #endif
408
409         DHD_TRACE(("%s: Enter\n", __func__));
410
411 #ifdef BDC
412         /* Pop BDC header used to convey priority for buses that don't */
413
414         if (pktbuf->len < BDC_HEADER_LEN) {
415                 DHD_ERROR(("%s: rx data too short (%d < %d)\n", __func__,
416                            pktbuf->len, BDC_HEADER_LEN));
417                 return -EBADE;
418         }
419
420         h = (struct bdc_header *)(pktbuf->data);
421
422         *ifidx = BDC_GET_IF_IDX(h);
423         if (*ifidx >= DHD_MAX_IFS) {
424                 DHD_ERROR(("%s: rx data ifnum out of range (%d)\n",
425                            __func__, *ifidx));
426                 return -EBADE;
427         }
428
429         if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) !=
430             BDC_PROTO_VER) {
431                 DHD_ERROR(("%s: non-BDC packet received, flags 0x%x\n",
432                            brcmf_ifname(dhd, *ifidx), h->flags));
433                 return -EBADE;
434         }
435
436         if (h->flags & BDC_FLAG_SUM_GOOD) {
437                 DHD_INFO(("%s: BDC packet received with good rx-csum, "
438                         "flags 0x%x\n",
439                         brcmf_ifname(dhd, *ifidx), h->flags));
440                 PKTSETSUMGOOD(pktbuf, true);
441         }
442
443         pktbuf->priority = h->priority & BDC_PRIORITY_MASK;
444
445         skb_pull(pktbuf, BDC_HEADER_LEN);
446 #endif                          /* BDC */
447
448         return 0;
449 }
450
451 int dhd_prot_attach(dhd_pub_t *dhd)
452 {
453         dhd_prot_t *cdc;
454
455         cdc = kzalloc(sizeof(dhd_prot_t), GFP_ATOMIC);
456         if (!cdc) {
457                 DHD_ERROR(("%s: kmalloc failed\n", __func__));
458                 goto fail;
459         }
460
461         /* ensure that the msg buf directly follows the cdc msg struct */
462         if ((unsigned long)(&cdc->msg + 1) != (unsigned long)cdc->buf) {
463                 DHD_ERROR(("dhd_prot_t is not correctly defined\n"));
464                 goto fail;
465         }
466
467         dhd->prot = cdc;
468 #ifdef BDC
469         dhd->hdrlen += BDC_HEADER_LEN;
470 #endif
471         dhd->maxctl = BRCMF_C_IOCTL_MAXLEN +
472                                 sizeof(struct cdc_ioctl) + ROUND_UP_MARGIN;
473         return 0;
474
475 fail:
476         kfree(cdc);
477         return -ENOMEM;
478 }
479
480 /* ~NOTE~ What if another thread is waiting on the semaphore?  Holding it? */
481 void dhd_prot_detach(dhd_pub_t *dhd)
482 {
483         kfree(dhd->prot);
484         dhd->prot = NULL;
485 }
486
487 void dhd_prot_dstats(dhd_pub_t *dhd)
488 {
489         /* No stats from dongle added yet, copy bus stats */
490         dhd->dstats.tx_packets = dhd->tx_packets;
491         dhd->dstats.tx_errors = dhd->tx_errors;
492         dhd->dstats.rx_packets = dhd->rx_packets;
493         dhd->dstats.rx_errors = dhd->rx_errors;
494         dhd->dstats.rx_dropped = dhd->rx_dropped;
495         dhd->dstats.multicast = dhd->rx_multicast;
496         return;
497 }
498
499 int dhd_prot_init(dhd_pub_t *dhd)
500 {
501         int ret = 0;
502         char buf[128];
503
504         DHD_TRACE(("%s: Enter\n", __func__));
505
506         brcmf_os_proto_block(dhd);
507
508         /* Get the device MAC address */
509         strcpy(buf, "cur_etheraddr");
510         ret = dhdcdc_query_ioctl(dhd, 0, BRCMF_C_GET_VAR, buf, sizeof(buf));
511         if (ret < 0) {
512                 brcmf_os_proto_unblock(dhd);
513                 return ret;
514         }
515         memcpy(dhd->mac, buf, ETH_ALEN);
516
517         brcmf_os_proto_unblock(dhd);
518
519 #ifdef EMBEDDED_PLATFORM
520         ret = brcmf_c_preinit_ioctls(dhd);
521 #endif                          /* EMBEDDED_PLATFORM */
522
523         /* Always assumes wl for now */
524         dhd->iswl = true;
525
526         return ret;
527 }
528
529 void dhd_prot_stop(dhd_pub_t *dhd)
530 {
531         /* Nothing to do for CDC */
532 }