dhd_linux.c 28.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*
 * 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.
 */

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/mmc/sdio_func.h>
#include <linux/random.h>
#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <linux/fcntl.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/hardirq.h>
#include <linux/mutex.h>
#include <linux/wait.h>
34
#include <linux/module.h>
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <net/cfg80211.h>
#include <net/rtnetlink.h>
#include <defs.h>
#include <brcmu_utils.h>
#include <brcmu_wifi.h>

#include "dhd.h"
#include "dhd_bus.h"
#include "dhd_proto.h"
#include "dhd_dbg.h"
#include "wl_cfg80211.h"

MODULE_AUTHOR("Broadcom Corporation");
MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac driver.");
MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN fullmac cards");
MODULE_LICENSE("Dual BSD/GPL");


/* Interface control information */
struct brcmf_if {
55
	struct brcmf_pub *drvr;	/* back pointer to brcmf_pub */
56
57
58
59
60
61
62
63
	/* OS/stack specifics */
	struct net_device *ndev;
	struct net_device_stats stats;
	int idx;		/* iface idx in dongle */
	u8 mac_addr[ETH_ALEN];	/* assigned MAC address */
};

/* Error bits */
64
int brcmf_msg_level = BRCMF_ERROR_VAL;
65
66
module_param(brcmf_msg_level, int, 0);

67
int brcmf_ifname2idx(struct brcmf_pub *drvr, char *name)
68
69
70
71
72
73
74
75
{
	int i = BRCMF_MAX_IFS;
	struct brcmf_if *ifp;

	if (name == NULL || *name == '\0')
		return 0;

	while (--i > 0) {
76
		ifp = drvr->iflist[i];
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
		if (ifp && !strncmp(ifp->ndev->name, name, IFNAMSIZ))
			break;
	}

	brcmf_dbg(TRACE, "return idx %d for \"%s\"\n", i, name);

	return i;		/* default - the primary interface */
}

char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)
{
	if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) {
		brcmf_dbg(ERROR, "ifidx %d out of range\n", ifidx);
		return "<if_bad>";
	}

93
	if (drvr->iflist[ifidx] == NULL) {
94
95
96
97
		brcmf_dbg(ERROR, "null i/f %d\n", ifidx);
		return "<if_null>";
	}

98
99
	if (drvr->iflist[ifidx]->ndev)
		return drvr->iflist[ifidx]->ndev->name;
100
101
102
103
104
105
106
107

	return "<if_none>";
}

static void _brcmf_set_multicast_list(struct work_struct *work)
{
	struct net_device *ndev;
	struct netdev_hw_addr *ha;
108
	u32 dcmd_value, cnt;
109
	__le32 cnt_le;
110
	__le32 dcmd_le_value;
111
112
113
114
115
116

	struct brcmf_dcmd dcmd;
	char *buf, *bufp;
	uint buflen;
	int ret;

117
	struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
118
119
						    multicast_work);

120
	ndev = drvr->iflist[0]->ndev;
121
122
123
	cnt = netdev_mc_count(ndev);

	/* Determine initial value of allmulti flag */
124
	dcmd_value = (ndev->flags & IFF_ALLMULTI) ? true : false;
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153

	/* Send down the multicast list first. */

	buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETH_ALEN);
	bufp = buf = kmalloc(buflen, GFP_ATOMIC);
	if (!bufp)
		return;

	strcpy(bufp, "mcast_list");
	bufp += strlen("mcast_list") + 1;

	cnt_le = cpu_to_le32(cnt);
	memcpy(bufp, &cnt_le, sizeof(cnt));
	bufp += sizeof(cnt_le);

	netdev_for_each_mc_addr(ha, ndev) {
		if (!cnt)
			break;
		memcpy(bufp, ha->addr, ETH_ALEN);
		bufp += ETH_ALEN;
		cnt--;
	}

	memset(&dcmd, 0, sizeof(dcmd));
	dcmd.cmd = BRCMF_C_SET_VAR;
	dcmd.buf = buf;
	dcmd.len = buflen;
	dcmd.set = true;

154
	ret = brcmf_proto_dcmd(drvr, 0, &dcmd, dcmd.len);
155
156
	if (ret < 0) {
		brcmf_dbg(ERROR, "%s: set mcast_list failed, cnt %d\n",
157
			  brcmf_ifname(drvr, 0), cnt);
158
		dcmd_value = cnt ? true : dcmd_value;
159
160
161
162
163
164
165
166
167
	}

	kfree(buf);

	/* Now send the allmulti setting.  This is based on the setting in the
	 * net_device flags, but might be modified above to be turned on if we
	 * were trying to set some addresses and dongle rejected it...
	 */

168
	buflen = sizeof("allmulti") + sizeof(dcmd_value);
169
170
171
172
	buf = kmalloc(buflen, GFP_ATOMIC);
	if (!buf)
		return;

173
	dcmd_le_value = cpu_to_le32(dcmd_value);
174

175
	if (!brcmf_c_mkiovar
176
177
	    ("allmulti", (void *)&dcmd_le_value,
	    sizeof(dcmd_le_value), buf, buflen)) {
178
		brcmf_dbg(ERROR, "%s: mkiovar failed for allmulti, datalen %d buflen %u\n",
179
			  brcmf_ifname(drvr, 0),
180
			  (int)sizeof(dcmd_value), buflen);
181
182
183
184
185
186
187
188
189
190
		kfree(buf);
		return;
	}

	memset(&dcmd, 0, sizeof(dcmd));
	dcmd.cmd = BRCMF_C_SET_VAR;
	dcmd.buf = buf;
	dcmd.len = buflen;
	dcmd.set = true;

