dhd_linux.c 22.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * 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/kernel.h>
#include <linux/etherdevice.h>
19
#include <linux/module.h>
20 21 22 23 24 25 26 27 28 29
#include <net/cfg80211.h>
#include <net/rtnetlink.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"
30
#include "fwil.h"
31 32

MODULE_AUTHOR("Broadcom Corporation");
H
Hante Meuleman 已提交
33 34
MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
MODULE_SUPPORTED_DEVICE("Broadcom 802.11 WLAN fullmac cards");
35 36
MODULE_LICENSE("Dual BSD/GPL");

37
#define MAX_WAIT_FOR_8021X_TX		50	/* msecs */
38 39

/* Error bits */
40
int brcmf_msg_level;
41 42 43 44 45 46
module_param(brcmf_msg_level, int, 0);


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

51
	if (drvr->iflist[ifidx] == NULL) {
52
		brcmf_err("null i/f %d\n", ifidx);
53 54 55
		return "<if_null>";
	}

56 57
	if (drvr->iflist[ifidx]->ndev)
		return drvr->iflist[ifidx]->ndev->name;
58 59 60 61 62 63

	return "<if_none>";
}

static void _brcmf_set_multicast_list(struct work_struct *work)
{
64
	struct brcmf_if *ifp;
65 66
	struct net_device *ndev;
	struct netdev_hw_addr *ha;
67
	u32 cmd_value, cnt;
68 69
	__le32 cnt_le;
	char *buf, *bufp;
70 71
	u32 buflen;
	s32 err;
72

73 74
	brcmf_dbg(TRACE, "enter\n");

75
	ifp = container_of(work, struct brcmf_if, multicast_work);
76
	ndev = ifp->ndev;
77 78

	/* Determine initial value of allmulti flag */
79
	cmd_value = (ndev->flags & IFF_ALLMULTI) ? true : false;
80 81

	/* Send down the multicast list first. */
82 83 84 85
	cnt = netdev_mc_count(ndev);
	buflen = sizeof(cnt) + (cnt * ETH_ALEN);
	buf = kmalloc(buflen, GFP_ATOMIC);
	if (!buf)
86
		return;
87
	bufp = buf;
88 89

	cnt_le = cpu_to_le32(cnt);
90
	memcpy(bufp, &cnt_le, sizeof(cnt_le));
91 92 93 94 95 96 97 98 99 100
	bufp += sizeof(cnt_le);

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

101 102
	err = brcmf_fil_iovar_data_set(ifp, "mcast_list", buf, buflen);
	if (err < 0) {
103
		brcmf_err("Setting mcast_list failed, %d\n", err);
104
		cmd_value = cnt ? true : cmd_value;
105 106 107 108
	}

	kfree(buf);

109 110
	/*
	 * Now send the allmulti setting.  This is based on the setting in the
111 112 113
	 * net_device flags, but might be modified above to be turned on if we
	 * were trying to set some addresses and dongle rejected it...
	 */
114 115
	err = brcmf_fil_iovar_int_set(ifp, "allmulti", cmd_value);
	if (err < 0)
116
		brcmf_err("Setting allmulti failed, %d\n", err);
117 118 119 120 121

	/*Finally, pick up the PROMISC flag */
	cmd_value = (ndev->flags & IFF_PROMISC) ? true : false;
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PROMISC, cmd_value);
	if (err < 0)
122
		brcmf_err("Setting BRCMF_C_SET_PROMISC failed, %d\n",
123
			  err);
124 125 126 127 128
}

static void
_brcmf_set_mac_address(struct work_struct *work)
{
129 130
	struct brcmf_if *ifp;
	s32 err;
131 132 133

	brcmf_dbg(TRACE, "enter\n");

134 135
	ifp = container_of(work, struct brcmf_if, setmacaddr_work);
	err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr,
136 137
				       ETH_ALEN);
	if (err < 0) {
138
		brcmf_err("Setting cur_etheraddr failed, %d\n", err);
139 140
	} else {
		brcmf_dbg(TRACE, "MAC address updated to %pM\n",
141 142
			  ifp->mac_addr);
		memcpy(ifp->ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
143
	}
144 145 146 147
}

