dhd_linux.c 21.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * 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.
 */

17 18
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

19 20
#include <linux/kernel.h>
#include <linux/etherdevice.h>
21
#include <linux/module.h>
22 23 24 25 26 27 28 29 30 31
#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"
32
#include "fwil.h"
33 34

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

39
#define MAX_WAIT_FOR_8021X_TX		50	/* msecs */
40 41

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


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

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

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

	return "<if_none>";
}

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

75 76
	brcmf_dbg(TRACE, "enter\n");

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

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

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

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

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

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

	kfree(buf);

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

	/*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)
124
		brcmf_err("Setting BRCMF_C_SET_PROMISC failed, %d\n",
125
			  err);
126 127 128 129 130
}

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

	brcmf_dbg(TRACE, "enter\n");

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

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

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

static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
{
160
	struct brcmf_if *ifp = netdev_priv(ndev);
161

162
	schedule_work(&ifp->multicast_work);
163 164 165 166 167
}

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

	brcmf_dbg(TRACE, "Enter\n");

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

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

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

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

207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
	/* 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 已提交
222
	ret =  brcmf_bus_txdata(drvr->bus_if, skb);
223 224 225

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

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

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

	brcmf_dbg(TRACE, "Enter\n");

243 244 245 246 247 248 249 250
	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);
		}
251 252
}

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

	brcmf_dbg(TRACE, "Enter\n");

265 266
	skb_queue_walk_safe(skb_list, skb, pnext) {
		skb_unlink(skb, skb_list);
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282

		/* 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;

283
		ifp = drvr->iflist[ifidx];
284
		if (ifp == NULL)
285
			ifp = drvr->iflist[0];
286

287 288 289 290 291 292
		if (!ifp || !ifp->ndev ||
		    ifp->ndev->reg_state != NETREG_REGISTERED) {
			brcmu_pkt_buf_free_skb(skb);
			continue;
		}

293 294 295 296
		skb->dev = ifp->ndev;
		skb->protocol = eth_type_trans(skb, skb->dev);

		if (skb->pkt_type == PACKET_MULTICAST)
297
			bus_if->dstats.multicast++;
298 299 300 301 302 303 304 305

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

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

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

308 309
		if (drvr->iflist[ifidx]) {
			ifp = drvr->iflist[ifidx];
310
			ifp->ndev->last_rx = jiffies;
311
		}
312

313 314
		bus_if->dstats.rx_bytes += skb->len;
		bus_if->dstats.rx_packets++;	/* Local count */
315 316 317 318 319 320 321 322 323 324 325 326 327 328

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

329
void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
330 331 332 333
{
	uint ifidx;
	struct ethhdr *eh;
	u16 type;
334 335
	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
	struct brcmf_pub *drvr = bus_if->drvr;
336

337
	brcmf_proto_hdrpull(dev, &ifidx, txp);
338 339 340 341

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

342
	if (type == ETH_P_PAE) {
343
		atomic_dec(&drvr->pend_8021x_cnt);
344 345 346
		if (waitqueue_active(&drvr->pend_8021x_wait))
			wake_up(&drvr->pend_8021x_wait);
	}
347 348 349 350
}

static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
{
351
	struct brcmf_if *ifp = netdev_priv(ndev);
352
	struct brcmf_bus *bus_if = ifp->drvr->bus_if;
353 354 355 356

	brcmf_dbg(TRACE, "Enter\n");

	/* Copy dongle stats to net device stats */
357 358 359 360 361 362 363 364 365
	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;
366 367 368 369

	return &ifp->stats;
}

370 371 372 373 374
/*
 * 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)
375
{
376
	s32 err;
377

378 379
	err = brcmf_fil_iovar_int_set(ifp, "toe_ol", toe_ol);
	if (err < 0) {
380
		brcmf_err("Setting toe_ol failed, %d\n", err);
381
		return err;
382 383
	}

384 385
	err = brcmf_fil_iovar_int_set(ifp, "toe", (toe_ol != 0));
	if (err < 0)
386
		brcmf_err("Setting toe failed, %d\n", err);
387

388
	return err;
389 390 391 392 393 394

}

static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
				    struct ethtool_drvinfo *info)
{
395
	struct brcmf_if *ifp = netdev_priv(ndev);
396
	struct brcmf_pub *drvr = ifp->drvr;
397 398

	sprintf(info->driver, KBUILD_MODNAME);
399
	sprintf(info->version, "%lu", drvr->drv_version);
A
Arend van Spriel 已提交
400
	sprintf(info->bus_info, "%s", dev_name(drvr->bus_if->dev));
401 402
}

403 404
static const struct ethtool_ops brcmf_ethtool_ops = {
	.get_drvinfo = brcmf_ethtool_get_drvinfo,
405 406
};

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

450
		sprintf(info.version, "%lu", drvr->drv_version);
451 452 453 454 455 456 457 458 459
		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:
460
		ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt);
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480
		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 */