191
	ret = brcmf_proto_dcmd(drvr, 0, &dcmd, dcmd.len);
192
193
	if (ret < 0) {
		brcmf_dbg(ERROR, "%s: set allmulti %d failed\n",
194
			  brcmf_ifname(drvr, 0),
195
			  le32_to_cpu(dcmd_le_value));
196
197
198
199
200
201
202
	}

	kfree(buf);

	/* Finally, pick up the PROMISC flag as well, like the NIC
		 driver does */

203
204
	dcmd_value = (ndev->flags & IFF_PROMISC) ? true : false;
	dcmd_le_value = cpu_to_le32(dcmd_value);
205
206
207

	memset(&dcmd, 0, sizeof(dcmd));
	dcmd.cmd = BRCMF_C_SET_PROMISC;
208
209
	dcmd.buf = &dcmd_le_value;
	dcmd.len = sizeof(dcmd_le_value);
210
211
	dcmd.set = true;

212
	ret = brcmf_proto_dcmd(drvr, 0, &dcmd, dcmd.len);
213
214
	if (ret < 0) {
		brcmf_dbg(ERROR, "%s: set promisc %d failed\n",
215
			  brcmf_ifname(drvr, 0),
216
			  le32_to_cpu(dcmd_le_value));
217
218
219
220
221
222
223
224
225
226
	}
}

static void
_brcmf_set_mac_address(struct work_struct *work)
{
	char buf[32];
	struct brcmf_dcmd dcmd;
	int ret;

227
	struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
228
229
230
						    setmacaddr_work);

	brcmf_dbg(TRACE, "enter\n");
231
	if (!brcmf_c_mkiovar("cur_etheraddr", (char *)drvr->macvalue,
232
233
			   ETH_ALEN, buf, 32)) {
		brcmf_dbg(ERROR, "%s: mkiovar failed for cur_etheraddr\n",
234
			  brcmf_ifname(drvr, 0));
235
236
237
238
239
240
241
242
		return;
	}
	memset(&dcmd, 0, sizeof(dcmd));
	dcmd.cmd = BRCMF_C_SET_VAR;
	dcmd.buf = buf;
	dcmd.len = 32;
	dcmd.set = true;

243
	ret = brcmf_proto_dcmd(drvr, 0, &dcmd, dcmd.len);
244
245
	if (ret < 0)
		brcmf_dbg(ERROR, "%s: set cur_etheraddr failed\n",
246
			  brcmf_ifname(drvr, 0));
247
	else
248
249
		memcpy(drvr->iflist[0]->ndev->dev_addr,
		       drvr->macvalue, ETH_ALEN);
250
251
252
253
254
255

	return;
}

static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
{
256
	struct brcmf_if *ifp = netdev_priv(ndev);
257
	struct brcmf_pub *drvr = ifp->drvr;
258
259
	struct sockaddr *sa = (struct sockaddr *)addr;

260
261
	memcpy(&drvr->macvalue, sa->sa_data, ETH_ALEN);
	schedule_work(&drvr->setmacaddr_work);
262
263
264
265
266
	return 0;
}

static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
{
267
	struct brcmf_if *ifp = netdev_priv(ndev);
268
	struct brcmf_pub *drvr = ifp->drvr;
269

270
	schedule_work(&drvr->multicast_work);
271
272
273
274
275
}

int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf)
{
	/* Reject if down */
276
	if (!drvr->up || (drvr->bus_if->state == BRCMF_BUS_DOWN))
277
278
279
280
281
282
283
284
285
286
		return -ENODEV;

	/* Update multicast statistic */
	if (pktbuf->len >= ETH_ALEN) {
		u8 *pktdata = (u8 *) (pktbuf->data);
		struct ethhdr *eh = (struct ethhdr *)pktdata;

		if (is_multicast_ether_addr(eh->h_dest))
			drvr->tx_multicast++;
		if (ntohs(eh->h_proto) == ETH_P_PAE)
287
			atomic_inc(&drvr->pend_8021x_cnt);
288
289
290
291
292
293
	}

	/* If the protocol uses a data header, apply it */
	brcmf_proto_hdrpush(drvr, ifidx, pktbuf);

	/* Use bus module to send data frame */
294
	return brcmf_sdbrcm_bus_txdata(drvr->dev, pktbuf);
295
296
297
298
299
}

static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
	int ret;
300
	struct brcmf_if *ifp = netdev_priv(ndev);
301
	struct brcmf_pub *drvr = ifp->drvr;
302
303
304
305

	brcmf_dbg(TRACE, "Enter\n");

	/* Reject if down */
306
307
	if (!drvr->up ||
	    (drvr->bus_if->state == BRCMF_BUS_DOWN)) {
308
		brcmf_dbg(ERROR, "xmit rejected pub.up=%d state=%d\n",
309
310
			  drvr->up,
			  drvr->bus_if->state);
311
312
313
314
		netif_stop_queue(ndev);
		return -ENODEV;
	}