static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
{
148
	struct brcmf_if *ifp = netdev_priv(ndev);
149 150
	struct sockaddr *sa = (struct sockaddr *)addr;

151 152
	memcpy(&ifp->mac_addr, sa->sa_data, ETH_ALEN);
	schedule_work(&ifp->setmacaddr_work);
153 154 155 156 157
	return 0;
}

static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
{
158
	struct brcmf_if *ifp = netdev_priv(ndev);
159

160
	schedule_work(&ifp->multicast_work);
161 162 163 164 165
}

static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
	int ret;
166
	struct brcmf_if *ifp = netdev_priv(ndev);
167
	struct brcmf_pub *drvr = ifp->drvr;
168 169 170 171

	brcmf_dbg(TRACE, "Enter\n");

	/* Reject if down */
172
	if (!drvr->bus_if->drvr_up ||
173
	    (drvr->bus_if->state != BRCMF_BUS_DATA)) {
174
		brcmf_err("xmit rejected drvup=%d state=%d\n",
175
			  drvr->bus_if->drvr_up,
176
			  drvr->bus_if->state);
177 178 179 180
		netif_stop_queue(ndev);
		return -ENODEV;
	}

181
	if (!drvr->iflist[ifp->idx]) {
182
		brcmf_err("bad ifidx %d\n", ifp->idx);
183 184 185 186 187
		netif_stop_queue(ndev);
		return -ENODEV;
	}

	/* Make sure there's enough room for any header */
188
	if (skb_headroom(skb) < drvr->hdrlen) {
189 190 191
		struct sk_buff *skb2;

		brcmf_dbg(INFO, "%s: insufficient headroom\n",
192
			  brcmf_ifname(drvr, ifp->idx));
193
		drvr->bus_if->tx_realloc++;
194
		skb2 = skb_realloc_headroom(skb, drvr->hdrlen);
195 196 197
		dev_kfree_skb(skb);
		skb = skb2;
		if (skb == NULL) {
198
			brcmf_err("%s: skb_realloc_headroom failed\n",
199
				  brcmf_ifname(drvr, ifp->idx));
200 201 202 203 204
			ret = -ENOMEM;
			goto done;
		}
	}

205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
	/* Update multicast statistic */
	if (skb->len >= ETH_ALEN) {
		u8 *pktdata = (u8 *)(skb->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)
			atomic_inc(&drvr->pend_8021x_cnt);
	}

	/* If the protocol uses a data header, apply it */
	brcmf_proto_hdrpush(drvr, ifp->idx, skb);

	/* Use bus module to send data frame */
A
Arend van Spriel 已提交
220
	ret =  brcmf_bus_txdata(drvr->bus_if, skb);
221 222 223

done:
	if (ret)
224
		drvr->bus_if->dstats.tx_dropped++;
225
	else
226
		drvr->bus_if->dstats.tx_packets++;
227 228 229 230 231

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

232
void brcmf_txflowblock(struct device *dev, bool state)
233 234
{
	struct net_device *ndev;
235 236
	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
	struct brcmf_pub *drvr = bus_if->drvr;
237
	int i;
238 239 240

	brcmf_dbg(TRACE, "Enter\n");

241 242 243 244 245 246 247 248
	for (i = 0; i < BRCMF_MAX_IFS; i++)
		if (drvr->iflist[i]) {
			ndev = drvr->iflist[i]->ndev;
			if (state)
				netif_stop_queue(ndev);
			else
				netif_wake_queue(ndev);
		}
249 250
}

