dhd_common.c 9.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * Copyright (c) 2010 Broadcom Corporation
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
16

17 18 19 20 21 22 23 24
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/netdevice.h>
#include <brcmu_wifi.h>
#include <brcmu_utils.h>
#include "dhd.h"
#include "dhd_bus.h"
#include "dhd_dbg.h"
25
#include "fwil.h"
26
#include "fwil_types.h"
27
#include "tracepoint.h"
28

29 30 31 32 33
#define PKTFILTER_BUF_SIZE		128
#define BRCMF_DEFAULT_BCN_TIMEOUT	3
#define BRCMF_DEFAULT_SCAN_CHANNEL_TIME	40
#define BRCMF_DEFAULT_SCAN_UNASSOC_TIME	40
#define BRCMF_DEFAULT_PACKET_FILTER	"100 0 0 0 0x01 0x00"
34

J
Joe Perches 已提交
35
#ifdef DEBUG
36 37 38 39 40 41 42 43
static const char brcmf_version[] =
	"Dongle Host Driver, version " BRCMF_VERSION_STR "\nCompiled on "
	__DATE__ " at " __TIME__;
#else
static const char brcmf_version[] =
	"Dongle Host Driver, version " BRCMF_VERSION_STR;
#endif

44

45
bool brcmf_c_prec_enq(struct device *dev, struct pktq *q,
46 47 48 49 50
		      struct sk_buff *pkt, int prec)
{
	struct sk_buff *p;
	int eprec = -1;		/* precedence to evict from */
	bool discard_oldest;
51 52
	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
	struct brcmf_pub *drvr = bus_if->drvr;
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80

	/* Fast case, precedence queue is not full and we are also not
	 * exceeding total queue length
	 */
	if (!pktq_pfull(q, prec) && !pktq_full(q)) {
		brcmu_pktq_penq(q, prec, pkt);
		return true;
	}

	/* Determine precedence from which to evict packet, if any */
	if (pktq_pfull(q, prec))
		eprec = prec;
	else if (pktq_full(q)) {
		p = brcmu_pktq_peek_tail(q, &eprec);
		if (eprec > prec)
			return false;
	}

	/* Evict if needed */
	if (eprec >= 0) {
		/* Detect queueing to unconfigured precedence */
		discard_oldest = ac_bitmap_tst(drvr->wme_dp, eprec);
		if (eprec == prec && !discard_oldest)
			return false;	/* refuse newer (incoming) packet */
		/* Evict packet according to discard policy */
		p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) :
			brcmu_pktq_pdeq_tail(q, eprec);
		if (p == NULL)
81
			brcmf_err("brcmu_pktq_penq() failed, oldest %d\n",
82 83 84 85 86 87 88 89
				  discard_oldest);

		brcmu_pkt_buf_free_skb(p);
	}

	/* Enqueue */
	p = brcmu_pktq_penq(q, prec, pkt);
	if (p == NULL)
90
		brcmf_err("brcmu_pktq_penq() failed\n");
91 92 93 94 95 96 97 98 99

	return p != NULL;
}

/* Convert user's input in hex pattern to byte-size mask */
static int brcmf_c_pattern_atoh(char *src, char *dst)
{
	int i;
	if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) {
100
		brcmf_err("Mask invalid format. Needs to start with 0x\n");
101 102 103 104
		return -EINVAL;
	}
	src = src + 2;		/* Skip past 0x */
	if (strlen(src) % 2 != 0) {
105
		brcmf_err("Mask invalid format. Length must be even.\n");
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
		return -EINVAL;
	}
	for (i = 0; *src != '\0'; i++) {
		unsigned long res;
		char num[3];
		strncpy(num, src, 2);
		num[2] = '\0';
		if (kstrtoul(num, 16, &res))
			return -EINVAL;
		dst[i] = (u8)res;
		src += 2;
	}
	return i;
}