315
	if (!drvr->iflist[ifp->idx]) {
316
		brcmf_dbg(ERROR, "bad ifidx %d\n", ifp->idx);
317
318
319
320
321
		netif_stop_queue(ndev);
		return -ENODEV;
	}

	/* Make sure there's enough room for any header */
322
	if (skb_headroom(skb) < drvr->hdrlen) {
323
324
325
		struct sk_buff *skb2;

		brcmf_dbg(INFO, "%s: insufficient headroom\n",
326
327
328
			  brcmf_ifname(drvr, ifp->idx));
		drvr->tx_realloc++;
		skb2 = skb_realloc_headroom(skb, drvr->hdrlen);
329
330
331
332
		dev_kfree_skb(skb);
		skb = skb2;
		if (skb == NULL) {
			brcmf_dbg(ERROR, "%s: skb_realloc_headroom failed\n",
333
				  brcmf_ifname(drvr, ifp->idx));
334
335
336
337
338
			ret = -ENOMEM;
			goto done;
		}
	}

339
	ret = brcmf_sendpkt(drvr, ifp->idx, skb);
340
341
342

done:
	if (ret)
343
		drvr->dstats.tx_dropped++;
344
	else
345
		drvr->tx_packets++;
346
347
348
349
350

	/* Return ok: we always eat the packet */
	return 0;
}

351
void brcmf_txflowcontrol(struct device *dev, int ifidx, bool state)
352
353
{
	struct net_device *ndev;
354
355
	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
	struct brcmf_pub *drvr = bus_if->drvr;
356
357
358
359

	brcmf_dbg(TRACE, "Enter\n");

	drvr->txoff = state;
360
	ndev = drvr->iflist[ifidx]->ndev;
361
362
363
364
365
366
	if (state == ON)
		netif_stop_queue(ndev);
	else
		netif_wake_queue(ndev);
}

367
static int brcmf_host_event(struct brcmf_pub *drvr, int *ifidx,
368
369
370
371
372
			    void *pktdata, struct brcmf_event_msg *event,
			    void **data)
{
	int bcmerror = 0;

373
	bcmerror = brcmf_c_host_event(drvr, ifidx, pktdata, event, data);
374
375
376
	if (bcmerror != 0)
		return bcmerror;

377
378
	if (drvr->iflist[*ifidx]->ndev)
		brcmf_cfg80211_event(drvr->iflist[*ifidx]->ndev,
379
380
381
382
383
				     event, *data);

	return bcmerror;
}

384
void brcmf_rx_frame(struct device *dev, int ifidx,
385
		    struct sk_buff_head *skb_list)
386
387
388
389
{
	unsigned char *eth;
	uint len;
	void *data;
390
	struct sk_buff *skb, *pnext;
391
392
	struct brcmf_if *ifp;
	struct brcmf_event_msg event;
393
394
	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
	struct brcmf_pub *drvr = bus_if->drvr;
395
396
397

	brcmf_dbg(TRACE, "Enter\n");

398
399
	skb_queue_walk_safe(skb_list, skb, pnext) {
		skb_unlink(skb, skb_list);
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415

		/* Get the protocol, maintain skb around eth_type_trans()
		 * The main reason for this hack is for the limitation of
		 * Linux 2.4 where 'eth_type_trans' uses the
		 * 'net->hard_header_len'
		 * to perform skb_pull inside vs ETH_HLEN. Since to avoid
		 * coping of the packet coming from the network stack to add
		 * BDC, Hardware header etc, during network interface
		 * registration
		 * we set the 'net->hard_header_len' to ETH_HLEN + extra space
		 * required
		 * for BDC, Hardware header etc. and not just the ETH_HLEN
		 */
		eth = skb->data;
		len = skb->len;

416
		ifp = drvr->iflist[ifidx];
417
		if (ifp == NULL)
418
			ifp = drvr->iflist[0];
419

420
421
422
423
424
425
		if (!ifp || !ifp->ndev ||
		    ifp->ndev->reg_state != NETREG_REGISTERED) {
			brcmu_pkt_buf_free_skb(skb);
			continue;
		}

426
427
428
429
		skb->dev = ifp->ndev;
		skb->protocol = eth_type_trans(skb, skb->dev);

		if (skb->pkt_type == PACKET_MULTICAST)
430
			drvr->rx_multicast++;
431
432
433
434
435
436
437
438
439

		skb->data = eth;
		skb->len = len;

		/* Strip header, count, deliver upward */
		skb_pull(skb, ETH_HLEN);

		/* Process special event packets and then discard them */
		if (ntohs(skb->protocol) == ETH_P_LINK_CTL)
440
			brcmf_host_event(drvr, &ifidx,
441
442
443
					  skb_mac_header(skb),
					  &event, &data);

444
445
		if (drvr->iflist[ifidx]) {
			ifp = drvr->iflist[ifidx];
446
			ifp->ndev->last_rx = jiffies;
447
		}
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464

		drvr->dstats.rx_bytes += skb->len;
		drvr->rx_packets++;	/* Local count */

		if (in_interrupt())
			netif_rx(skb);
		else
			/* If the receive is not processed inside an ISR,
			 * the softirqd must be woken explicitly to service
			 * the NET_RX_SOFTIRQ.  In 2.6 kernels, this is handled
			 * by netif_rx_ni(), but in earlier kernels, we need
			 * to do it manually.
			 */
			netif_rx_ni(skb);
	}
}