251
void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
252 253 254
{
	unsigned char *eth;
	uint len;
255
	struct sk_buff *skb, *pnext;
256
	struct brcmf_if *ifp;
257 258
	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
	struct brcmf_pub *drvr = bus_if->drvr;
259 260
	u8 ifidx;
	int ret;
261 262 263

	brcmf_dbg(TRACE, "Enter\n");

264 265
	skb_queue_walk_safe(skb_list, skb, pnext) {
		skb_unlink(skb, skb_list);
266

267 268 269 270 271 272 273 274 275 276
		/* process and remove protocol-specific header
		 */
		ret = brcmf_proto_hdrpull(drvr, &ifidx, skb);
		if (ret < 0) {
			if (ret != -ENODATA)
				bus_if->dstats.rx_errors++;
			brcmu_pkt_buf_free_skb(skb);
			continue;
		}

277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
		/* 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;

292
		ifp = drvr->iflist[ifidx];
293
		if (ifp == NULL)
294
			ifp = drvr->iflist[0];
295

296 297 298 299 300 301
		if (!ifp || !ifp->ndev ||
		    ifp->ndev->reg_state != NETREG_REGISTERED) {
			brcmu_pkt_buf_free_skb(skb);
			continue;
		}

302 303 304 305
		skb->dev = ifp->ndev;
		skb->protocol = eth_type_trans(skb, skb->dev);

		if (skb->pkt_type == PACKET_MULTICAST)
306
			bus_if->dstats.multicast++;
307 308 309 310 311 312 313 314

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

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

		/* Process special event packets and then discard them */
315
		brcmf_fweh_process_skb(drvr, skb, &ifidx);
316

317 318
		if (drvr->iflist[ifidx]) {
			ifp = drvr->iflist[ifidx];
319
			ifp->ndev->last_rx = jiffies;
320
		}
321

322 323
		bus_if->dstats.rx_bytes += skb->len;
		bus_if->dstats.rx_packets++;	/* Local count */
324 325 326 327 328 329 330 331 332 333 334 335 336 337

		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);
	}
}

338
void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
339
{
340
	u8 ifidx;
341 342
	struct ethhdr *eh;
	u16 type;
343 344
	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
	struct brcmf_pub *drvr = bus_if->drvr;
345

346
	brcmf_proto_hdrpull(drvr, &ifidx, txp);
347 348 349 350

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

351
	if (type == ETH_P_PAE) {
352
		atomic_dec(&drvr->pend_8021x_cnt);
353 354 355
		if (waitqueue_active(&drvr->pend_8021x_wait))
			wake_up(&drvr->pend_8021x_wait);
	}
356 357 358 359
}

static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
{
360
	struct brcmf_if *ifp = netdev_priv(ndev);
361
	struct brcmf_bus *bus_if = ifp->drvr->bus_if;
362 363 364 365

	brcmf_dbg(TRACE, "Enter\n");

	/* Copy dongle stats to net device stats */
366 367 368 369 370 371 372 373 374
	ifp->stats.rx_packets = bus_if->dstats.rx_packets;
	ifp->stats.tx_packets = bus_if->dstats.tx_packets;
	ifp->stats.rx_bytes = bus_if->dstats.rx_bytes;
	ifp->stats.tx_bytes = bus_if->dstats.tx_bytes;
	ifp->stats.rx_errors = bus_if->dstats.rx_errors;
	ifp->stats.tx_errors = bus_if->dstats.tx_errors;
	ifp->stats.rx_dropped = bus_if->dstats.rx_dropped;
	ifp->stats.tx_dropped = bus_if->dstats.tx_dropped;
	ifp->stats.multicast = bus_if->dstats.multicast;
375 376 377 378

	return &ifp->stats;
}

379 380 381 382 383
/*
 * Set current toe component enables in toe_ol iovar,
 * and set toe global enable iovar
 */
