diff options
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c')
| -rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c | 378 | 
1 files changed, 129 insertions, 249 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 4acbac5a74c..58d92bca9ca 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -43,7 +43,6 @@  #include "dhd_proto.h"  #include "dhd_dbg.h"  #include "wl_cfg80211.h" -#include "bcmchip.h"  MODULE_AUTHOR("Broadcom Corporation");  MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac driver."); @@ -58,7 +57,6 @@ struct brcmf_if {  	struct net_device *ndev;  	struct net_device_stats stats;  	int idx;		/* iface idx in dongle */ -	int state;		/* interface state */  	u8 mac_addr[ETH_ALEN];	/* assigned MAC address */  }; @@ -78,22 +76,9 @@ struct brcmf_info {  };  /* Error bits */ +int brcmf_msg_level = BRCMF_ERROR_VAL;  module_param(brcmf_msg_level, int, 0); - -static int brcmf_net2idx(struct brcmf_info *drvr_priv, struct net_device *ndev) -{ -	int i = 0; - -	while (i < BRCMF_MAX_IFS) { -		if (drvr_priv->iflist[i] && drvr_priv->iflist[i]->ndev == ndev) -			return i; -		i++; -	} - -	return BRCMF_BAD_IF; -} -  int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name)  {  	int i = BRCMF_MAX_IFS; @@ -285,14 +270,9 @@ _brcmf_set_mac_address(struct work_struct *work)  static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)  { -	struct brcmf_info *drvr_priv = *(struct brcmf_info **) -					netdev_priv(ndev); +	struct brcmf_if *ifp = netdev_priv(ndev); +	struct brcmf_info *drvr_priv = ifp->info;  	struct sockaddr *sa = (struct sockaddr *)addr; -	int ifidx; - -	ifidx = brcmf_net2idx(drvr_priv, ndev); -	if (ifidx == BRCMF_BAD_IF) -		return -1;  	memcpy(&drvr_priv->macvalue, sa->sa_data, ETH_ALEN);  	schedule_work(&drvr_priv->setmacaddr_work); @@ -301,13 +281,8 @@ static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)  static void brcmf_netdev_set_multicast_list(struct net_device *ndev)  { -	struct brcmf_info *drvr_priv = *(struct brcmf_info **) -					netdev_priv(ndev); -	int ifidx; - -	ifidx = brcmf_net2idx(drvr_priv, ndev); -	if (ifidx == BRCMF_BAD_IF) -		return; +	struct brcmf_if *ifp = netdev_priv(ndev); +	struct brcmf_info *drvr_priv = ifp->info;  	schedule_work(&drvr_priv->multicast_work);  } @@ -317,7 +292,7 @@ int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf)  	struct brcmf_info *drvr_priv = drvr->info;  	/* Reject if down */ -	if (!drvr->up || (drvr->busstate == BRCMF_BUS_DOWN)) +	if (!drvr->up || (drvr->bus_if->state == BRCMF_BUS_DOWN))  		return -ENODEV;  	/* Update multicast statistic */ @@ -335,29 +310,29 @@ int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf)  	brcmf_proto_hdrpush(drvr, ifidx, pktbuf);  	/* Use bus module to send data frame */ -	return brcmf_sdbrcm_bus_txdata(drvr->bus, pktbuf); +	return brcmf_sdbrcm_bus_txdata(drvr->dev, pktbuf);  }  static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)  {  	int ret; -	struct brcmf_info *drvr_priv = *(struct brcmf_info **) -					netdev_priv(ndev); -	int ifidx; +	struct brcmf_if *ifp = netdev_priv(ndev); +	struct brcmf_info *drvr_priv = ifp->info;  	brcmf_dbg(TRACE, "Enter\n");  	/* Reject if down */ -	if (!drvr_priv->pub.up || (drvr_priv->pub.busstate == BRCMF_BUS_DOWN)) { -		brcmf_dbg(ERROR, "xmit rejected pub.up=%d busstate=%d\n", -			  drvr_priv->pub.up, drvr_priv->pub.busstate); +	if (!drvr_priv->pub.up || +	    (drvr_priv->pub.bus_if->state == BRCMF_BUS_DOWN)) { +		brcmf_dbg(ERROR, "xmit rejected pub.up=%d state=%d\n", +			  drvr_priv->pub.up, +			  drvr_priv->pub.bus_if->state);  		netif_stop_queue(ndev);  		return -ENODEV;  	} -	ifidx = brcmf_net2idx(drvr_priv, ndev); -	if (ifidx == BRCMF_BAD_IF) { -		brcmf_dbg(ERROR, "bad ifidx %d\n", ifidx); +	if (!drvr_priv->iflist[ifp->idx]) { +		brcmf_dbg(ERROR, "bad ifidx %d\n", ifp->idx);  		netif_stop_queue(ndev);  		return -ENODEV;  	} @@ -367,20 +342,20 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)  		struct sk_buff *skb2;  		brcmf_dbg(INFO, "%s: insufficient headroom\n", -			  brcmf_ifname(&drvr_priv->pub, ifidx)); +			  brcmf_ifname(&drvr_priv->pub, ifp->idx));  		drvr_priv->pub.tx_realloc++;  		skb2 = skb_realloc_headroom(skb, drvr_priv->pub.hdrlen);  		dev_kfree_skb(skb);  		skb = skb2;  		if (skb == NULL) {  			brcmf_dbg(ERROR, "%s: skb_realloc_headroom failed\n", -				  brcmf_ifname(&drvr_priv->pub, ifidx)); +				  brcmf_ifname(&drvr_priv->pub, ifp->idx));  			ret = -ENOMEM;  			goto done;  		}  	} -	ret = brcmf_sendpkt(&drvr_priv->pub, ifidx, skb); +	ret = brcmf_sendpkt(&drvr_priv->pub, ifp->idx, skb);  done:  	if (ret) @@ -424,26 +399,21 @@ static int brcmf_host_event(struct brcmf_info *drvr_priv, int *ifidx,  	return bcmerror;  } -void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb, -		  int numpkt) +void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, +		    struct sk_buff_head *skb_list)  {  	struct brcmf_info *drvr_priv = drvr->info;  	unsigned char *eth;  	uint len;  	void *data; -	struct sk_buff *pnext, *save_pktbuf; -	int i; +	struct sk_buff *skb, *pnext;  	struct brcmf_if *ifp;  	struct brcmf_event_msg event;  	brcmf_dbg(TRACE, "Enter\n"); -	save_pktbuf = skb; - -	for (i = 0; skb && i < numpkt; i++, skb = pnext) { - -		pnext = skb->next; -		skb->next = NULL; +	skb_queue_walk_safe(skb_list, skb, pnext) { +		skb_unlink(skb, skb_list);  		/* Get the protocol, maintain skb around eth_type_trans()  		 * The main reason for this hack is for the limitation of @@ -464,6 +434,12 @@ void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb,  		if (ifp == NULL)  			ifp = drvr_priv->iflist[0]; +		if (!ifp || !ifp->ndev || +		    ifp->ndev->reg_state != NETREG_REGISTERED) { +			brcmu_pkt_buf_free_skb(skb); +			continue; +		} +  		skb->dev = ifp->ndev;  		skb->protocol = eth_type_trans(skb, skb->dev); @@ -482,12 +458,10 @@ void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb,  					  skb_mac_header(skb),  					  &event, &data); -		if (drvr_priv->iflist[ifidx] && -		    !drvr_priv->iflist[ifidx]->state) +		if (drvr_priv->iflist[ifidx]) {  			ifp = drvr_priv->iflist[ifidx]; - -		if (ifp->ndev)  			ifp->ndev->last_rx = jiffies; +		}  		drvr->dstats.rx_bytes += skb->len;  		drvr->rx_packets++;	/* Local count */ @@ -524,19 +498,11 @@ void brcmf_txcomplete(struct brcmf_pub *drvr, struct sk_buff *txp, bool success)  static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)  { -	struct brcmf_info *drvr_priv = *(struct brcmf_info **) -					netdev_priv(ndev); -	struct brcmf_if *ifp; -	int ifidx; +	struct brcmf_if *ifp = netdev_priv(ndev); +	struct brcmf_info *drvr_priv = ifp->info;  	brcmf_dbg(TRACE, "Enter\n"); -	ifidx = brcmf_net2idx(drvr_priv, ndev); -	if (ifidx == BRCMF_BAD_IF) -		return NULL; - -	ifp = drvr_priv->iflist[ifidx]; -  	if (drvr_priv->pub.up)  		/* Use the protocol to get dongle stats */  		brcmf_proto_dstats(&drvr_priv->pub); @@ -637,14 +603,12 @@ static int brcmf_toe_set(struct brcmf_info *drvr_priv, int ifidx, u32 toe_ol)  static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,  				    struct ethtool_drvinfo *info)  { -	struct brcmf_info *drvr_priv = *(struct brcmf_info **) -					netdev_priv(ndev); +	struct brcmf_if *ifp = netdev_priv(ndev); +	struct brcmf_info *drvr_priv = ifp->info;  	sprintf(info->driver, KBUILD_MODNAME);  	sprintf(info->version, "%lu", drvr_priv->pub.drv_version); -	sprintf(info->fw_version, "%s", BCM4329_FW_NAME); -	sprintf(info->bus_info, "%s", -		dev_name(brcmf_bus_get_device(drvr_priv->pub.bus))); +	sprintf(info->bus_info, "%s", dev_name(drvr_priv->pub.dev));  }  static struct ethtool_ops brcmf_ethtool_ops = { @@ -765,14 +729,12 @@ static int brcmf_ethtool(struct brcmf_info *drvr_priv, void __user *uaddr)  static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,  				    int cmd)  { -	struct brcmf_info *drvr_priv = *(struct brcmf_info **) -					netdev_priv(ndev); -	int ifidx; +	struct brcmf_if *ifp = netdev_priv(ndev); +	struct brcmf_info *drvr_priv = ifp->info; -	ifidx = brcmf_net2idx(drvr_priv, ndev); -	brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifidx, cmd); +	brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifp->idx, cmd); -	if (ifidx == BRCMF_BAD_IF) +	if (!drvr_priv->iflist[ifp->idx])  		return -1;  	if (cmd == SIOCETHTOOL) @@ -788,22 +750,19 @@ s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len)  	s32 err = 0;  	int buflen = 0;  	bool is_set_key_cmd; -	struct brcmf_info *drvr_priv = *(struct brcmf_info **) -					netdev_priv(ndev); -	int ifidx; +	struct brcmf_if *ifp = netdev_priv(ndev); +	struct brcmf_info *drvr_priv = ifp->info;  	memset(&dcmd, 0, sizeof(dcmd));  	dcmd.cmd = cmd;  	dcmd.buf = arg;  	dcmd.len = len; -	ifidx = brcmf_net2idx(drvr_priv, ndev); -  	if (dcmd.buf != NULL)  		buflen = min_t(uint, dcmd.len, BRCMF_DCMD_MAXLEN);  	/* send to dongle (must be up, and wl) */ -	if ((drvr_priv->pub.busstate != BRCMF_BUS_DATA)) { +	if ((drvr_priv->pub.bus_if->state != BRCMF_BUS_DATA)) {  		brcmf_dbg(ERROR, "DONGLE_DOWN\n");  		err = -EIO;  		goto done; @@ -826,7 +785,7 @@ s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len)  	if (is_set_key_cmd)  		brcmf_netdev_wait_pend8021x(ndev); -	err = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, buflen); +	err = brcmf_proto_dcmd(&drvr_priv->pub, ifp->idx, &dcmd, buflen);  done:  	if (err > 0) @@ -837,7 +796,8 @@ done:  static int brcmf_netdev_stop(struct net_device *ndev)  { -	struct brcmf_pub *drvr = *(struct brcmf_pub **) netdev_priv(ndev); +	struct brcmf_if *ifp = netdev_priv(ndev); +	struct brcmf_pub *drvr = &ifp->info->pub;  	brcmf_dbg(TRACE, "Enter\n");  	brcmf_cfg80211_down(drvr->config); @@ -853,16 +813,14 @@ static int brcmf_netdev_stop(struct net_device *ndev)  static int brcmf_netdev_open(struct net_device *ndev)  { -	struct brcmf_info *drvr_priv = *(struct brcmf_info **) -					netdev_priv(ndev); +	struct brcmf_if *ifp = netdev_priv(ndev); +	struct brcmf_info *drvr_priv = ifp->info;  	u32 toe_ol; -	int ifidx = brcmf_net2idx(drvr_priv, ndev);  	s32 ret = 0; -	brcmf_dbg(TRACE, "ifidx %d\n", ifidx); - -	if (ifidx == 0) {	/* do it only for primary eth0 */ +	brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx); +	if (ifp->idx == 0) {	/* do it only for primary eth0 */  		/* try to bring up bus */  		ret = brcmf_bus_start(&drvr_priv->pub);  		if (ret != 0) { @@ -874,12 +832,12 @@ static int brcmf_netdev_open(struct net_device *ndev)  		memcpy(ndev->dev_addr, drvr_priv->pub.mac, ETH_ALEN);  		/* Get current TOE mode from dongle */ -		if (brcmf_toe_get(drvr_priv, ifidx, &toe_ol) >= 0 +		if (brcmf_toe_get(drvr_priv, ifp->idx, &toe_ol) >= 0  		    && (toe_ol & TOE_TX_CSUM_OL) != 0) -			drvr_priv->iflist[ifidx]->ndev->features |= +			drvr_priv->iflist[ifp->idx]->ndev->features |=  				NETIF_F_IP_CSUM;  		else -			drvr_priv->iflist[ifidx]->ndev->features &= +			drvr_priv->iflist[ifp->idx]->ndev->features &=  				~NETIF_F_IP_CSUM;  	}  	/* Allow transmit calls */ @@ -893,75 +851,62 @@ static int brcmf_netdev_open(struct net_device *ndev)  	return ret;  } +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 +}; +  int -brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, struct net_device *ndev, -	     char *name, u8 *mac_addr, u32 flags, u8 bssidx) +brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, char *name, u8 *mac_addr)  {  	struct brcmf_if *ifp; -	int ret = 0, err = 0; +	struct net_device *ndev; -	brcmf_dbg(TRACE, "idx %d, handle->%p\n", ifidx, ndev); +	brcmf_dbg(TRACE, "idx %d\n", ifidx);  	ifp = drvr_priv->iflist[ifidx]; -	if (!ifp) { -		ifp = kmalloc(sizeof(struct brcmf_if), GFP_ATOMIC); -		if (!ifp) -			return -ENOMEM; +	/* +	 * 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); +		drvr_priv->iflist[ifidx] = NULL; +	} + +	/* Allocate netdev, including space for private structure */ +	ndev = alloc_netdev(sizeof(struct brcmf_if), name, ether_setup); +	if (!ndev) { +		brcmf_dbg(ERROR, "OOM - alloc_netdev\n"); +		return -ENOMEM;  	} -	memset(ifp, 0, sizeof(struct brcmf_if)); +	ifp = netdev_priv(ndev); +	ifp->ndev = ndev;  	ifp->info = drvr_priv;  	drvr_priv->iflist[ifidx] = ifp; +	ifp->idx = ifidx;  	if (mac_addr != NULL)  		memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN); -	if (ndev == NULL) { -		ifp->state = BRCMF_E_IF_ADD; -		ifp->idx = ifidx; -		/* -		 * Delete the existing interface before overwriting it -		 * in case we missed the BRCMF_E_IF_DEL event. -		 */ -		if (ifp->ndev != NULL) { -			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); -		} - -		/* Allocate netdev, including space for private structure */ -		ifp->ndev = alloc_netdev(sizeof(drvr_priv), "wlan%d", -					 ether_setup); -		if (!ifp->ndev) { -			brcmf_dbg(ERROR, "OOM - alloc_netdev\n"); -			ret = -ENOMEM; -		} - -		if (ret == 0) { -			memcpy(netdev_priv(ifp->ndev), &drvr_priv, -			       sizeof(drvr_priv)); -			err = brcmf_net_attach(&drvr_priv->pub, ifp->idx); -			if (err != 0) { -				brcmf_dbg(ERROR, "brcmf_net_attach failed, err %d\n", -					  err); -				ret = -EOPNOTSUPP; -			} else { -				brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n", -					  current->pid, ifp->ndev->name); -				ifp->state = 0; -			} -		} - -		if (ret < 0) { -			if (ifp->ndev) -				free_netdev(ifp->ndev); +	if (brcmf_net_attach(&drvr_priv->pub, ifp->idx)) { +		brcmf_dbg(ERROR, "brcmf_net_attach failed"); +		free_netdev(ifp->ndev); +		drvr_priv->iflist[ifidx] = NULL; +		return -EOPNOTSUPP; +	} -			drvr_priv->iflist[ifp->idx] = NULL; -			kfree(ifp); -		} -	} else -		ifp->ndev = ndev; +	brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n", +		  current->pid, ifp->ndev->name);  	return 0;  } @@ -977,47 +922,37 @@ void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx)  		brcmf_dbg(ERROR, "Null interface\n");  		return;  	} +	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); +		} -	ifp->state = BRCMF_E_IF_DEL; -	ifp->idx = ifidx; -	if (ifp->ndev != NULL) { -		netif_stop_queue(ifp->ndev);  		unregister_netdev(ifp->ndev); -		free_netdev(ifp->ndev);  		drvr_priv->iflist[ifidx] = NULL; -		kfree(ifp); +		if (ifidx == 0) +			brcmf_cfg80211_detach(drvr_priv->pub.config); +		free_netdev(ifp->ndev);  	}  } -struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen) +struct brcmf_pub *brcmf_attach(struct brcmf_sdio *bus, uint bus_hdrlen, +			       struct device *dev)  {  	struct brcmf_info *drvr_priv = NULL; -	struct net_device *ndev;  	brcmf_dbg(TRACE, "Enter\n"); -	/* Allocate netdev, including space for private structure */ -	ndev = alloc_netdev(sizeof(drvr_priv), "wlan%d", ether_setup); -	if (!ndev) { -		brcmf_dbg(ERROR, "OOM - alloc_netdev\n"); -		goto fail; -	} -  	/* Allocate primary brcmf_info */  	drvr_priv = kzalloc(sizeof(struct brcmf_info), GFP_ATOMIC);  	if (!drvr_priv)  		goto fail; -	/* -	 * Save the brcmf_info into the priv -	 */ -	memcpy(netdev_priv(ndev), &drvr_priv, sizeof(drvr_priv)); - -	if (brcmf_add_if(drvr_priv, 0, ndev, ndev->name, NULL, 0, 0) == -	    BRCMF_BAD_IF) -		goto fail; - -	ndev->netdev_ops = NULL;  	mutex_init(&drvr_priv->proto_block);  	/* Link to info module */ @@ -1026,6 +961,8 @@ struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen)  	/* Link to bus module */  	drvr_priv->pub.bus = bus;  	drvr_priv->pub.hdrlen = bus_hdrlen; +	drvr_priv->pub.bus_if = dev_get_drvdata(dev); +	drvr_priv->pub.dev = dev;  	/* Attach and link in the protocol */  	if (brcmf_proto_attach(&drvr_priv->pub) != 0) { @@ -1033,29 +970,12 @@ struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen)  		goto fail;  	} -	/* Attach and link in the cfg80211 */ -	drvr_priv->pub.config = -			brcmf_cfg80211_attach(ndev, -					      brcmf_bus_get_device(bus), -					      &drvr_priv->pub); -	if (drvr_priv->pub.config == NULL) { -		brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n"); -		goto fail; -	} -  	INIT_WORK(&drvr_priv->setmacaddr_work, _brcmf_set_mac_address);  	INIT_WORK(&drvr_priv->multicast_work, _brcmf_set_multicast_list); -	/* -	 * Save the brcmf_info into the priv -	 */ -	memcpy(netdev_priv(ndev), &drvr_priv, sizeof(drvr_priv)); -  	return &drvr_priv->pub;  fail: -	if (ndev) -		free_netdev(ndev);  	if (drvr_priv)  		brcmf_detach(&drvr_priv->pub); @@ -1072,14 +992,14 @@ int brcmf_bus_start(struct brcmf_pub *drvr)  	brcmf_dbg(TRACE, "\n");  	/* Bring up the bus */ -	ret = brcmf_sdbrcm_bus_init(&drvr_priv->pub); +	ret = brcmf_sdbrcm_bus_init(drvr_priv->pub.dev);  	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 */ -	if (drvr_priv->pub.busstate != BRCMF_BUS_DATA) { +	if (drvr_priv->pub.bus_if->state != BRCMF_BUS_DATA) {  		brcmf_dbg(ERROR, "failed bus is not ready\n");  		return -ENODEV;  	} @@ -1123,16 +1043,6 @@ int brcmf_bus_start(struct brcmf_pub *drvr)  	return 0;  } -static 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 -}; -  int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx)  {  	struct brcmf_info *drvr_priv = drvr->info; @@ -1169,6 +1079,15 @@ int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx)  	memcpy(ndev->dev_addr, temp_addr, ETH_ALEN); +	/* attach to cfg80211 for primary interface */ +	if (!ifidx) { +		drvr->config = brcmf_cfg80211_attach(ndev, drvr->dev, drvr); +		if (drvr->config == NULL) { +			brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n"); +			goto fail; +		} +	} +  	if (register_netdev(ndev) != 0) {  		brcmf_dbg(ERROR, "couldn't register the net device\n");  		goto fail; @@ -1196,7 +1115,7 @@ static void brcmf_bus_detach(struct brcmf_pub *drvr)  			brcmf_proto_stop(&drvr_priv->pub);  			/* Stop the bus module */ -			brcmf_sdbrcm_bus_stop(drvr_priv->pub.bus); +			brcmf_sdbrcm_bus_stop(drvr_priv->pub.dev);  		}  	}  } @@ -1210,21 +1129,13 @@ void brcmf_detach(struct brcmf_pub *drvr)  	if (drvr) {  		drvr_priv = drvr->info;  		if (drvr_priv) { -			struct brcmf_if *ifp;  			int i; -			for (i = 1; i < BRCMF_MAX_IFS; i++) +			/* make sure primary interface removed last */ +			for (i = BRCMF_MAX_IFS-1; i > -1; i--)  				if (drvr_priv->iflist[i])  					brcmf_del_if(drvr_priv, i); -			ifp = drvr_priv->iflist[0]; -			if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { -				rtnl_lock(); -				brcmf_netdev_stop(ifp->ndev); -				rtnl_unlock(); -				unregister_netdev(ifp->ndev); -			} -  			cancel_work_sync(&drvr_priv->setmacaddr_work);  			cancel_work_sync(&drvr_priv->multicast_work); @@ -1233,43 +1144,11 @@ void brcmf_detach(struct brcmf_pub *drvr)  			if (drvr->prot)  				brcmf_proto_detach(drvr); -			brcmf_cfg80211_detach(drvr->config); - -			free_netdev(ifp->ndev); -			kfree(ifp);  			kfree(drvr_priv);  		}  	}  } -static void __exit brcmf_module_cleanup(void) -{ -	brcmf_dbg(TRACE, "Enter\n"); - -	brcmf_bus_unregister(); -} - -static int __init brcmf_module_init(void) -{ -	int error; - -	brcmf_dbg(TRACE, "Enter\n"); - -	error = brcmf_bus_register(); - -	if (error) { -		brcmf_dbg(ERROR, "brcmf_bus_register failed\n"); -		goto failed; -	} -	return 0; - -failed: -	return -EINVAL; -} - -module_init(brcmf_module_init); -module_exit(brcmf_module_cleanup); -  int brcmf_os_proto_block(struct brcmf_pub *drvr)  {  	struct brcmf_info *drvr_priv = drvr->info; @@ -1302,7 +1181,8 @@ static int brcmf_get_pend_8021x_cnt(struct brcmf_info *drvr_priv)  int brcmf_netdev_wait_pend8021x(struct net_device *ndev)  { -	struct brcmf_info *drvr_priv = *(struct brcmf_info **)netdev_priv(ndev); +	struct brcmf_if *ifp = netdev_priv(ndev); +	struct brcmf_info *drvr_priv = ifp->info;  	int timeout = 10 * HZ / 1000;  	int ntimes = MAX_WAIT_FOR_8021X_TX;  	int pend = brcmf_get_pend_8021x_cnt(drvr_priv);  |