465
void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
466
467
468
469
{
	uint ifidx;
	struct ethhdr *eh;
	u16 type;
470
471
	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
	struct brcmf_pub *drvr = bus_if->drvr;
472
473
474
475
476
477
478

	brcmf_proto_hdrpull(drvr, &ifidx, txp);

	eh = (struct ethhdr *)(txp->data);
	type = ntohs(eh->h_proto);

	if (type == ETH_P_PAE)
479
		atomic_dec(&drvr->pend_8021x_cnt);
480
481
482
483
484

}

static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
{
485
	struct brcmf_if *ifp = netdev_priv(ndev);
486
	struct brcmf_pub *drvr = ifp->drvr;
487
488
489

	brcmf_dbg(TRACE, "Enter\n");

490
	if (drvr->up)
491
		/* Use the protocol to get dongle stats */
492
		brcmf_proto_dstats(drvr);
493
494

	/* Copy dongle stats to net device stats */
495
496
497
498
499
500
501
502
503
	ifp->stats.rx_packets = drvr->dstats.rx_packets;
	ifp->stats.tx_packets = drvr->dstats.tx_packets;
	ifp->stats.rx_bytes = drvr->dstats.rx_bytes;
	ifp->stats.tx_bytes = drvr->dstats.tx_bytes;
	ifp->stats.rx_errors = drvr->dstats.rx_errors;
	ifp->stats.tx_errors = drvr->dstats.tx_errors;
	ifp->stats.rx_dropped = drvr->dstats.rx_dropped;
	ifp->stats.tx_dropped = drvr->dstats.tx_dropped;
	ifp->stats.multicast = drvr->dstats.multicast;
504
505
506
507
508
509

	return &ifp->stats;
}

/* Retrieve current toe component enables, which are kept
	 as a bitmap in toe_ol iovar */
510
static int brcmf_toe_get(struct brcmf_pub *drvr, int ifidx, u32 *toe_ol)
511
512
{
	struct brcmf_dcmd dcmd;
513
	__le32 toe_le;
514
515
516
517
518
519
520
521
522
523
524
	char buf[32];
	int ret;

	memset(&dcmd, 0, sizeof(dcmd));

	dcmd.cmd = BRCMF_C_GET_VAR;
	dcmd.buf = buf;
	dcmd.len = (uint) sizeof(buf);
	dcmd.set = false;

	strcpy(buf, "toe_ol");
525
	ret = brcmf_proto_dcmd(drvr, ifidx, &dcmd, dcmd.len);
526
527
528
529
	if (ret < 0) {
		/* Check for older dongle image that doesn't support toe_ol */
		if (ret == -EIO) {
			brcmf_dbg(ERROR, "%s: toe not supported by device\n",
530
				  brcmf_ifname(drvr, ifidx));
531
532
533
534
			return -EOPNOTSUPP;
		}

		brcmf_dbg(INFO, "%s: could not get toe_ol: ret=%d\n",
535
			  brcmf_ifname(drvr, ifidx), ret);
536
537
538
		return ret;
	}

539
540
	memcpy(&toe_le, buf, sizeof(u32));
	*toe_ol = le32_to_cpu(toe_le);
541
542
543
544
545
	return 0;
}

/* Set current toe component enables in toe_ol iovar,
	 and set toe global enable iovar */
546
static int brcmf_toe_set(struct brcmf_pub *drvr, int ifidx, u32 toe_ol)
547
548
549
{
	struct brcmf_dcmd dcmd;
	char buf[32];
550
551
	int ret;
	__le32 toe_le = cpu_to_le32(toe_ol);
552
553
554
555
556
557
558
559
560
561

	memset(&dcmd, 0, sizeof(dcmd));

	dcmd.cmd = BRCMF_C_SET_VAR;
	dcmd.buf = buf;
	dcmd.len = (uint) sizeof(buf);
	dcmd.set = true;

	/* Set toe_ol as requested */
	strcpy(buf, "toe_ol");
562
	memcpy(&buf[sizeof("toe_ol")], &toe_le, sizeof(u32));
563

564
	ret = brcmf_proto_dcmd(drvr, ifidx, &dcmd, dcmd.len);
565
566
	if (ret < 0) {
		brcmf_dbg(ERROR, "%s: could not set toe_ol: ret=%d\n",
567
			  brcmf_ifname(drvr, ifidx), ret);
568
569
570
571
		return ret;
	}

	/* Enable toe globally only if any components are enabled. */
572
	toe_le = cpu_to_le32(toe_ol != 0);
573
574

	strcpy(buf, "toe");
575
	memcpy(&buf[sizeof("toe")], &toe_le, sizeof(u32));
576

577
	ret = brcmf_proto_dcmd(drvr, ifidx, &dcmd, dcmd.len);
578
579
	if (ret < 0) {
		brcmf_dbg(ERROR, "%s: could not set toe: ret=%d\n",
580
			  brcmf_ifname(drvr, ifidx), ret);
581
582
583
584
585
586
587
588
589
		return ret;
	}

	return 0;
}

static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
				    struct ethtool_drvinfo *info)
{
590
	struct brcmf_if *ifp = netdev_priv(ndev);
591
	struct brcmf_pub *drvr = ifp->drvr;
592
593

	sprintf(info->driver, KBUILD_MODNAME);
594
595
	sprintf(info->version, "%lu", drvr->drv_version);
	sprintf(info->bus_info, "%s", dev_name(drvr->dev));
596
597
598
599
600
601
}

