diff options
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c')
| -rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c | 302 | 
1 files changed, 78 insertions, 224 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index e067aec1fbf..09dd8c13d84 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -24,13 +24,13 @@  #include "dhd.h"  #include "dhd_bus.h" -#include "dhd_proto.h"  #include "dhd_dbg.h"  #include "fwil_types.h"  #include "p2p.h"  #include "wl_cfg80211.h"  #include "fwil.h"  #include "fwsignal.h" +#include "proto.h"  MODULE_AUTHOR("Broadcom Corporation");  MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); @@ -190,7 +190,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,  	int ret;  	struct brcmf_if *ifp = netdev_priv(ndev);  	struct brcmf_pub *drvr = ifp->drvr; -	struct ethhdr *eh; +	struct ethhdr *eh = (struct ethhdr *)(skb->data);  	brcmf_dbg(DATA, "Enter, idx=%d\n", ifp->bssidx); @@ -236,6 +236,9 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,  		goto done;  	} +	if (eh->h_proto == htons(ETH_P_PAE)) +		atomic_inc(&ifp->pend_8021x_cnt); +  	ret = brcmf_fws_process_skb(ifp, skb);  done: @@ -509,9 +512,8 @@ netif_rx:  	}  } -void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) +void brcmf_rx_frame(struct device *dev, struct sk_buff *skb)  { -	struct sk_buff *skb, *pnext;  	struct brcmf_if *ifp;  	struct brcmf_bus *bus_if = dev_get_drvdata(dev);  	struct brcmf_pub *drvr = bus_if->drvr; @@ -519,56 +521,46 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)  	u8 ifidx;  	int ret; -	brcmf_dbg(DATA, "Enter: %s: count=%u\n", dev_name(dev), -		  skb_queue_len(skb_list)); - -	skb_queue_walk_safe(skb_list, skb, pnext) { -		skb_unlink(skb, skb_list); - -		/* process and remove protocol-specific header */ -		ret = brcmf_proto_hdrpull(drvr, true, &ifidx, skb); -		ifp = drvr->iflist[ifidx]; +	brcmf_dbg(DATA, "Enter: %s: rxp=%p\n", dev_name(dev), skb); -		if (ret || !ifp || !ifp->ndev) { -			if ((ret != -ENODATA) && ifp) -				ifp->stats.rx_errors++; -			brcmu_pkt_buf_free_skb(skb); -			continue; -		} +	/* process and remove protocol-specific header */ +	ret = brcmf_proto_hdrpull(drvr, true, &ifidx, skb); +	ifp = drvr->iflist[ifidx]; -		rd = (struct brcmf_skb_reorder_data *)skb->cb; -		if (rd->reorder) -			brcmf_rxreorder_process_info(ifp, rd->reorder, skb); -		else -			brcmf_netif_rx(ifp, skb); +	if (ret || !ifp || !ifp->ndev) { +		if ((ret != -ENODATA) && ifp) +			ifp->stats.rx_errors++; +		brcmu_pkt_buf_free_skb(skb); +		return;  	} + +	rd = (struct brcmf_skb_reorder_data *)skb->cb; +	if (rd->reorder) +		brcmf_rxreorder_process_info(ifp, rd->reorder, skb); +	else +		brcmf_netif_rx(ifp, skb);  } -void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, +void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx,  		      bool success)  {  	struct brcmf_if *ifp;  	struct ethhdr *eh; -	u8 ifidx;  	u16 type; -	int res; - -	res = brcmf_proto_hdrpull(drvr, false, &ifidx, txp);  	ifp = drvr->iflist[ifidx];  	if (!ifp)  		goto done; -	if (res == 0) { -		eh = (struct ethhdr *)(txp->data); -		type = ntohs(eh->h_proto); +	eh = (struct ethhdr *)(txp->data); +	type = ntohs(eh->h_proto); -		if (type == ETH_P_PAE) { -			atomic_dec(&ifp->pend_8021x_cnt); -			if (waitqueue_active(&ifp->pend_8021x_wait)) -				wake_up(&ifp->pend_8021x_wait); -		} +	if (type == ETH_P_PAE) { +		atomic_dec(&ifp->pend_8021x_cnt); +		if (waitqueue_active(&ifp->pend_8021x_wait)) +			wake_up(&ifp->pend_8021x_wait);  	} +  	if (!success)  		ifp->stats.tx_errors++;  done: @@ -579,13 +571,17 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)  {  	struct brcmf_bus *bus_if = dev_get_drvdata(dev);  	struct brcmf_pub *drvr = bus_if->drvr; +	u8 ifidx;  	/* await txstatus signal for firmware if active */  	if (brcmf_fws_fc_active(drvr->fws)) {  		if (!success)  			brcmf_fws_bustxfail(drvr->fws, txp);  	} else { -		brcmf_txfinalize(drvr, txp, success); +		if (brcmf_proto_hdrpull(drvr, false, &ifidx, txp)) +			brcmu_pkt_buf_free_skb(txp); +		else +			brcmf_txfinalize(drvr, txp, ifidx, success);  	}  } @@ -598,28 +594,6 @@ static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)  	return &ifp->stats;  } -/* - * 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) -{ -	s32 err; - -	err = brcmf_fil_iovar_int_set(ifp, "toe_ol", toe_ol); -	if (err < 0) { -		brcmf_err("Setting toe_ol failed, %d\n", err); -		return err; -	} - -	err = brcmf_fil_iovar_int_set(ifp, "toe", (toe_ol != 0)); -	if (err < 0) -		brcmf_err("Setting toe failed, %d\n", err); - -	return err; - -} -  static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,  				    struct ethtool_drvinfo *info)  { @@ -627,8 +601,8 @@ static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,  	struct brcmf_pub *drvr = ifp->drvr;  	strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); -	snprintf(info->version, sizeof(info->version), "%lu", -		 drvr->drv_version); +	snprintf(info->version, sizeof(info->version), "n/a"); +	strlcpy(info->fw_version, drvr->fwver, sizeof(info->fw_version));  	strlcpy(info->bus_info, dev_name(drvr->bus_if->dev),  		sizeof(info->bus_info));  } @@ -637,124 +611,6 @@ static const struct ethtool_ops brcmf_ethtool_ops = {  	.get_drvinfo = brcmf_ethtool_get_drvinfo,  }; -static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr) -{ -	struct brcmf_pub *drvr = ifp->drvr; -	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, idx=%d\n", ifp->bssidx); - -	/* 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); -		} -		/* report dongle driver type */ -		else -			sprintf(info.driver, "wl"); - -		sprintf(info.version, "%lu", drvr->drv_version); -		if (copy_to_user(uaddr, &info, sizeof(info))) -			return -EFAULT; -		brcmf_dbg(TRACE, "given %*s, returning %s\n", -			  (int)sizeof(drvname), drvname, info.driver); -		break; - -		/* Get toe offload components from dongle */ -	case ETHTOOL_GRXCSUM: -	case ETHTOOL_GTXCSUM: -		ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt); -		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 */ -		ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt); -		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; - -		ret = brcmf_toe_set(ifp, toe_cmpnt); -		if (ret < 0) -			return ret; - -		/* If setting TX checksum mode, tell Linux the new mode */ -		if (cmd == ETHTOOL_STXCSUM) { -			if (edata.data) -				ifp->ndev->features |= NETIF_F_IP_CSUM; -			else -				ifp->ndev->features &= ~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) -{ -	struct brcmf_if *ifp = netdev_priv(ndev); -	struct brcmf_pub *drvr = ifp->drvr; - -	brcmf_dbg(TRACE, "Enter, idx=%d, cmd=0x%04x\n", ifp->bssidx, cmd); - -	if (!drvr->iflist[ifp->bssidx]) -		return -1; - -	if (cmd == SIOCETHTOOL) -		return brcmf_ethtool(ifp, ifr->ifr_data); - -	return -EOPNOTSUPP; -} -  static int brcmf_netdev_stop(struct net_device *ndev)  {  	struct brcmf_if *ifp = netdev_priv(ndev); @@ -775,7 +631,6 @@ static int brcmf_netdev_open(struct net_device *ndev)  	struct brcmf_pub *drvr = ifp->drvr;  	struct brcmf_bus *bus_if = drvr->bus_if;  	u32 toe_ol; -	s32 ret = 0;  	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); @@ -794,21 +649,20 @@ static int brcmf_netdev_open(struct net_device *ndev)  	else  		ndev->features &= ~NETIF_F_IP_CSUM; -	/* Allow transmit calls */ -	netif_start_queue(ndev);  	if (brcmf_cfg80211_up(ndev)) {  		brcmf_err("failed to bring up cfg80211\n"); -		return -1; +		return -EIO;  	} -	return ret; +	/* Allow transmit calls */ +	netif_start_queue(ndev); +	return 0;  }  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 @@ -850,7 +704,7 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)  	brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name); -	ndev->destructor = free_netdev; +	ndev->destructor = brcmf_cfg80211_free_netdev;  	return 0;  fail: @@ -874,13 +728,6 @@ static int brcmf_net_p2p_stop(struct net_device *ndev)  	return brcmf_cfg80211_down(ndev);  } -static int brcmf_net_p2p_do_ioctl(struct net_device *ndev, -				  struct ifreq *ifr, int cmd) -{ -	brcmf_dbg(TRACE, "Enter\n"); -	return 0; -} -  static netdev_tx_t brcmf_net_p2p_start_xmit(struct sk_buff *skb,  					    struct net_device *ndev)  { @@ -893,7 +740,6 @@ static netdev_tx_t brcmf_net_p2p_start_xmit(struct sk_buff *skb,  static const struct net_device_ops brcmf_netdev_ops_p2p = {  	.ndo_open = brcmf_net_p2p_open,  	.ndo_stop = brcmf_net_p2p_stop, -	.ndo_do_ioctl = brcmf_net_p2p_do_ioctl,  	.ndo_start_xmit = brcmf_net_p2p_start_xmit  }; @@ -1015,14 +861,12 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)  		}  		/* unregister will take care of freeing it */  		unregister_netdev(ifp->ndev); -		if (bssidx == 0) -			brcmf_cfg80211_detach(drvr->config);  	} else {  		kfree(ifp);  	}  } -int brcmf_attach(uint bus_hdrlen, struct device *dev) +int brcmf_attach(struct device *dev)  {  	struct brcmf_pub *drvr = NULL;  	int ret = 0; @@ -1037,7 +881,7 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev)  	mutex_init(&drvr->proto_block);  	/* Link to bus module */ -	drvr->hdrlen = bus_hdrlen; +	drvr->hdrlen = 0;  	drvr->bus_if = dev_get_drvdata(dev);  	drvr->bus_if->drvr = drvr; @@ -1054,8 +898,6 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev)  	/* attach firmware event handler */  	brcmf_fweh_attach(drvr); -	INIT_LIST_HEAD(&drvr->bus_if->dcmd_list); -  	return ret;  fail: @@ -1074,13 +916,6 @@ int brcmf_bus_start(struct device *dev)  	brcmf_dbg(TRACE, "\n"); -	/* Bring up the bus */ -	ret = brcmf_bus_init(bus_if); -	if (ret != 0) { -		brcmf_err("brcmf_sdbrcm_bus_init failed %d\n", ret); -		return ret; -	} -  	/* add primary networking interface */  	ifp = brcmf_add_if(drvr, 0, 0, "wlan%d", NULL);  	if (IS_ERR(ifp)) @@ -1094,7 +929,7 @@ int brcmf_bus_start(struct device *dev)  		p2p_ifp = NULL;  	/* signal bus ready */ -	bus_if->state = BRCMF_BUS_DATA; +	brcmf_bus_change_state(bus_if, BRCMF_BUS_DATA);  	/* Bus is ready, do any initialization */  	ret = brcmf_c_preinit_dcmds(ifp); @@ -1121,8 +956,7 @@ int brcmf_bus_start(struct device *dev)  fail:  	if (ret < 0) {  		brcmf_err("failed: %d\n", ret); -		if (drvr->config) -			brcmf_cfg80211_detach(drvr->config); +		brcmf_cfg80211_detach(drvr->config);  		if (drvr->fws) {  			brcmf_fws_del_interface(ifp);  			brcmf_fws_deinit(drvr); @@ -1144,14 +978,21 @@ fail:  	return 0;  } +void brcmf_bus_add_txhdrlen(struct device *dev, uint len) +{ +	struct brcmf_bus *bus_if = dev_get_drvdata(dev); +	struct brcmf_pub *drvr = bus_if->drvr; + +	if (drvr) { +		drvr->hdrlen += len; +	} +} +  static void brcmf_bus_detach(struct brcmf_pub *drvr)  {  	brcmf_dbg(TRACE, "Enter\n");  	if (drvr) { -		/* Stop the protocol module */ -		brcmf_proto_stop(drvr); -  		/* Stop the bus module */  		brcmf_bus_stop(drvr->bus_if);  	} @@ -1183,6 +1024,8 @@ void brcmf_detach(struct device *dev)  	/* stop firmware event handling */  	brcmf_fweh_detach(drvr); +	brcmf_bus_change_state(bus_if, BRCMF_BUS_DOWN); +  	/* make sure primary interface removed last */  	for (i = BRCMF_MAX_IFS-1; i > -1; i--)  		if (drvr->iflist[i]) { @@ -1190,18 +1033,27 @@ void brcmf_detach(struct device *dev)  			brcmf_del_if(drvr, i);  		} -	brcmf_bus_detach(drvr); - -	if (drvr->prot) -		brcmf_proto_detach(drvr); +	brcmf_cfg80211_detach(drvr->config);  	brcmf_fws_deinit(drvr); +	brcmf_bus_detach(drvr); + +	brcmf_proto_detach(drvr); +  	brcmf_debugfs_detach(drvr);  	bus_if->drvr = NULL;  	kfree(drvr);  } +s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len) +{ +	struct brcmf_bus *bus_if = dev_get_drvdata(dev); +	struct brcmf_if *ifp = bus_if->drvr->iflist[0]; + +	return brcmf_fil_iovar_data_set(ifp, name, data, len); +} +  static int brcmf_get_pend_8021x_cnt(struct brcmf_if *ifp)  {  	return atomic_read(&ifp->pend_8021x_cnt); @@ -1231,21 +1083,23 @@ u32 brcmf_get_chip_info(struct brcmf_if *ifp)  	return bus->chip << 4 | bus->chiprev;  } -static void brcmf_driver_init(struct work_struct *work) +static void brcmf_driver_register(struct work_struct *work)  { -	brcmf_debugfs_init(); -  #ifdef CONFIG_BRCMFMAC_SDIO -	brcmf_sdio_init(); +	brcmf_sdio_register();  #endif  #ifdef CONFIG_BRCMFMAC_USB -	brcmf_usb_init(); +	brcmf_usb_register();  #endif  } -static DECLARE_WORK(brcmf_driver_work, brcmf_driver_init); +static DECLARE_WORK(brcmf_driver_work, brcmf_driver_register);  static int __init brcmfmac_module_init(void)  { +	brcmf_debugfs_init(); +#ifdef CONFIG_BRCMFMAC_SDIO +	brcmf_sdio_init(); +#endif  	if (!schedule_work(&brcmf_driver_work))  		return -EBUSY;  | 