static int brcmf_toe_set(struct brcmf_if *ifp, u32 toe_ol)
384
{
385
	s32 err;
386

387 388
	err = brcmf_fil_iovar_int_set(ifp, "toe_ol", toe_ol);
	if (err < 0) {
389
		brcmf_err("Setting toe_ol failed, %d\n", err);
390
		return err;
391 392
	}

393 394
	err = brcmf_fil_iovar_int_set(ifp, "toe", (toe_ol != 0));
	if (err < 0)
395
		brcmf_err("Setting toe failed, %d\n", err);
396

397
	return err;
398 399 400 401 402 403

}

static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
				    struct ethtool_drvinfo *info)
{
404
	struct brcmf_if *ifp = netdev_priv(ndev);
405
	struct brcmf_pub *drvr = ifp->drvr;
406 407

	sprintf(info->driver, KBUILD_MODNAME);
408
	sprintf(info->version, "%lu", drvr->drv_version);
A
Arend van Spriel 已提交
409
	sprintf(info->bus_info, "%s", dev_name(drvr->bus_if->dev));
410 411
}

412 413
static const struct ethtool_ops brcmf_ethtool_ops = {
	.get_drvinfo = brcmf_ethtool_get_drvinfo,
414 415
};

416
static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr)
417
{
418
	struct brcmf_pub *drvr = ifp->drvr;
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
	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 */
451
		else if (!drvr->bus_if->drvr_up) {
452
			brcmf_err("dongle is not up\n");
453 454 455 456
			return -ENODEV;
		}
		/* finally, report dongle driver type */
		else
457
			sprintf(info.driver, "wl");
458

459
		sprintf(info.version, "%lu", drvr->drv_version);
460 461 462 463 464 465 466 467 468
		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:
469
		ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt);
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
		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 */
490
		ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt);
491 492 493 494 495 496 497 498 499 500 501
		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;

502
		ret = brcmf_toe_set(ifp, toe_cmpnt);
503 504 505 506 507 508
		if (ret < 0)
			return ret;

		/* If setting TX checksum mode, tell Linux the new mode */
		if (cmd == ETHTOOL_STXCSUM) {
			if (edata.data)
509
				ifp->ndev->features |= NETIF_F_IP_CSUM;
510
			else
511
				ifp->ndev->features &= ~NETIF_F_IP_CSUM;
512 513 514 515 516 517 518 519 520 521 522 523 524 525
		}

		break;

	default:
		return -EOPNOTSUPP;
	}

	return 0;
}

static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,
				    int cmd)
{
526
	struct brcmf_if *ifp = netdev_priv(ndev);
527
	struct brcmf_pub *drvr = ifp->drvr;
528

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

531
	if (!drvr->iflist[ifp->idx])
532 533 534
		return -1;

	if (cmd == SIOCETHTOOL)
535
		return brcmf_ethtool(ifp, ifr->ifr_data);
536 537 538 539 540 541

	return -EOPNOTSUPP;
}

static int brcmf_netdev_stop(struct net_device *ndev)
{
542
	struct brcmf_if *ifp = netdev_priv(ndev);
543
	struct brcmf_pub *drvr = ifp->drvr;
544 545

	brcmf_dbg(TRACE, "Enter\n");
546

547
	if (drvr->bus_if->drvr_up == 0)
548 549
		return 0;

550
	brcmf_cfg80211_down(ndev);
551

552
	/* Set state and stop OS transmissions */
J
John W. Linville 已提交
553
	drvr->bus_if->drvr_up = false;
554 555 556 557 558 559 560
	netif_stop_queue(ndev);

	return 0;
}

static int brcmf_netdev_open(struct net_device *ndev)
{
561
	struct brcmf_if *ifp = netdev_priv(ndev);
562
	struct brcmf_pub *drvr = ifp->drvr;
563
	struct brcmf_bus *bus_if = drvr->bus_if;
564 565 566
	u32 toe_ol;
	s32 ret = 0;

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

569 570
	/* If bus is not ready, can't continue */
	if (bus_if->state != BRCMF_BUS_DATA) {
571
		brcmf_err("failed bus is not ready\n");
572 573
		return -EAGAIN;
	}
574

575
	atomic_set(&drvr->pend_8021x_cnt, 0);
576

577
	memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN);