static struct ethtool_ops brcmf_ethtool_ops = {
	.get_drvinfo = brcmf_ethtool_get_drvinfo
};

602
static int brcmf_ethtool(struct brcmf_pub *drvr, void __user *uaddr)
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
{
	struct ethtool_drvinfo info;
	char drvname[sizeof(info.driver)];
	u32 cmd;
	struct ethtool_value edata;
	u32 toe_cmpnt, csum_dir;
	int ret;

	brcmf_dbg(TRACE, "Enter\n");

	/* all ethtool calls start with a cmd word */
	if (copy_from_user(&cmd, uaddr, sizeof(u32)))
		return -EFAULT;

	switch (cmd) {
	case ETHTOOL_GDRVINFO:
		/* Copy out any request driver name */
		if (copy_from_user(&info, uaddr, sizeof(info)))
			return -EFAULT;
		strncpy(drvname, info.driver, sizeof(info.driver));
		drvname[sizeof(info.driver) - 1] = '\0';

		/* clear struct for return */
		memset(&info, 0, sizeof(info));
		info.cmd = cmd;

		/* if requested, identify ourselves */
		if (strcmp(drvname, "?dhd") == 0) {
			sprintf(info.driver, "dhd");
			strcpy(info.version, BRCMF_VERSION_STR);
		}

		/* otherwise, require dongle to be up */
636
		else if (!drvr->up) {
637
638
639
640
641
			brcmf_dbg(ERROR, "dongle is not up\n");
			return -ENODEV;
		}

		/* finally, report dongle driver type */
642
		else if (drvr->iswl)
643
644
645
646
			sprintf(info.driver, "wl");
		else
			sprintf(info.driver, "xx");

647
		sprintf(info.version, "%lu", drvr->drv_version);
648
649
650
651
652
653
654
655
656
		if (copy_to_user(uaddr, &info, sizeof(info)))
			return -EFAULT;
		brcmf_dbg(CTL, "given %*s, returning %s\n",
			  (int)sizeof(drvname), drvname, info.driver);
		break;

		/* Get toe offload components from dongle */
	case ETHTOOL_GRXCSUM:
	case ETHTOOL_GTXCSUM:
657
		ret = brcmf_toe_get(drvr, 0, &toe_cmpnt);
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
		if (ret < 0)
			return ret;

		csum_dir =
		    (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;

		edata.cmd = cmd;
		edata.data = (toe_cmpnt & csum_dir) ? 1 : 0;

		if (copy_to_user(uaddr, &edata, sizeof(edata)))
			return -EFAULT;
		break;

		/* Set toe offload components in dongle */
	case ETHTOOL_SRXCSUM:
	case ETHTOOL_STXCSUM:
		if (copy_from_user(&edata, uaddr, sizeof(edata)))
			return -EFAULT;

		/* Read the current settings, update and write back */
678
		ret = brcmf_toe_get(drvr, 0, &toe_cmpnt);
679
680
681
682
683
684
685
686
687
688
689
		if (ret < 0)
			return ret;

		csum_dir =
		    (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;

		if (edata.data != 0)
			toe_cmpnt |= csum_dir;
		else
			toe_cmpnt &= ~csum_dir;

690
		ret = brcmf_toe_set(drvr, 0, toe_cmpnt);
691
692
693
694
695
696
		if (ret < 0)
			return ret;

		/* If setting TX checksum mode, tell Linux the new mode */
		if (cmd == ETHTOOL_STXCSUM) {
			if (edata.data)
697
				drvr->iflist[0]->ndev->features |=
698
699
				    NETIF_F_IP_CSUM;
			else
700
				drvr->iflist[0]->ndev->features &=
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
				    ~NETIF_F_IP_CSUM;
		}

		break;

	default:
		return -EOPNOTSUPP;
	}

	return 0;
}

static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,
				    int cmd)
{
716
	struct brcmf_if *ifp = netdev_priv(ndev);
717
	struct brcmf_pub *drvr = ifp->drvr;
718

719
	brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifp->idx, cmd);
720

721
	if (!drvr->iflist[ifp->idx])
722
723
724
		return -1;

	if (cmd == SIOCETHTOOL)
725
		return brcmf_ethtool(drvr, ifr->ifr_data);
726
727
728
729
730
731
732
733
734
735
736

	return -EOPNOTSUPP;
}

/* called only from within this driver. Sends a command to the dongle. */
s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len)
{
	struct brcmf_dcmd dcmd;
	s32 err = 0;
	int buflen = 0;
	bool is_set_key_cmd;
737
	struct brcmf_if *ifp = netdev_priv(ndev);
738
	struct brcmf_pub *drvr = ifp->drvr;
739
740
741
742
743
744
745
746
747
748

	memset(&dcmd, 0, sizeof(dcmd));
	dcmd.cmd = cmd;
	dcmd.buf = arg;
	dcmd.len = len;

	if (dcmd.buf != NULL)
		buflen = min_t(uint, dcmd.len, BRCMF_DCMD_MAXLEN);

	/* send to dongle (must be up, and wl) */
749
	if ((drvr->bus_if->state != BRCMF_BUS_DATA)) {
750
751
752
753
754
		brcmf_dbg(ERROR, "DONGLE_DOWN\n");
		err = -EIO;
		goto done;
	}

755
	if (!drvr->iswl) {
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
		err = -EIO;
		goto done;
	}

	/*
	 * Intercept BRCMF_C_SET_KEY CMD - serialize M4 send and
	 * set key CMD to prevent M4 encryption.
	 */
	is_set_key_cmd = ((dcmd.cmd == BRCMF_C_SET_KEY) ||
			  ((dcmd.cmd == BRCMF_C_SET_VAR) &&
			   !(strncmp("wsec_key", dcmd.buf, 9))) ||
			  ((dcmd.cmd == BRCMF_C_SET_VAR) &&
			   !(strncmp("bsscfg:wsec_key", dcmd.buf, 15))));
	if (is_set_key_cmd)
		brcmf_netdev_wait_pend8021x(ndev);

772
	err = brcmf_proto_dcmd(drvr, ifp->idx, &dcmd, buflen);
773
774
775
776
777
778
779
780
781
782

done:
	if (err > 0)
		err = 0;

	return err;
}