481
		ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt);
482 483 484 485 486 487 488 489 490 491 492
		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;

493
		ret = brcmf_toe_set(ifp, toe_cmpnt);
494 495 496 497 498 499
		if (ret < 0)
			return ret;

		/* If setting TX checksum mode, tell Linux the new mode */
		if (cmd == ETHTOOL_STXCSUM) {
			if (edata.data)
500
				ifp->ndev->features |= NETIF_F_IP_CSUM;
501
			else
502
				ifp->ndev->features &= ~NETIF_F_IP_CSUM;
503 504 505 506 507 508 509 510 511 512 513 514 515 516
		}

		break;

	default:
		return -EOPNOTSUPP;
	}

	return 0;
}

static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,
				    int cmd)
{
517
	struct brcmf_if *ifp = netdev_priv(ndev);
518
	struct brcmf_pub *drvr = ifp->drvr;
519

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

522
	if (!drvr->iflist[ifp->idx])
523 524 525
		return -1;

	if (cmd == SIOCETHTOOL)
526
		return brcmf_ethtool(ifp, ifr->ifr_data);
527 528 529 530 531 532

	return -EOPNOTSUPP;
}

static int brcmf_netdev_stop(struct net_device *ndev)
{
533
	struct brcmf_if *ifp = netdev_priv(ndev);
534
	struct brcmf_pub *drvr = ifp->drvr;
535 536

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

538
	if (drvr->bus_if->drvr_up == 0)
539 540
		return 0;

541
	brcmf_cfg80211_down(ndev);
542

543
	/* Set state and stop OS transmissions */
J
John W. Linville 已提交
544
	drvr->bus_if->drvr_up = false;
545 546 547 548 549 550 551
	netif_stop_queue(ndev);

	return 0;
}

static int brcmf_netdev_open(struct net_device *ndev)
{
552
	struct brcmf_if *ifp = netdev_priv(ndev);
553
	struct brcmf_pub *drvr = ifp->drvr;
554
	struct brcmf_bus *bus_if = drvr->bus_if;
555 556 557
	u32 toe_ol;
	s32 ret = 0;

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

560 561
	/* If bus is not ready, can't continue */
	if (bus_if->state != BRCMF_BUS_DATA) {
562
		brcmf_err("failed bus is not ready\n");
563 564
		return -EAGAIN;
	}
565

566
	atomic_set(&drvr->pend_8021x_cnt, 0);
567

568
	memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN);
569

570 571 572 573 574 575 576 577
	/* 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;
578 579

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

582 583
	/* Allow transmit calls */
	netif_start_queue(ndev);
J
John W. Linville 已提交
584
	drvr->bus_if->drvr_up = true;
585
	if (brcmf_cfg80211_up(ndev)) {
586
		brcmf_err("failed to bring up cfg80211\n");
587 588 589 590 591 592
		return -1;
	}

	return ret;
}

593 594 595 596 597 598 599 600 601 602
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
};

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

613
int brcmf_net_attach(struct brcmf_if *ifp)
614
{
615
	struct brcmf_pub *drvr = ifp->drvr;
616 617
	struct net_device *ndev;

618 619
	brcmf_dbg(TRACE, "ifidx %d mac %pM\n", ifp->idx, ifp->mac_addr);
	ndev = ifp->ndev;
620

621 622 623 624 625
	/* set appropriate operations */
	if (!ifp->idx)
		ndev->netdev_ops = &brcmf_netdev_ops_pri;
	else
		ndev->netdev_ops = &brcmf_netdev_ops_virt;
626 627 628 629 630 631 632

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

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

633 634
	/* set the mac address */
	memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
635 636

	if (register_netdev(ndev) != 0) {
637
		brcmf_err("couldn't register the net device\n");
638 639 640 641 642 643 644 645 646 647 648 649
		goto fail;
	}

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

	return 0;

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

650
struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx,
651
			      char *name, u8 *addr_mask)