578

579 580 581 582 583 584 585 586
	/* Get current TOE mode from dongle */
	if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0
	    && (toe_ol & TOE_TX_CSUM_OL) != 0)
		drvr->iflist[ifp->idx]->ndev->features |=
			NETIF_F_IP_CSUM;
	else
		drvr->iflist[ifp->idx]->ndev->features &=
			~NETIF_F_IP_CSUM;
587 588

	/* make sure RF is ready for work */
589
	brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
590

591 592
	/* Allow transmit calls */
	netif_start_queue(ndev);
J
John W. Linville 已提交
593
	drvr->bus_if->drvr_up = true;
594
	if (brcmf_cfg80211_up(ndev)) {
595
		brcmf_err("failed to bring up cfg80211\n");
596 597 598 599 600 601
		return -1;
	}

	return ret;
}

602 603 604 605 606 607 608 609 610 611
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
};

612 613 614 615 616 617 618 619 620 621
static const struct net_device_ops brcmf_netdev_ops_virt = {
	.ndo_open = brcmf_cfg80211_up,
	.ndo_stop = brcmf_cfg80211_down,
	.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
};

622
int brcmf_net_attach(struct brcmf_if *ifp)
623
{
624
	struct brcmf_pub *drvr = ifp->drvr;
625 626
	struct net_device *ndev;

627 628
	brcmf_dbg(TRACE, "ifidx %d mac %pM\n", ifp->idx, ifp->mac_addr);
	ndev = ifp->ndev;
629

630 631 632 633 634
	/* set appropriate operations */
	if (!ifp->idx)
		ndev->netdev_ops = &brcmf_netdev_ops_pri;
	else
		ndev->netdev_ops = &brcmf_netdev_ops_virt;
635 636 637 638 639 640 641

	ndev->hard_header_len = ETH_HLEN + drvr->hdrlen;
	ndev->ethtool_ops = &brcmf_ethtool_ops;

	drvr->rxsz = ndev->mtu + ndev->hard_header_len +
			      drvr->hdrlen;

642 643
	/* set the mac address */
	memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
644 645

	if (register_netdev(ndev) != 0) {
646
		brcmf_err("couldn't register the net device\n");
647 648 649 650 651 652 653 654 655 656 657 658
		goto fail;
	}

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

	return 0;

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

659
struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx,
660
			      char *name, u8 *addr_mask)
661 662
{
	struct brcmf_if *ifp;
663
	struct net_device *ndev;
664
	int i;
665

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

668
	ifp = drvr->iflist[ifidx];
669 670 671 672 673
	/*
	 * Delete the existing interface before overwriting it
	 * in case we missed the BRCMF_E_IF_DEL event.
	 */
	if (ifp) {
674
		brcmf_err("ERROR: netdev:%s already exists\n",
675
			  ifp->ndev->name);
676 677 678 679 680 681
		if (ifidx) {
			netif_stop_queue(ifp->ndev);
			unregister_netdev(ifp->ndev);
			free_netdev(ifp->ndev);
			drvr->iflist[ifidx] = NULL;
		} else {
682
			brcmf_err("ignore IF event\n");
683 684
			return ERR_PTR(-EINVAL);
		}
685
	}
686

687
	/* Allocate netdev, including space for private structure */
688 689
	ndev = alloc_netdev(sizeof(struct brcmf_if), name, ether_setup);
	if (!ndev) {
690
		brcmf_err("OOM - alloc_netdev\n");
691
		return ERR_PTR(-ENOMEM);
692
	}
693

694 695
	ifp = netdev_priv(ndev);
	ifp->ndev = ndev;
696 697
	ifp->drvr = drvr;
	drvr->iflist[ifidx] = ifp;
698
	ifp->idx = ifidx;
699
	ifp->bssidx = bssidx;
700 701 702 703

	INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address);
	INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);