121 122 123
static void
brcmf_c_pktfilter_offload_enable(struct brcmf_if *ifp, char *arg, int enable,
				 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 133 134 135 136
	if (!arg_save)
		goto fail;

	arg_org = arg_save;

137
	argv = strsep(&arg_save, " ");
138

139
	if (argv == NULL) {
140
		brcmf_err("No args provided\n");
141 142 143 144 145
		goto fail;
	}

	/* Parse packet filter id. */
	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 153 154
	err = brcmf_fil_iovar_data_set(ifp, "pkt_filter_enable", &enable_parm,
				       sizeof(enable_parm));
	if (err)
155
		brcmf_err("Set pkt_filter_enable error (%d)\n", err);
156

157 158 159
	/* Control the master mode */
	err = brcmf_fil_iovar_int_set(ifp, "pkt_filter_mode", master_mode);
	if (err)
160
		brcmf_err("Set pkt_filter_mode error (%d)\n", err);
161 162 163 164 165

fail:
	kfree(arg_org);
}

166
static void brcmf_c_pktfilter_offload_set(struct brcmf_if *ifp, char *arg)
167
{
168
	struct brcmf_pkt_filter_le *pkt_filter;
169 170
	unsigned long res;
	int buf_len;
171
	s32 err;
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
	u32 mask_size;
	u32 pattern_size;
	char *argv[8], *buf = NULL;
	int i = 0;
	char *arg_save = NULL, *arg_org = NULL;

	arg_save = kstrdup(arg, GFP_ATOMIC);
	if (!arg_save)
		goto fail;

	arg_org = arg_save;

	buf = kmalloc(PKTFILTER_BUF_SIZE, GFP_ATOMIC);
	if (!buf)
		goto fail;

	argv[i] = strsep(&arg_save, " ");
189 190 191
	while (argv[i]) {
		i++;
		if (i >= 8) {
192
			brcmf_err("Too many parameters\n");
193 194
			goto fail;
		}
195
		argv[i] = strsep(&arg_save, " ");
196
	}
197

198
	if (i != 6) {
199
		brcmf_err("Not enough args provided %d\n", i);
200 201 202
		goto fail;
	}

203
	pkt_filter = (struct brcmf_pkt_filter_le *)buf;
204 205

	/* Parse packet filter id. */
206 207 208
	pkt_filter->id = 0;
	if (!kstrtoul(argv[0], 0, &res))
		pkt_filter->id = cpu_to_le32((u32)res);
209 210

	/* Parse filter polarity. */
211 212 213
	pkt_filter->negate_match = 0;
	if (!kstrtoul(argv[1], 0, &res))
		pkt_filter->negate_match = cpu_to_le32((u32)res);
214 215

	/* Parse filter type. */
216 217 218
	pkt_filter->type = 0;
	if (!kstrtoul(argv[2], 0, &res))
		pkt_filter->type = cpu_to_le32((u32)res);
219 220

	/* Parse pattern filter offset. */
221 222 223
	pkt_filter->u.pattern.offset = 0;
	if (!kstrtoul(argv[3], 0, &res))
		pkt_filter->u.pattern.offset = cpu_to_le32((u32)res);
224 225

	/* Parse pattern filter mask. */
226 227
	mask_size = brcmf_c_pattern_atoh(argv[4],
			(char *)pkt_filter->u.pattern.mask_and_pattern);
228 229

	/* Parse pattern filter pattern. */
230 231
	pattern_size = brcmf_c_pattern_atoh(argv[5],
		(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 236 237
		goto fail;
	}

238
	pkt_filter->u.pattern.size_bytes = cpu_to_le32(mask_size);
239 240
	buf_len = offsetof(struct brcmf_pkt_filter_le,
			   u.pattern.mask_and_pattern);
241
	buf_len += mask_size + pattern_size;
242

243 244 245
	err = brcmf_fil_iovar_data_set(ifp, "pkt_filter_add", pkt_filter,
				       buf_len);
	if (err)
246
		brcmf_err("Set pkt_filter_add error (%d)\n", err);
247 248 249 250 251 252 253

fail:
	kfree(arg_org);

	kfree(buf);
}

254
int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
255
{
256 257 258 259
	s8 eventmask[BRCMF_EVENTING_MASK_LEN];
	u8 buf[BRCMF_DCMD_SMLEN];
	char *ptr;
	s32 err;
260

261 262 263 264
	/* retreive mac address */
	err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
				       sizeof(ifp->mac_addr));
	if (err < 0) {
265
		brcmf_err("Retreiving cur_etheraddr failed, %d\n",
266 267
			  err);
		goto done;
268
	}
269
	memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac));