static int brcmf_netdev_stop(struct net_device *ndev)
{
783
	struct brcmf_if *ifp = netdev_priv(ndev);
784
	struct brcmf_pub *drvr = ifp->drvr;
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799

	brcmf_dbg(TRACE, "Enter\n");
	brcmf_cfg80211_down(drvr->config);
	if (drvr->up == 0)
		return 0;

	/* Set state and stop OS transmissions */
	drvr->up = 0;
	netif_stop_queue(ndev);

	return 0;
}

static int brcmf_netdev_open(struct net_device *ndev)
{
800
	struct brcmf_if *ifp = netdev_priv(ndev);
801
	struct brcmf_pub *drvr = ifp->drvr;
802
803
804
	u32 toe_ol;
	s32 ret = 0;

805
	brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx);
806

807
	if (ifp->idx == 0) {	/* do it only for primary eth0 */
808
		/* try to bring up bus */
809
		ret = brcmf_bus_start(drvr->dev);
810
811
812
813
		if (ret != 0) {
			brcmf_dbg(ERROR, "failed with code %d\n", ret);
			return -1;
		}
814
		atomic_set(&drvr->pend_8021x_cnt, 0);
815

816
		memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN);
817
818

		/* Get current TOE mode from dongle */
819
		if (brcmf_toe_get(drvr, ifp->idx, &toe_ol) >= 0
820
		    && (toe_ol & TOE_TX_CSUM_OL) != 0)
821
			drvr->iflist[ifp->idx]->ndev->features |=
822
823
				NETIF_F_IP_CSUM;
		else
824
			drvr->iflist[ifp->idx]->ndev->features &=
825
826
827
828
				~NETIF_F_IP_CSUM;
	}
	/* Allow transmit calls */
	netif_start_queue(ndev);
829
830
	drvr->up = 1;
	if (brcmf_cfg80211_up(drvr->config)) {
831
832
833
834
835
836
837
		brcmf_dbg(ERROR, "failed to bring up cfg80211\n");
		return -1;
	}

	return ret;
}

838
839
840
841
842
843
844
845
846
847
static const struct net_device_ops brcmf_netdev_ops_pri = {
	.ndo_open = brcmf_netdev_open,
	.ndo_stop = brcmf_netdev_stop,
	.ndo_get_stats = brcmf_netdev_get_stats,
	.ndo_do_ioctl = brcmf_netdev_ioctl_entry,
	.ndo_start_xmit = brcmf_netdev_start_xmit,
	.ndo_set_mac_address = brcmf_netdev_set_mac_address,
	.ndo_set_rx_mode = brcmf_netdev_set_multicast_list
};

848
int
849
brcmf_add_if(struct device *dev, int ifidx, char *name, u8 *mac_addr)
850
851
{
	struct brcmf_if *ifp;
852
	struct net_device *ndev;
853
854
	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
	struct brcmf_pub *drvr = bus_if->drvr;
855

856
	brcmf_dbg(TRACE, "idx %d\n", ifidx);
857

858
	ifp = drvr->iflist[ifidx];
859
860
861
862
863
864
865
866
867
868
	/*
	 * Delete the existing interface before overwriting it
	 * in case we missed the BRCMF_E_IF_DEL event.
	 */
	if (ifp) {
		brcmf_dbg(ERROR, "ERROR: netdev:%s already exists, try free & unregister\n",
			  ifp->ndev->name);
		netif_stop_queue(ifp->ndev);
		unregister_netdev(ifp->ndev);
		free_netdev(ifp->ndev);
869
		drvr->iflist[ifidx] = NULL;
870
	}
871

872
	/* Allocate netdev, including space for private structure */
873
874
	ndev = alloc_netdev(sizeof(struct brcmf_if), name, ether_setup);
	if (!ndev) {
875
		brcmf_dbg(ERROR, "OOM - alloc_netdev\n");
876
		return -ENOMEM;
877
	}
878

879
880
	ifp = netdev_priv(ndev);
	ifp->ndev = ndev;
881
882
	ifp->drvr = drvr;
	drvr->iflist[ifidx] = ifp;
883
	ifp->idx = ifidx;
884
885
	if (mac_addr != NULL)
		memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN);
886

887
	if (brcmf_net_attach(drvr, ifp->idx)) {
888
889
		brcmf_dbg(ERROR, "brcmf_net_attach failed");
		free_netdev(ifp->ndev);
890
		drvr->iflist[ifidx] = NULL;
891
		return -EOPNOTSUPP;
892
	}