652 653
{
	struct brcmf_if *ifp;
654
	struct net_device *ndev;
655
	int i;
656

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

659
	ifp = drvr->iflist[ifidx];
660 661 662 663 664
	/*
	 * Delete the existing interface before overwriting it
	 * in case we missed the BRCMF_E_IF_DEL event.
	 */
	if (ifp) {
665
		brcmf_err("ERROR: netdev:%s already exists\n",
666
			  ifp->ndev->name);
667 668 669 670 671 672
		if (ifidx) {
			netif_stop_queue(ifp->ndev);
			unregister_netdev(ifp->ndev);
			free_netdev(ifp->ndev);
			drvr->iflist[ifidx] = NULL;
		} else {
673
			brcmf_err("ignore IF event\n");
674 675
			return ERR_PTR(-EINVAL);
		}
676
	}
677

678
	/* Allocate netdev, including space for private structure */
679 680
	ndev = alloc_netdev(sizeof(struct brcmf_if), name, ether_setup);
	if (!ndev) {
681
		brcmf_err("OOM - alloc_netdev\n");
682
		return ERR_PTR(-ENOMEM);
683
	}
684

685 686
	ifp = netdev_priv(ndev);
	ifp->ndev = ndev;
687 688
	ifp->drvr = drvr;
	drvr->iflist[ifidx] = ifp;
689
	ifp->idx = ifidx;
690
	ifp->bssidx = bssidx;
691 692 693 694

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

695 696 697
	if (addr_mask != NULL)
		for (i = 0; i < ETH_ALEN; i++)
			ifp->mac_addr[i] = drvr->mac[i] ^ addr_mask[i];
698

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

702
	return ifp;
703 704
}

705
void brcmf_del_if(struct brcmf_pub *drvr, int ifidx)
706 707 708 709 710
{
	struct brcmf_if *ifp;

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

711
	ifp = drvr->iflist[ifidx];
712
	if (!ifp) {
713
		brcmf_err("Null interface\n");
714 715
		return;
	}
716 717 718 719 720 721 722 723 724 725 726
	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);
		}

727 728 729
		cancel_work_sync(&ifp->setmacaddr_work);
		cancel_work_sync(&ifp->multicast_work);

730
		unregister_netdev(ifp->ndev);
731
		drvr->iflist[ifidx] = NULL;
732
		if (ifidx == 0)
733
			brcmf_cfg80211_detach(drvr->config);
734
		free_netdev(ifp->ndev);
735 736 737
	}
}

738
int brcmf_attach(uint bus_hdrlen, struct device *dev)
739
{
740
	struct brcmf_pub *drvr = NULL;
741
	int ret = 0;
742 743 744 745

	brcmf_dbg(TRACE, "Enter\n");

	/* Allocate primary brcmf_info */
746 747
	drvr = kzalloc(sizeof(struct brcmf_pub), GFP_ATOMIC);
	if (!drvr)
748
		return -ENOMEM;
749

750
	mutex_init(&drvr->proto_block);
751 752

	/* Link to bus module */
753 754
	drvr->hdrlen = bus_hdrlen;
	drvr->bus_if = dev_get_drvdata(dev);
755
	drvr->bus_if->drvr = drvr;
756

757 758 759
	/* create device debugfs folder */
	brcmf_debugfs_attach(drvr);

760
	/* Attach and link in the protocol */
761 762
	ret = brcmf_proto_attach(drvr);
	if (ret != 0) {
763
		brcmf_err("brcmf_prot_attach failed\n");
764 765 766
		goto fail;
	}

767 768 769
	/* attach firmware event handler */
	brcmf_fweh_attach(drvr);

770 771
	INIT_LIST_HEAD(&drvr->bus_if->dcmd_list);

772 773
	init_waitqueue_head(&drvr->pend_8021x_wait);

774
	return ret;
775 776

fail:
777
	brcmf_detach(dev);
778

779
	return ret;
780 781
}