704 705 706
	if (addr_mask != NULL)
		for (i = 0; i < ETH_ALEN; i++)
			ifp->mac_addr[i] = drvr->mac[i] ^ addr_mask[i];
707

708 709
	brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n",
		  current->pid, ifp->ndev->name, ifp->mac_addr);
710

711
	return ifp;
712 713
}

714
void brcmf_del_if(struct brcmf_pub *drvr, int ifidx)
715 716 717 718 719
{
	struct brcmf_if *ifp;

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

720
	ifp = drvr->iflist[ifidx];
721
	if (!ifp) {
722
		brcmf_err("Null interface\n");
723 724
		return;
	}
725 726 727 728 729 730 731 732 733 734 735
	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);
		}

736 737 738
		cancel_work_sync(&ifp->setmacaddr_work);
		cancel_work_sync(&ifp->multicast_work);

739
		unregister_netdev(ifp->ndev);
740
		drvr->iflist[ifidx] = NULL;
741
		if (ifidx == 0)
742
			brcmf_cfg80211_detach(drvr->config);
743
		free_netdev(ifp->ndev);
744 745 746
	}
}

747
int brcmf_attach(uint bus_hdrlen, struct device *dev)
748
{
749
	struct brcmf_pub *drvr = NULL;
750
	int ret = 0;
751 752 753 754

	brcmf_dbg(TRACE, "Enter\n");

	/* Allocate primary brcmf_info */
755 756
	drvr = kzalloc(sizeof(struct brcmf_pub), GFP_ATOMIC);
	if (!drvr)
757
		return -ENOMEM;
758

759
	mutex_init(&drvr->proto_block);
760 761

	/* Link to bus module */
762 763
	drvr->hdrlen = bus_hdrlen;
	drvr->bus_if = dev_get_drvdata(dev);
764
	drvr->bus_if->drvr = drvr;
765

766 767 768
	/* create device debugfs folder */
	brcmf_debugfs_attach(drvr);

769
	/* Attach and link in the protocol */
770 771
	ret = brcmf_proto_attach(drvr);
	if (ret != 0) {
772
		brcmf_err("brcmf_prot_attach failed\n");
773 774 775
		goto fail;
	}

776 777 778
	/* attach firmware event handler */
	brcmf_fweh_attach(drvr);

779 780
	INIT_LIST_HEAD(&drvr->bus_if->dcmd_list);

781 782
	init_waitqueue_head(&drvr->pend_8021x_wait);

783
	return ret;
784 785

fail:
786
	brcmf_detach(dev);
787

788
	return ret;
789 790
}

791
int brcmf_bus_start(struct device *dev)
792 793
{
	int ret = -1;
794 795
	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
	struct brcmf_pub *drvr = bus_if->drvr;
796
	struct brcmf_if *ifp;
797 798 799 800

	brcmf_dbg(TRACE, "\n");

	/* Bring up the bus */
A
Arend van Spriel 已提交
801
	ret = brcmf_bus_init(bus_if);
802
	if (ret != 0) {
803
		brcmf_err("brcmf_sdbrcm_bus_init failed %d\n", ret);
804 805 806
		return ret;
	}

807
	/* add primary networking interface */
808
	ifp = brcmf_add_if(drvr, 0, 0, "wlan%d", NULL);
809 810 811
	if (IS_ERR(ifp))
		return PTR_ERR(ifp);

812 813 814 815 816
	/* signal bus ready */
	bus_if->state = BRCMF_BUS_DATA;

	/* Bus is ready, do any initialization */
	ret = brcmf_c_preinit_dcmds(ifp);
817
	if (ret < 0)
818
		goto fail;
819

A
Arend van Spriel 已提交
820
	drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev);
