]> rtime.felk.cvut.cz Git - can-eth-gw-linux.git/blob - drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
[can-eth-gw-linux.git] / drivers / net / wireless / brcm80211 / brcmfmac / dhd_common.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 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18
19 #include <linux/kernel.h>
20 #include <linux/string.h>
21 #include <linux/netdevice.h>
22 #include <brcmu_wifi.h>
23 #include <brcmu_utils.h>
24 #include "dhd.h"
25 #include "dhd_bus.h"
26 #include "dhd_proto.h"
27 #include "dhd_dbg.h"
28 #include "fwil.h"
29
30 #define PKTFILTER_BUF_SIZE              128
31 #define BRCMF_ARPOL_MODE                0xb     /* agent|snoop|peer_autoreply */
32 #define BRCMF_DEFAULT_BCN_TIMEOUT       3
33 #define BRCMF_DEFAULT_SCAN_CHANNEL_TIME 40
34 #define BRCMF_DEFAULT_SCAN_UNASSOC_TIME 40
35 #define BRCMF_DEFAULT_PACKET_FILTER     "100 0 0 0 0x01 0x00"
36
37 #ifdef DEBUG
38 static const char brcmf_version[] =
39         "Dongle Host Driver, version " BRCMF_VERSION_STR "\nCompiled on "
40         __DATE__ " at " __TIME__;
41 #else
42 static const char brcmf_version[] =
43         "Dongle Host Driver, version " BRCMF_VERSION_STR;
44 #endif
45
46
47 bool brcmf_c_prec_enq(struct device *dev, struct pktq *q,
48                       struct sk_buff *pkt, int prec)
49 {
50         struct sk_buff *p;
51         int eprec = -1;         /* precedence to evict from */
52         bool discard_oldest;
53         struct brcmf_bus *bus_if = dev_get_drvdata(dev);
54         struct brcmf_pub *drvr = bus_if->drvr;
55
56         /* Fast case, precedence queue is not full and we are also not
57          * exceeding total queue length
58          */
59         if (!pktq_pfull(q, prec) && !pktq_full(q)) {
60                 brcmu_pktq_penq(q, prec, pkt);
61                 return true;
62         }
63
64         /* Determine precedence from which to evict packet, if any */
65         if (pktq_pfull(q, prec))
66                 eprec = prec;
67         else if (pktq_full(q)) {
68                 p = brcmu_pktq_peek_tail(q, &eprec);
69                 if (eprec > prec)
70                         return false;
71         }
72
73         /* Evict if needed */
74         if (eprec >= 0) {
75                 /* Detect queueing to unconfigured precedence */
76                 discard_oldest = ac_bitmap_tst(drvr->wme_dp, eprec);
77                 if (eprec == prec && !discard_oldest)
78                         return false;   /* refuse newer (incoming) packet */
79                 /* Evict packet according to discard policy */
80                 p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) :
81                         brcmu_pktq_pdeq_tail(q, eprec);
82                 if (p == NULL)
83                         brcmf_err("brcmu_pktq_penq() failed, oldest %d\n",
84                                   discard_oldest);
85
86                 brcmu_pkt_buf_free_skb(p);
87         }
88
89         /* Enqueue */
90         p = brcmu_pktq_penq(q, prec, pkt);
91         if (p == NULL)
92                 brcmf_err("brcmu_pktq_penq() failed\n");
93
94         return p != NULL;
95 }
96
97 /* Convert user's input in hex pattern to byte-size mask */
98 static int brcmf_c_pattern_atoh(char *src, char *dst)
99 {
100         int i;
101         if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) {
102                 brcmf_err("Mask invalid format. Needs to start with 0x\n");
103                 return -EINVAL;
104         }
105         src = src + 2;          /* Skip past 0x */
106         if (strlen(src) % 2 != 0) {
107                 brcmf_err("Mask invalid format. Length must be even.\n");
108                 return -EINVAL;
109         }
110         for (i = 0; *src != '\0'; i++) {
111                 unsigned long res;
112                 char num[3];
113                 strncpy(num, src, 2);
114                 num[2] = '\0';
115                 if (kstrtoul(num, 16, &res))
116                         return -EINVAL;
117                 dst[i] = (u8)res;
118                 src += 2;
119         }
120         return i;
121 }
122
123 static void
124 brcmf_c_pktfilter_offload_enable(struct brcmf_if *ifp, char *arg, int enable,
125                                  int master_mode)
126 {
127         unsigned long res;
128         char *argv;
129         char *arg_save = NULL, *arg_org = NULL;
130         s32 err;
131         struct brcmf_pkt_filter_enable_le enable_parm;
132
133         arg_save = kstrdup(arg, GFP_ATOMIC);
134         if (!arg_save)
135                 goto fail;
136
137         arg_org = arg_save;
138
139         argv = strsep(&arg_save, " ");
140
141         if (argv == NULL) {
142                 brcmf_err("No args provided\n");
143                 goto fail;
144         }
145
146         /* Parse packet filter id. */
147         enable_parm.id = 0;
148         if (!kstrtoul(argv, 0, &res))
149                 enable_parm.id = cpu_to_le32((u32)res);
150
151         /* Enable/disable the specified filter. */
152         enable_parm.enable = cpu_to_le32(enable);
153
154         err = brcmf_fil_iovar_data_set(ifp, "pkt_filter_enable", &enable_parm,
155                                        sizeof(enable_parm));
156         if (err)
157                 brcmf_err("Set pkt_filter_enable error (%d)\n", err);
158
159         /* Control the master mode */
160         err = brcmf_fil_iovar_int_set(ifp, "pkt_filter_mode", master_mode);
161         if (err)
162                 brcmf_err("Set pkt_filter_mode error (%d)\n", err);
163
164 fail:
165         kfree(arg_org);
166 }
167
168 static void brcmf_c_pktfilter_offload_set(struct brcmf_if *ifp, char *arg)
169 {
170         struct brcmf_pkt_filter_le *pkt_filter;
171         unsigned long res;
172         int buf_len;
173         s32 err;
174         u32 mask_size;
175         u32 pattern_size;
176         char *argv[8], *buf = NULL;
177         int i = 0;
178         char *arg_save = NULL, *arg_org = NULL;
179
180         arg_save = kstrdup(arg, GFP_ATOMIC);
181         if (!arg_save)
182                 goto fail;
183
184         arg_org = arg_save;
185
186         buf = kmalloc(PKTFILTER_BUF_SIZE, GFP_ATOMIC);
187         if (!buf)
188                 goto fail;
189
190         argv[i] = strsep(&arg_save, " ");
191         while (argv[i]) {
192                 i++;
193                 if (i >= 8) {
194                         brcmf_err("Too many parameters\n");
195                         goto fail;
196                 }
197                 argv[i] = strsep(&arg_save, " ");
198         }
199
200         if (i != 6) {
201                 brcmf_err("Not enough args provided %d\n", i);
202                 goto fail;
203         }
204
205         pkt_filter = (struct brcmf_pkt_filter_le *)buf;
206
207         /* Parse packet filter id. */
208         pkt_filter->id = 0;
209         if (!kstrtoul(argv[0], 0, &res))
210                 pkt_filter->id = cpu_to_le32((u32)res);
211
212         /* Parse filter polarity. */
213         pkt_filter->negate_match = 0;
214         if (!kstrtoul(argv[1], 0, &res))
215                 pkt_filter->negate_match = cpu_to_le32((u32)res);
216
217         /* Parse filter type. */
218         pkt_filter->type = 0;
219         if (!kstrtoul(argv[2], 0, &res))
220                 pkt_filter->type = cpu_to_le32((u32)res);
221
222         /* Parse pattern filter offset. */
223         pkt_filter->u.pattern.offset = 0;
224         if (!kstrtoul(argv[3], 0, &res))
225                 pkt_filter->u.pattern.offset = cpu_to_le32((u32)res);
226
227         /* Parse pattern filter mask. */
228         mask_size = brcmf_c_pattern_atoh(argv[4],
229                         (char *)pkt_filter->u.pattern.mask_and_pattern);
230
231         /* Parse pattern filter pattern. */
232         pattern_size = brcmf_c_pattern_atoh(argv[5],
233                 (char *)&pkt_filter->u.pattern.mask_and_pattern[mask_size]);
234
235         if (mask_size != pattern_size) {
236                 brcmf_err("Mask and pattern not the same size\n");
237                 goto fail;
238         }
239
240         pkt_filter->u.pattern.size_bytes = cpu_to_le32(mask_size);
241         buf_len = offsetof(struct brcmf_pkt_filter_le,
242                            u.pattern.mask_and_pattern);
243         buf_len += mask_size + pattern_size;
244
245         err = brcmf_fil_iovar_data_set(ifp, "pkt_filter_add", pkt_filter,
246                                        buf_len);
247         if (err)
248                 brcmf_err("Set pkt_filter_add error (%d)\n", err);
249
250 fail:
251         kfree(arg_org);
252
253         kfree(buf);
254 }
255
256 int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
257 {
258         s8 eventmask[BRCMF_EVENTING_MASK_LEN];
259         u8 buf[BRCMF_DCMD_SMLEN];
260         char *ptr;
261         s32 err;
262         struct brcmf_bus_dcmd *cmdlst;
263         struct list_head *cur, *q;
264
265         /* retreive mac address */
266         err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
267                                        sizeof(ifp->mac_addr));
268         if (err < 0) {
269                 brcmf_err("Retreiving cur_etheraddr failed, %d\n",
270                           err);
271                 goto done;
272         }
273         memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac));
274
275         /* query for 'ver' to get version info from firmware */
276         memset(buf, 0, sizeof(buf));
277         strcpy(buf, "ver");
278         err = brcmf_fil_iovar_data_get(ifp, "ver", buf, sizeof(buf));
279         if (err < 0) {
280                 brcmf_err("Retreiving version information failed, %d\n",
281                           err);
282                 goto done;
283         }
284         ptr = (char *)buf;
285         strsep(&ptr, "\n");
286         /* Print fw version info */
287         brcmf_err("Firmware version = %s\n", buf);
288
289         /*
290          * Setup timeout if Beacons are lost and roam is off to report
291          * link down
292          */
293         err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout",
294                                       BRCMF_DEFAULT_BCN_TIMEOUT);
295         if (err) {
296                 brcmf_err("bcn_timeout error (%d)\n", err);
297                 goto done;
298         }
299
300         /* Enable/Disable build-in roaming to allowed ext supplicant to take
301          * of romaing
302          */
303         err = brcmf_fil_iovar_int_set(ifp, "roam_off", 1);
304         if (err) {
305                 brcmf_err("roam_off error (%d)\n", err);
306                 goto done;
307         }
308
309         /* Setup event_msgs, enable E_IF */
310         err = brcmf_fil_iovar_data_get(ifp, "event_msgs", eventmask,
311                                        BRCMF_EVENTING_MASK_LEN);
312         if (err) {
313                 brcmf_err("Get event_msgs error (%d)\n", err);
314                 goto done;
315         }
316         setbit(eventmask, BRCMF_E_IF);
317         err = brcmf_fil_iovar_data_set(ifp, "event_msgs", eventmask,
318                                        BRCMF_EVENTING_MASK_LEN);
319         if (err) {
320                 brcmf_err("Set event_msgs error (%d)\n", err);
321                 goto done;
322         }
323
324         /* Setup default scan channel time */
325         err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
326                                     BRCMF_DEFAULT_SCAN_CHANNEL_TIME);
327         if (err) {
328                 brcmf_err("BRCMF_C_SET_SCAN_CHANNEL_TIME error (%d)\n",
329                           err);
330                 goto done;
331         }
332
333         /* Setup default scan unassoc time */
334         err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
335                                     BRCMF_DEFAULT_SCAN_UNASSOC_TIME);
336         if (err) {
337                 brcmf_err("BRCMF_C_SET_SCAN_UNASSOC_TIME error (%d)\n",
338                           err);
339                 goto done;
340         }
341
342         /* Try to set and enable ARP offload feature, this may fail */
343         err = brcmf_fil_iovar_int_set(ifp, "arp_ol", BRCMF_ARPOL_MODE);
344         if (err) {
345                 brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
346                           BRCMF_ARPOL_MODE, err);
347                 err = 0;
348         } else {
349                 err = brcmf_fil_iovar_int_set(ifp, "arpoe", 1);
350                 if (err) {
351                         brcmf_dbg(TRACE, "failed to enable ARP offload err = %d\n",
352                                   err);
353                         err = 0;
354                 } else
355                         brcmf_dbg(TRACE, "successfully enabled ARP offload to 0x%x\n",
356                                   BRCMF_ARPOL_MODE);
357         }
358
359         /* Setup packet filter */
360         brcmf_c_pktfilter_offload_set(ifp, BRCMF_DEFAULT_PACKET_FILTER);
361         brcmf_c_pktfilter_offload_enable(ifp, BRCMF_DEFAULT_PACKET_FILTER,
362                                          0, true);
363
364         /* set bus specific command if there is any */
365         list_for_each_safe(cur, q, &ifp->drvr->bus_if->dcmd_list) {
366                 cmdlst = list_entry(cur, struct brcmf_bus_dcmd, list);
367                 if (cmdlst->name && cmdlst->param && cmdlst->param_len) {
368                         brcmf_fil_iovar_data_set(ifp, cmdlst->name,
369                                                  cmdlst->param,
370                                                  cmdlst->param_len);
371                 }
372                 list_del(cur);
373                 kfree(cmdlst);
374         }
375 done:
376         return err;
377 }