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