782
int brcmf_bus_start(struct device *dev)
783 784
{
	int ret = -1;
785 786
	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
	struct brcmf_pub *drvr = bus_if->drvr;
787
	struct brcmf_if *ifp;
788 789 790 791

	brcmf_dbg(TRACE, "\n");

	/* Bring up the bus */
A
Arend van Spriel 已提交
792
	ret = brcmf_bus_init(bus_if);
793
	if (ret != 0) {
794
		brcmf_err("brcmf_sdbrcm_bus_init failed %d\n", ret);
795 796 797
		return ret;
	}

798
	/* add primary networking interface */
799
	ifp = brcmf_add_if(drvr, 0, 0, "wlan%d", NULL);
800 801 802
	if (IS_ERR(ifp))
		return PTR_ERR(ifp);

803 804 805 806 807
	/* signal bus ready */
	bus_if->state = BRCMF_BUS_DATA;

	/* Bus is ready, do any initialization */
	ret = brcmf_c_preinit_dcmds(ifp);
808
	if (ret < 0)
809
		goto fail;
810

A
Arend van Spriel 已提交
811
	drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev);
812 813 814 815
	if (drvr->config == NULL) {
		ret = -ENOMEM;
		goto fail;
	}
816

817 818 819 820
	ret = brcmf_fweh_activate_events(ifp);
	if (ret < 0)
		goto fail;

821
	ret = brcmf_net_attach(ifp);
822
fail:
823
	if (ret < 0) {
824
		brcmf_err("failed: %d\n", ret);
825 826 827
		if (drvr->config)
			brcmf_cfg80211_detach(drvr->config);
		free_netdev(drvr->iflist[0]->ndev);
828
		drvr->iflist[0] = NULL;
829
		return ret;
830 831
	}

832 833 834 835 836 837 838 839
	return 0;
}

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

	if (drvr) {
840 841
		/* Stop the protocol module */
		brcmf_proto_stop(drvr);
842

843
		/* Stop the bus module */
A
Arend van Spriel 已提交
844
		brcmf_bus_stop(drvr->bus_if);
845 846 847
	}
}

848
void brcmf_detach(struct device *dev)
849
{
850 851 852
	int i;
	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
	struct brcmf_pub *drvr = bus_if->drvr;
853 854 855

	brcmf_dbg(TRACE, "Enter\n");

856 857
	if (drvr == NULL)
		return;
858

859 860 861
	/* stop firmware event handling */
	brcmf_fweh_detach(drvr);

862 863 864 865
	/* make sure primary interface removed last */
	for (i = BRCMF_MAX_IFS-1; i > -1; i--)
		if (drvr->iflist[i])
			brcmf_del_if(drvr, i);
866

867
	brcmf_bus_detach(drvr);
868

869
	if (drvr->prot) {
870
		brcmf_proto_detach(drvr);
871
	}
872

873
	brcmf_debugfs_detach(drvr);
874 875
	bus_if->drvr = NULL;
	kfree(drvr);
876 877
}

878
static int brcmf_get_pend_8021x_cnt(struct brcmf_pub *drvr)
879
{
880
	return atomic_read(&drvr->pend_8021x_cnt);
881 882 883 884
}

int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
{
885
	struct brcmf_if *ifp = netdev_priv(ndev);
886
	struct brcmf_pub *drvr = ifp->drvr;
887 888 889 890 891 892 893 894 895
	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;
896 897
}

898
static void brcmf_driver_init(struct work_struct *work)
899
{
900 901
	brcmf_debugfs_init();

902
#ifdef CONFIG_BRCMFMAC_SDIO
903
	brcmf_sdio_init();
904
#endif
905
#ifdef CONFIG_BRCMFMAC_USB
906
	brcmf_usb_init();
907
#endif
908 909 910 911 912 913 914 915
}
static DECLARE_WORK(brcmf_driver_work, brcmf_driver_init);

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

916
	return 0;
917 918
}

919
static void __exit brcmfmac_module_exit(void)
920
{
921 922
	cancel_work_sync(&brcmf_driver_work);

923 924 925
#ifdef CONFIG_BRCMFMAC_SDIO
	brcmf_sdio_exit();
#endif
926 927 928
#ifdef CONFIG_BRCMFMAC_USB
	brcmf_usb_exit();
#endif
929
	brcmf_debugfs_exit();
930 931
}

932 933
module_init(brcmfmac_module_init);
module_exit(brcmfmac_module_exit);