893

894
895
	brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n",
		  current->pid, ifp->ndev->name);
896
897
898
899

	return 0;
}

900
void brcmf_del_if(struct brcmf_pub *drvr, int ifidx)
901
902
903
904
905
{
	struct brcmf_if *ifp;

	brcmf_dbg(TRACE, "idx %d\n", ifidx);

906
	ifp = drvr->iflist[ifidx];
907
908
909
910
	if (!ifp) {
		brcmf_dbg(ERROR, "Null interface\n");
		return;
	}
911
912
913
914
915
916
917
918
919
920
921
	if (ifp->ndev) {
		if (ifidx == 0) {
			if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
				rtnl_lock();
				brcmf_netdev_stop(ifp->ndev);
				rtnl_unlock();
			}
		} else {
			netif_stop_queue(ifp->ndev);
		}

922
		unregister_netdev(ifp->ndev);
923
		drvr->iflist[ifidx] = NULL;
924
		if (ifidx == 0)
925
			brcmf_cfg80211_detach(drvr->config);
926
		free_netdev(ifp->ndev);
927
928
929
	}
}

930
931
struct brcmf_pub *brcmf_attach(struct brcmf_sdio *bus, uint bus_hdrlen,
			       struct device *dev)
932
{
933
	struct brcmf_pub *drvr = NULL;
934
935
936
937

	brcmf_dbg(TRACE, "Enter\n");

	/* Allocate primary brcmf_info */
938
939
	drvr = kzalloc(sizeof(struct brcmf_pub), GFP_ATOMIC);
	if (!drvr)
940
941
		goto fail;

942
	mutex_init(&drvr->proto_block);
943
944

	/* Link to bus module */
945
946
947
	drvr->bus = bus;
	drvr->hdrlen = bus_hdrlen;
	drvr->bus_if = dev_get_drvdata(dev);
948
	drvr->bus_if->drvr = drvr;
949
	drvr->dev = dev;
950
951

	/* Attach and link in the protocol */
952
	if (brcmf_proto_attach(drvr) != 0) {
953
954
955
956
		brcmf_dbg(ERROR, "brcmf_prot_attach failed\n");
		goto fail;
	}

957
958
	INIT_WORK(&drvr->setmacaddr_work, _brcmf_set_mac_address);
	INIT_WORK(&drvr->multicast_work, _brcmf_set_multicast_list);
959

960
	return drvr;
961
962

fail:
963
	if (drvr)
964
		brcmf_detach(dev);
965
966
967
968

	return NULL;
}

969
int brcmf_bus_start(struct device *dev)
970
971
972
973
{
	int ret = -1;
	/* Room for "event_msgs" + '\0' + bitvec */
	char iovbuf[BRCMF_EVENTING_MASK_LEN + 12];
974
975
	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
	struct brcmf_pub *drvr = bus_if->drvr;
976
977
978
979

	brcmf_dbg(TRACE, "\n");

	/* Bring up the bus */
980
	ret = brcmf_sdbrcm_bus_init(dev);
981
982
983
984
985
986
	if (ret != 0) {
		brcmf_dbg(ERROR, "brcmf_sdbrcm_bus_init failed %d\n", ret);
		return ret;
	}

	/* If bus is not ready, can't come up */
987
	if (bus_if->state != BRCMF_BUS_DATA) {
988
989
990
991
		brcmf_dbg(ERROR, "failed bus is not ready\n");
		return -ENODEV;
	}

992
	brcmf_c_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN,
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
		      iovbuf, sizeof(iovbuf));
	brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, iovbuf,
				    sizeof(iovbuf));
	memcpy(drvr->eventmask, iovbuf, BRCMF_EVENTING_MASK_LEN);

	setbit(drvr->eventmask, BRCMF_E_SET_SSID);
	setbit(drvr->eventmask, BRCMF_E_PRUNE);
	setbit(drvr->eventmask, BRCMF_E_AUTH);
	setbit(drvr->eventmask, BRCMF_E_REASSOC);
	setbit(drvr->eventmask, BRCMF_E_REASSOC_IND);
	setbit(drvr->eventmask, BRCMF_E_DEAUTH_IND);
	setbit(drvr->eventmask, BRCMF_E_DISASSOC_IND);
	setbit(drvr->eventmask, BRCMF_E_DISASSOC);
	setbit(drvr->eventmask, BRCMF_E_JOIN);
	setbit(drvr->eventmask, BRCMF_E_ASSOC_IND);
	setbit(drvr->eventmask, BRCMF_E_PSK_SUP);
	setbit(drvr->eventmask, BRCMF_E_LINK);
	setbit(drvr->eventmask, BRCMF_E_NDIS_LINK);
	setbit(drvr->eventmask, BRCMF_E_MIC_ERROR);
	setbit(drvr->eventmask, BRCMF_E_PMKID_CACHE);
	setbit(drvr->eventmask, BRCMF_E_TXFAIL);
	setbit(drvr->eventmask, BRCMF_E_JOIN_START);
	setbit(drvr->eventmask, BRCMF_E_SCAN_COMPLETE);

/* enable dongle roaming event */

	drvr->pktfilter_count = 1;
	/* Setup filter to allow only unicast */
	drvr->pktfilter[0] = "100 0 0 0 0x01 0x00";

	/* Bus is ready, do any protocol initialization */