821 822 823 824
	if (drvr->config == NULL) {
		ret = -ENOMEM;
		goto fail;
	}
825

826 827 828 829
	ret = brcmf_fweh_activate_events(ifp);
	if (ret < 0)
		goto fail;

830
	ret = brcmf_net_attach(ifp);
831
fail:
832
	if (ret < 0) {
833
		brcmf_err("failed: %d\n", ret);
834 835 836
		if (drvr->config)
			brcmf_cfg80211_detach(drvr->config);
		free_netdev(drvr->iflist[0]->ndev);
837
		drvr->iflist[0] = NULL;
838
		return ret;
839 840
	}

841 842 843 844 845 846 847 848
	return 0;
}

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

	if (drvr) {
849 850
		/* Stop the protocol module */
		brcmf_proto_stop(drvr);
851

852
		/* Stop the bus module */
A
Arend van Spriel 已提交
853
		brcmf_bus_stop(drvr->bus_if);
854 855 856
	}
}

857 858 859 860 861 862 863 864 865 866 867
void brcmf_dev_reset(struct device *dev)
{
	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
	struct brcmf_pub *drvr = bus_if->drvr;

	if (drvr == NULL)
		return;

	brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1);
}

868
void brcmf_detach(struct device *dev)
869
{
870 871 872
	int i;
	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
	struct brcmf_pub *drvr = bus_if->drvr;
873 874 875

	brcmf_dbg(TRACE, "Enter\n");

876 877
	if (drvr == NULL)
		return;
878

879 880 881
	/* stop firmware event handling */
	brcmf_fweh_detach(drvr);

882 883 884 885
	/* make sure primary interface removed last */
	for (i = BRCMF_MAX_IFS-1; i > -1; i--)
		if (drvr->iflist[i])
			brcmf_del_if(drvr, i);
886

887
	brcmf_bus_detach(drvr);
888

889
	if (drvr->prot) {
890
		brcmf_proto_detach(drvr);
891
	}
892

893
	brcmf_debugfs_detach(drvr);
894 895
	bus_if->drvr = NULL;
	kfree(drvr);
896 897
}

898
static int brcmf_get_pend_8021x_cnt(struct brcmf_pub *drvr)
899
{
900
	return atomic_read(&drvr->pend_8021x_cnt);
901 902 903 904
}

int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
{
905
	struct brcmf_if *ifp = netdev_priv(ndev);
906
	struct brcmf_pub *drvr = ifp->drvr;
907 908 909 910 911 912 913 914 915
	int err;

	err = wait_event_timeout(drvr->pend_8021x_wait,
				 !brcmf_get_pend_8021x_cnt(drvr),
				 msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX));

	WARN_ON(!err);

	return !err;
916 917
}

918
static void brcmf_driver_init(struct work_struct *work)
919
{
920 921
	brcmf_debugfs_init();

922
#ifdef CONFIG_BRCMFMAC_SDIO
923
	brcmf_sdio_init();
924
#endif
925
#ifdef CONFIG_BRCMFMAC_USB
926
	brcmf_usb_init();
927
#endif
928 929 930 931 932 933 934 935
}
static DECLARE_WORK(brcmf_driver_work, brcmf_driver_init);

static int __init brcmfmac_module_init(void)
{
	if (!schedule_work(&brcmf_driver_work))
		return -EBUSY;

936
	return 0;
937 938
}

939
static void __exit brcmfmac_module_exit(void)
940
{
941 942
	cancel_work_sync(&brcmf_driver_work);

943 944 945
#ifdef CONFIG_BRCMFMAC_SDIO
	brcmf_sdio_exit();
#endif
946 947 948
#ifdef CONFIG_BRCMFMAC_USB
	brcmf_usb_exit();
#endif
949
	brcmf_debugfs_exit();
950 951
}

952 953
module_init(brcmfmac_module_init);
module_exit(brcmfmac_module_exit);