270 271 272

	/* query for 'ver' to get version info from firmware */
	memset(buf, 0, sizeof(buf));
273 274 275
	strcpy(buf, "ver");
	err = brcmf_fil_iovar_data_get(ifp, "ver", buf, sizeof(buf));
	if (err < 0) {
276
		brcmf_err("Retreiving version information failed, %d\n",
277 278 279 280
			  err);
		goto done;
	}
	ptr = (char *)buf;
281
	strsep(&ptr, "\n");
282

283
	/* Print fw version info */
284
	brcmf_err("Firmware version = %s\n", buf);
285

286 287 288 289
	/* locate firmware version number for ethtool */
	ptr = strrchr(buf, ' ') + 1;
	strlcpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver));

290 291 292 293 294 295 296
	/*
	 * Setup timeout if Beacons are lost and roam is off to report
	 * link down
	 */
	err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout",
				      BRCMF_DEFAULT_BCN_TIMEOUT);
	if (err) {
297
		brcmf_err("bcn_timeout error (%d)\n", err);
298 299
		goto done;
	}
300 301

	/* Enable/Disable build-in roaming to allowed ext supplicant to take
302 303 304 305
	 * of romaing
	 */
	err = brcmf_fil_iovar_int_set(ifp, "roam_off", 1);
	if (err) {
306
		brcmf_err("roam_off error (%d)\n", err);
307 308 309 310 311 312 313
		goto done;
	}

	/* Setup event_msgs, enable E_IF */
	err = brcmf_fil_iovar_data_get(ifp, "event_msgs", eventmask,
				       BRCMF_EVENTING_MASK_LEN);
	if (err) {
314
		brcmf_err("Get event_msgs error (%d)\n", err);
315 316 317 318 319 320
		goto done;
	}
	setbit(eventmask, BRCMF_E_IF);
	err = brcmf_fil_iovar_data_set(ifp, "event_msgs", eventmask,
				       BRCMF_EVENTING_MASK_LEN);
	if (err) {
321
		brcmf_err("Set event_msgs error (%d)\n", err);
322 323 324 325 326 327 328
		goto done;
	}

	/* Setup default scan channel time */
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
				    BRCMF_DEFAULT_SCAN_CHANNEL_TIME);
	if (err) {
329
		brcmf_err("BRCMF_C_SET_SCAN_CHANNEL_TIME error (%d)\n",
330 331 332 333 334 335 336 337
			  err);
		goto done;
	}

	/* Setup default scan unassoc time */
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
				    BRCMF_DEFAULT_SCAN_UNASSOC_TIME);
	if (err) {
338
		brcmf_err("BRCMF_C_SET_SCAN_UNASSOC_TIME error (%d)\n",
339 340 341 342 343 344 345 346 347
			  err);
		goto done;
	}

	/* Setup packet filter */
	brcmf_c_pktfilter_offload_set(ifp, BRCMF_DEFAULT_PACKET_FILTER);
	brcmf_c_pktfilter_offload_enable(ifp, BRCMF_DEFAULT_PACKET_FILTER,
					 0, true);

348 349
	/* do bus specific preinit here */
	err = brcmf_bus_preinit(ifp->drvr->bus_if);
350 351
done:
	return err;
352
}
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384

#ifdef CONFIG_BRCM_TRACING
void __brcmf_err(const char *func, const char *fmt, ...)
{
	struct va_format vaf = {
		.fmt = fmt,
	};
	va_list args;

	va_start(args, fmt);
	vaf.va = &args;
	pr_err("%s: %pV", func, &vaf);
	trace_brcmf_err(func, &vaf);
	va_end(args);
}
#endif
#if defined(CONFIG_BRCM_TRACING) || defined(CONFIG_BRCMDBG)
void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...)
{
	struct va_format vaf = {
		.fmt = fmt,
	};
	va_list args;

	va_start(args, fmt);
	vaf.va = &args;
	if (brcmf_msg_level & level)
		pr_debug("%s %pV", func, &vaf);
	trace_brcmf_dbg(level, func, &vaf);
	va_end(args);
}
#endif