1024
	ret = brcmf_proto_init(drvr);
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
	if (ret < 0)
		return ret;

	return 0;
}

int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx)
{
	struct net_device *ndev;
	u8 temp_addr[ETH_ALEN] = {
		0x00, 0x90, 0x4c, 0x11, 0x22, 0x33};

	brcmf_dbg(TRACE, "ifidx %d\n", ifidx);

1039
	ndev = drvr->iflist[ifidx]->ndev;
1040
1041
1042
1043
1044
1045
1046
	ndev->netdev_ops = &brcmf_netdev_ops_pri;

	/*
	 * We have to use the primary MAC for virtual interfaces
	 */
	if (ifidx != 0) {
		/* for virtual interfaces use the primary MAC  */
1047
		memcpy(temp_addr, drvr->mac, ETH_ALEN);
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057

	}

	if (ifidx == 1) {
		brcmf_dbg(TRACE, "ACCESS POINT MAC:\n");
		/*  ACCESSPOINT INTERFACE CASE */
		temp_addr[0] |= 0X02;	/* set bit 2 ,
			 - Locally Administered address  */

	}
1058
	ndev->hard_header_len = ETH_HLEN + drvr->hdrlen;
1059
1060
	ndev->ethtool_ops = &brcmf_ethtool_ops;

1061
1062
	drvr->rxsz = ndev->mtu + ndev->hard_header_len +
			      drvr->hdrlen;
1063
1064
1065

	memcpy(ndev->dev_addr, temp_addr, ETH_ALEN);

1066
1067
	/* attach to cfg80211 for primary interface */
	if (!ifidx) {
1068
		drvr->config = brcmf_cfg80211_attach(ndev, drvr->dev, drvr);
1069
1070
1071
1072
1073
1074
		if (drvr->config == NULL) {
			brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n");
			goto fail;
		}
	}

1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
	if (register_netdev(ndev) != 0) {
		brcmf_dbg(ERROR, "couldn't register the net device\n");
		goto fail;
	}

	brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);

	return 0;

fail:
	ndev->netdev_ops = NULL;
	return -EBADE;
}

static void brcmf_bus_detach(struct brcmf_pub *drvr)
{
	brcmf_dbg(TRACE, "Enter\n");

	if (drvr) {
1094
1095
		/* Stop the protocol module */
		brcmf_proto_stop(drvr);
1096

1097
1098
		/* Stop the bus module */
		brcmf_sdbrcm_bus_stop(drvr->dev);
1099
1100
1101
	}
}

1102
void brcmf_detach(struct device *dev)
1103
{
1104
1105
1106
1107
	int i;
	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
	struct brcmf_pub *drvr = bus_if->drvr;

1108
1109
1110
	brcmf_dbg(TRACE, "Enter\n");


1111
1112
1113
1114
	/* make sure primary interface removed last */
	for (i = BRCMF_MAX_IFS-1; i > -1; i--)
		if (drvr->iflist[i])
			brcmf_del_if(drvr, i);
1115

1116
1117
	cancel_work_sync(&drvr->setmacaddr_work);
	cancel_work_sync(&drvr->multicast_work);
1118

1119
	brcmf_bus_detach(drvr);
1120

1121
1122
	if (drvr->prot)
		brcmf_proto_detach(drvr);
1123

1124
1125
	bus_if->drvr = NULL;
	kfree(drvr);
1126
1127
}

1128
static int brcmf_get_pend_8021x_cnt(struct brcmf_pub *drvr)
1129
{
1130
	return atomic_read(&drvr->pend_8021x_cnt);
1131
1132
1133
1134
1135
1136
}

#define MAX_WAIT_FOR_8021X_TX	10

int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
{
1137
	struct brcmf_if *ifp = netdev_priv(ndev);
1138
	struct brcmf_pub *drvr = ifp->drvr;
1139
1140
	int timeout = 10 * HZ / 1000;
	int ntimes = MAX_WAIT_FOR_8021X_TX;
1141
	int pend = brcmf_get_pend_8021x_cnt(drvr);
1142
1143
1144
1145
1146
1147
1148
1149

	while (ntimes && pend) {
		if (pend) {
			set_current_state(TASK_INTERRUPTIBLE);
			schedule_timeout(timeout);
			set_current_state(TASK_RUNNING);
			ntimes--;
		}
1150
		pend = brcmf_get_pend_8021x_cnt(drvr);
1151
1152
1153
1154
1155
	}
	return pend;
}

#ifdef BCMDBG
1156
int brcmf_write_to_file(struct brcmf_pub *drvr, const u8 *buf, int size)
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
{
	int ret = 0;
	struct file *fp;
	mm_segment_t old_fs;
	loff_t pos = 0;

	/* change to KERNEL_DS address limit */
	old_fs = get_fs();
	set_fs(KERNEL_DS);

	/* open file to write */
	fp = filp_open("/tmp/mem_dump", O_WRONLY | O_CREAT, 0640);
	if (!fp) {
		brcmf_dbg(ERROR, "open file error\n");
		ret = -1;
		goto exit;
	}

	/* Write buf to file */
1176
	fp->f_op->write(fp, (char __user *)buf, size, &pos);
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189

exit:
	/* free buf before return */
	kfree(buf);
	/* close file before return */
	if (fp)
		filp_close(fp, current->files);
	/* restore previous address limit */
	set_fs(old_fs);

	return ret;
}
#endif				/* BCMDBG */