diff options
Diffstat (limited to 'drivers/net')
199 files changed, 4252 insertions, 2474 deletions
diff --git a/drivers/net/arcnet/com20020_cs.c b/drivers/net/arcnet/com20020_cs.c index 5bed4c4e250..74dc1875f9c 100644 --- a/drivers/net/arcnet/com20020_cs.c +++ b/drivers/net/arcnet/com20020_cs.c @@ -333,16 +333,4 @@ static struct pcmcia_driver com20020_cs_driver = {  	.suspend	= com20020_suspend,  	.resume		= com20020_resume,  }; - -static int __init init_com20020_cs(void) -{ -	return pcmcia_register_driver(&com20020_cs_driver); -} - -static void __exit exit_com20020_cs(void) -{ -	pcmcia_unregister_driver(&com20020_cs_driver); -} - -module_init(init_com20020_cs); -module_exit(exit_com20020_cs); +module_pcmcia_driver(com20020_cs_driver); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 11d01d67b3f..dbbea0eec13 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -846,8 +846,10 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active,  		if (bond->dev->flags & IFF_ALLMULTI)  			dev_set_allmulti(old_active->dev, -1); +		netif_addr_lock_bh(bond->dev);  		netdev_for_each_mc_addr(ha, bond->dev)  			dev_mc_del(old_active->dev, ha->addr); +		netif_addr_unlock_bh(bond->dev);  	}  	if (new_active) { @@ -858,8 +860,10 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active,  		if (bond->dev->flags & IFF_ALLMULTI)  			dev_set_allmulti(new_active->dev, 1); +		netif_addr_lock_bh(bond->dev);  		netdev_for_each_mc_addr(ha, bond->dev)  			dev_mc_add(new_active->dev, ha->addr); +		netif_addr_unlock_bh(bond->dev);  	}  } @@ -1629,7 +1633,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)  	/* If this is the first slave, then we need to set the master's hardware  	 * address to be the same as the slave's. */ -	if (bond->dev_addr_from_first) +	if (bond->slave_cnt == 0 && bond->dev_addr_from_first)  		bond_set_dev_addr(bond->dev, slave_dev);  	new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL); @@ -1746,6 +1750,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)  	bond_compute_features(bond); +	bond_update_speed_duplex(new_slave); +  	read_lock(&bond->lock);  	new_slave->last_arp_rx = jiffies - @@ -1798,8 +1804,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)  		new_slave->link == BOND_LINK_DOWN ? "DOWN" :  			(new_slave->link == BOND_LINK_UP ? "UP" : "BACK")); -	bond_update_speed_duplex(new_slave); -  	if (USES_PRIMARY(bond->params.mode) && bond->params.primary[0]) {  		/* if there is a primary slave, remember it */  		if (strcmp(bond->params.primary, new_slave->dev->name) == 0) { @@ -1901,11 +1905,29 @@ err_dest_symlinks:  	bond_destroy_slave_symlinks(bond_dev, slave_dev);  err_detach: +	if (!USES_PRIMARY(bond->params.mode)) { +		netif_addr_lock_bh(bond_dev); +		bond_mc_list_flush(bond_dev, slave_dev); +		netif_addr_unlock_bh(bond_dev); +	} +	bond_del_vlans_from_slave(bond, slave_dev);  	write_lock_bh(&bond->lock);  	bond_detach_slave(bond, new_slave); +	if (bond->primary_slave == new_slave) +		bond->primary_slave = NULL;  	write_unlock_bh(&bond->lock); +	if (bond->curr_active_slave == new_slave) { +		read_lock(&bond->lock); +		write_lock_bh(&bond->curr_slave_lock); +		bond_change_active_slave(bond, NULL); +		bond_select_active_slave(bond); +		write_unlock_bh(&bond->curr_slave_lock); +		read_unlock(&bond->lock); +	} +	slave_disable_netpoll(new_slave);  err_close: +	slave_dev->priv_flags &= ~IFF_BONDING;  	dev_close(slave_dev);  err_unset_master: @@ -1964,7 +1986,6 @@ static int __bond_release_one(struct net_device *bond_dev,  	}  	block_netpoll_tx(); -	call_netdevice_notifiers(NETDEV_RELEASE, bond_dev);  	write_lock_bh(&bond->lock);  	slave = bond_get_slave_by_dev(bond, slave_dev); @@ -1977,12 +1998,11 @@ static int __bond_release_one(struct net_device *bond_dev,  		return -EINVAL;  	} +	write_unlock_bh(&bond->lock);  	/* unregister rx_handler early so bond_handle_frame wouldn't be called  	 * for this slave anymore.  	 */  	netdev_rx_handler_unregister(slave_dev); -	write_unlock_bh(&bond->lock); -	synchronize_net();  	write_lock_bh(&bond->lock);  	if (!all && !bond->params.fail_over_mac) { @@ -2066,8 +2086,10 @@ static int __bond_release_one(struct net_device *bond_dev,  	write_unlock_bh(&bond->lock);  	unblock_netpoll_tx(); -	if (bond->slave_cnt == 0) +	if (bond->slave_cnt == 0) {  		call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev); +		call_netdevice_notifiers(NETDEV_RELEASE, bond->dev); +	}  	bond_compute_features(bond);  	if (!(bond_dev->features & NETIF_F_VLAN_CHALLENGED) && @@ -2373,8 +2395,6 @@ static void bond_miimon_commit(struct bonding *bond)  				bond_set_backup_slave(slave);  			} -			bond_update_speed_duplex(slave); -  			pr_info("%s: link status definitely up for interface %s, %u Mbps %s duplex.\n",  				bond->dev->name, slave->dev->name,  				slave->speed, slave->duplex ? "full" : "half"); @@ -3170,11 +3190,20 @@ static int bond_slave_netdev_event(unsigned long event,  				   struct net_device *slave_dev)  {  	struct slave *slave = bond_slave_get_rtnl(slave_dev); -	struct bonding *bond = slave->bond; -	struct net_device *bond_dev = slave->bond->dev; +	struct bonding *bond; +	struct net_device *bond_dev;  	u32 old_speed;  	u8 old_duplex; +	/* A netdev event can be generated while enslaving a device +	 * before netdev_rx_handler_register is called in which case +	 * slave will be NULL +	 */ +	if (!slave) +		return NOTIFY_DONE; +	bond_dev = slave->bond->dev; +	bond = slave->bond; +  	switch (event) {  	case NETDEV_UNREGISTER:  		if (bond->setup_by_slave) @@ -3288,20 +3317,22 @@ static int bond_xmit_hash_policy_l2(struct sk_buff *skb, int count)   */  static int bond_xmit_hash_policy_l23(struct sk_buff *skb, int count)  { -	struct ethhdr *data = (struct ethhdr *)skb->data; -	struct iphdr *iph; -	struct ipv6hdr *ipv6h; +	const struct ethhdr *data; +	const struct iphdr *iph; +	const struct ipv6hdr *ipv6h;  	u32 v6hash; -	__be32 *s, *d; +	const __be32 *s, *d;  	if (skb->protocol == htons(ETH_P_IP) && -	    skb_network_header_len(skb) >= sizeof(*iph)) { +	    pskb_network_may_pull(skb, sizeof(*iph))) {  		iph = ip_hdr(skb); +		data = (struct ethhdr *)skb->data;  		return ((ntohl(iph->saddr ^ iph->daddr) & 0xffff) ^  			(data->h_dest[5] ^ data->h_source[5])) % count;  	} else if (skb->protocol == htons(ETH_P_IPV6) && -		   skb_network_header_len(skb) >= sizeof(*ipv6h)) { +		   pskb_network_may_pull(skb, sizeof(*ipv6h))) {  		ipv6h = ipv6_hdr(skb); +		data = (struct ethhdr *)skb->data;  		s = &ipv6h->saddr.s6_addr32[0];  		d = &ipv6h->daddr.s6_addr32[0];  		v6hash = (s[1] ^ d[1]) ^ (s[2] ^ d[2]) ^ (s[3] ^ d[3]); @@ -3320,33 +3351,36 @@ static int bond_xmit_hash_policy_l23(struct sk_buff *skb, int count)  static int bond_xmit_hash_policy_l34(struct sk_buff *skb, int count)  {  	u32 layer4_xor = 0; -	struct iphdr *iph; -	struct ipv6hdr *ipv6h; -	__be32 *s, *d; -	__be16 *layer4hdr; +	const struct iphdr *iph; +	const struct ipv6hdr *ipv6h; +	const __be32 *s, *d; +	const __be16 *l4 = NULL; +	__be16 _l4[2]; +	int noff = skb_network_offset(skb); +	int poff;  	if (skb->protocol == htons(ETH_P_IP) && -	    skb_network_header_len(skb) >= sizeof(*iph)) { +	    pskb_may_pull(skb, noff + sizeof(*iph))) {  		iph = ip_hdr(skb); -		if (!ip_is_fragment(iph) && -		    (iph->protocol == IPPROTO_TCP || -		     iph->protocol == IPPROTO_UDP) && -		    (skb_headlen(skb) - skb_network_offset(skb) >= -		     iph->ihl * sizeof(u32) + sizeof(*layer4hdr) * 2)) { -			layer4hdr = (__be16 *)((u32 *)iph + iph->ihl); -			layer4_xor = ntohs(*layer4hdr ^ *(layer4hdr + 1)); +		poff = proto_ports_offset(iph->protocol); + +		if (!ip_is_fragment(iph) && poff >= 0) { +			l4 = skb_header_pointer(skb, noff + (iph->ihl << 2) + poff, +						sizeof(_l4), &_l4); +			if (l4) +				layer4_xor = ntohs(l4[0] ^ l4[1]);  		}  		return (layer4_xor ^  			((ntohl(iph->saddr ^ iph->daddr)) & 0xffff)) % count;  	} else if (skb->protocol == htons(ETH_P_IPV6) && -		   skb_network_header_len(skb) >= sizeof(*ipv6h)) { +		   pskb_may_pull(skb, noff + sizeof(*ipv6h))) {  		ipv6h = ipv6_hdr(skb); -		if ((ipv6h->nexthdr == IPPROTO_TCP || -		     ipv6h->nexthdr == IPPROTO_UDP) && -		    (skb_headlen(skb) - skb_network_offset(skb) >= -		     sizeof(*ipv6h) + sizeof(*layer4hdr) * 2)) { -			layer4hdr = (__be16 *)(ipv6h + 1); -			layer4_xor = ntohs(*layer4hdr ^ *(layer4hdr + 1)); +		poff = proto_ports_offset(ipv6h->nexthdr); +		if (poff >= 0) { +			l4 = skb_header_pointer(skb, noff + sizeof(*ipv6h) + poff, +						sizeof(_l4), &_l4); +			if (l4) +				layer4_xor = ntohs(l4[0] ^ l4[1]);  		}  		s = &ipv6h->saddr.s6_addr32[0];  		d = &ipv6h->daddr.s6_addr32[0]; @@ -4848,9 +4882,18 @@ static int __net_init bond_net_init(struct net *net)  static void __net_exit bond_net_exit(struct net *net)  {  	struct bond_net *bn = net_generic(net, bond_net_id); +	struct bonding *bond, *tmp_bond; +	LIST_HEAD(list);  	bond_destroy_sysfs(bn);  	bond_destroy_proc_dir(bn); + +	/* Kill off any bonds created after unregistering bond rtnl ops */ +	rtnl_lock(); +	list_for_each_entry_safe(bond, tmp_bond, &bn->dev_list, bond_list) +		unregister_netdevice_queue(bond->dev, &list); +	unregister_netdevice_many(&list); +	rtnl_unlock();  }  static struct pernet_operations bond_net_ops = { diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 1c9e09fbdff..ea7a388f484 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -183,6 +183,11 @@ int bond_create_slave_symlinks(struct net_device *master,  	sprintf(linkname, "slave_%s", slave->name);  	ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj),  				linkname); + +	/* free the master link created earlier in case of error */ +	if (ret) +		sysfs_remove_link(&(slave->dev.kobj), "master"); +  	return ret;  } @@ -522,7 +527,7 @@ static ssize_t bonding_store_arp_interval(struct device *d,  		goto out;  	}  	if (new_value < 0) { -		pr_err("%s: Invalid arp_interval value %d not in range 1-%d; rejected.\n", +		pr_err("%s: Invalid arp_interval value %d not in range 0-%d; rejected.\n",  		       bond->dev->name, new_value, INT_MAX);  		ret = -EINVAL;  		goto out; @@ -537,14 +542,15 @@ static ssize_t bonding_store_arp_interval(struct device *d,  	pr_info("%s: Setting ARP monitoring interval to %d.\n",  		bond->dev->name, new_value);  	bond->params.arp_interval = new_value; -	if (bond->params.miimon) { -		pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring.\n", -			bond->dev->name, bond->dev->name); -		bond->params.miimon = 0; -	} -	if (!bond->params.arp_targets[0]) { -		pr_info("%s: ARP monitoring has been set up, but no ARP targets have been specified.\n", -			bond->dev->name); +	if (new_value) { +		if (bond->params.miimon) { +			pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring.\n", +				bond->dev->name, bond->dev->name); +			bond->params.miimon = 0; +		} +		if (!bond->params.arp_targets[0]) +			pr_info("%s: ARP monitoring has been set up, but no ARP targets have been specified.\n", +				bond->dev->name);  	}  	if (bond->dev->flags & IFF_UP) {  		/* If the interface is up, we may need to fire off @@ -552,10 +558,13 @@ static ssize_t bonding_store_arp_interval(struct device *d,  		 * timer will get fired off when the open function  		 * is called.  		 */ -		cancel_delayed_work_sync(&bond->mii_work); -		queue_delayed_work(bond->wq, &bond->arp_work, 0); +		if (!new_value) { +			cancel_delayed_work_sync(&bond->arp_work); +		} else { +			cancel_delayed_work_sync(&bond->mii_work); +			queue_delayed_work(bond->wq, &bond->arp_work, 0); +		}  	} -  out:  	rtnl_unlock();  	return ret; @@ -697,7 +706,7 @@ static ssize_t bonding_store_downdelay(struct device *d,  	}  	if (new_value < 0) {  		pr_err("%s: Invalid down delay value %d not in range %d-%d; rejected.\n", -		       bond->dev->name, new_value, 1, INT_MAX); +		       bond->dev->name, new_value, 0, INT_MAX);  		ret = -EINVAL;  		goto out;  	} else { @@ -752,8 +761,8 @@ static ssize_t bonding_store_updelay(struct device *d,  		goto out;  	}  	if (new_value < 0) { -		pr_err("%s: Invalid down delay value %d not in range %d-%d; rejected.\n", -		       bond->dev->name, new_value, 1, INT_MAX); +		pr_err("%s: Invalid up delay value %d not in range %d-%d; rejected.\n", +		       bond->dev->name, new_value, 0, INT_MAX);  		ret = -EINVAL;  		goto out;  	} else { @@ -963,37 +972,37 @@ static ssize_t bonding_store_miimon(struct device *d,  	}  	if (new_value < 0) {  		pr_err("%s: Invalid miimon value %d not in range %d-%d; rejected.\n", -		       bond->dev->name, new_value, 1, INT_MAX); +		       bond->dev->name, new_value, 0, INT_MAX);  		ret = -EINVAL;  		goto out; -	} else { -		pr_info("%s: Setting MII monitoring interval to %d.\n", -			bond->dev->name, new_value); -		bond->params.miimon = new_value; -		if (bond->params.updelay) -			pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value.\n", -				bond->dev->name, -				bond->params.updelay * bond->params.miimon); -		if (bond->params.downdelay) -			pr_info("%s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value.\n", -				bond->dev->name, -				bond->params.downdelay * bond->params.miimon); -		if (bond->params.arp_interval) { -			pr_info("%s: MII monitoring cannot be used with ARP monitoring. Disabling ARP monitoring...\n", -				bond->dev->name); -			bond->params.arp_interval = 0; -			if (bond->params.arp_validate) { -				bond->params.arp_validate = -					BOND_ARP_VALIDATE_NONE; -			} -		} - -		if (bond->dev->flags & IFF_UP) { -			/* If the interface is up, we may need to fire off -			 * the MII timer. If the interface is down, the -			 * timer will get fired off when the open function -			 * is called. -			 */ +	} +	pr_info("%s: Setting MII monitoring interval to %d.\n", +		bond->dev->name, new_value); +	bond->params.miimon = new_value; +	if (bond->params.updelay) +		pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value.\n", +			bond->dev->name, +			bond->params.updelay * bond->params.miimon); +	if (bond->params.downdelay) +		pr_info("%s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value.\n", +			bond->dev->name, +			bond->params.downdelay * bond->params.miimon); +	if (new_value && bond->params.arp_interval) { +		pr_info("%s: MII monitoring cannot be used with ARP monitoring. Disabling ARP monitoring...\n", +			bond->dev->name); +		bond->params.arp_interval = 0; +		if (bond->params.arp_validate) +			bond->params.arp_validate = BOND_ARP_VALIDATE_NONE; +	} +	if (bond->dev->flags & IFF_UP) { +		/* If the interface is up, we may need to fire off +		 * the MII timer. If the interface is down, the +		 * timer will get fired off when the open function +		 * is called. +		 */ +		if (!new_value) { +			cancel_delayed_work_sync(&bond->mii_work); +		} else {  			cancel_delayed_work_sync(&bond->arp_work);  			queue_delayed_work(bond->wq, &bond->mii_work, 0);  		} diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c index 666891a9a24..be90debc7cd 100644 --- a/drivers/net/caif/caif_serial.c +++ b/drivers/net/caif/caif_serial.c @@ -88,11 +88,9 @@ static inline void update_tty_status(struct ser_device *ser)  {  	ser->tty_status =  		ser->tty->stopped << 5 | -		ser->tty->hw_stopped << 4 |  		ser->tty->flow_stopped << 3 |  		ser->tty->packet << 2 | -		ser->tty->port->low_latency << 1 | -		ser->tty->warned; +		ser->tty->port->low_latency << 1;  }  static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty)  { diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index f32b9fc6a98..9aa0c64c33c 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -929,6 +929,7 @@ static int mcp251x_open(struct net_device *net)  	struct mcp251x_priv *priv = netdev_priv(net);  	struct spi_device *spi = priv->spi;  	struct mcp251x_platform_data *pdata = spi->dev.platform_data; +	unsigned long flags;  	int ret;  	ret = open_candev(net); @@ -945,9 +946,14 @@ static int mcp251x_open(struct net_device *net)  	priv->tx_skb = NULL;  	priv->tx_len = 0; +	flags = IRQF_ONESHOT; +	if (pdata->irq_flags) +		flags |= pdata->irq_flags; +	else +		flags |= IRQF_TRIGGER_FALLING; +  	ret = request_threaded_irq(spi->irq, NULL, mcp251x_can_ist, -		  pdata->irq_flags ? pdata->irq_flags : IRQF_TRIGGER_FALLING, -		  DEVICE_NAME, priv); +				   flags, DEVICE_NAME, priv);  	if (ret) {  		dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);  		if (pdata->transceiver_enable) diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig index b39ca5b3ea7..ff2ba86cd4a 100644 --- a/drivers/net/can/sja1000/Kconfig +++ b/drivers/net/can/sja1000/Kconfig @@ -46,6 +46,7 @@ config CAN_EMS_PCI  config CAN_PEAK_PCMCIA  	tristate "PEAK PCAN-PC Card"  	depends on PCMCIA +	depends on HAS_IOPORT  	---help---  	  This driver is for the PCAN-PC Card PCMCIA adapter (1 or 2 channels)  	  from PEAK-System (http://www.peak-system.com). To compile this diff --git a/drivers/net/can/sja1000/ems_pcmcia.c b/drivers/net/can/sja1000/ems_pcmcia.c index 5c2f3fbbf5a..321c27e1c7f 100644 --- a/drivers/net/can/sja1000/ems_pcmcia.c +++ b/drivers/net/can/sja1000/ems_pcmcia.c @@ -316,15 +316,4 @@ static struct pcmcia_driver ems_pcmcia_driver = {  	.remove = ems_pcmcia_remove,  	.id_table = ems_pcmcia_tbl,  }; - -static int __init ems_pcmcia_init(void) -{ -	return pcmcia_register_driver(&ems_pcmcia_driver); -} -module_init(ems_pcmcia_init); - -static void __exit ems_pcmcia_exit(void) -{ -	pcmcia_unregister_driver(&ems_pcmcia_driver); -} -module_exit(ems_pcmcia_exit); +module_pcmcia_driver(ems_pcmcia_driver); diff --git a/drivers/net/can/sja1000/peak_pcmcia.c b/drivers/net/can/sja1000/peak_pcmcia.c index 1a7020ba37f..0a707f70661 100644 --- a/drivers/net/can/sja1000/peak_pcmcia.c +++ b/drivers/net/can/sja1000/peak_pcmcia.c @@ -740,15 +740,4 @@ static struct pcmcia_driver pcan_driver = {  	.remove = pcan_remove,  	.id_table = pcan_table,  }; - -static int __init pcan_init(void) -{ -	return pcmcia_register_driver(&pcan_driver); -} -module_init(pcan_init); - -static void __exit pcan_exit(void) -{ -	pcmcia_unregister_driver(&pcan_driver); -} -module_exit(pcan_exit); +module_pcmcia_driver(pcan_driver); diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c index a042cdc260d..3c18d7d000e 100644 --- a/drivers/net/can/sja1000/plx_pci.c +++ b/drivers/net/can/sja1000/plx_pci.c @@ -348,7 +348,7 @@ static inline int plx_pci_check_sja1000(const struct sja1000_priv *priv)  	 */  	if ((priv->read_reg(priv, REG_CR) & REG_CR_BASICCAN_INITIAL_MASK) ==  	    REG_CR_BASICCAN_INITIAL && -	    (priv->read_reg(priv, REG_SR) == REG_SR_BASICCAN_INITIAL) && +	    (priv->read_reg(priv, SJA1000_REG_SR) == REG_SR_BASICCAN_INITIAL) &&  	    (priv->read_reg(priv, REG_IR) == REG_IR_BASICCAN_INITIAL))  		flag = 1; @@ -360,7 +360,7 @@ static inline int plx_pci_check_sja1000(const struct sja1000_priv *priv)  	 * See states on p. 23 of the Datasheet.  	 */  	if (priv->read_reg(priv, REG_MOD) == REG_MOD_PELICAN_INITIAL && -	    priv->read_reg(priv, REG_SR) == REG_SR_PELICAN_INITIAL && +	    priv->read_reg(priv, SJA1000_REG_SR) == REG_SR_PELICAN_INITIAL &&  	    priv->read_reg(priv, REG_IR) == REG_IR_PELICAN_INITIAL)  		return flag; diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index daf4013a8fc..e4df307eaa9 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -92,7 +92,7 @@ static void sja1000_write_cmdreg(struct sja1000_priv *priv, u8 val)  	 */  	spin_lock_irqsave(&priv->cmdreg_lock, flags);  	priv->write_reg(priv, REG_CMR, val); -	priv->read_reg(priv, REG_SR); +	priv->read_reg(priv, SJA1000_REG_SR);  	spin_unlock_irqrestore(&priv->cmdreg_lock, flags);  } @@ -502,7 +502,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)  	while ((isrc = priv->read_reg(priv, REG_IR)) && (n < SJA1000_MAX_IRQ)) {  		n++; -		status = priv->read_reg(priv, REG_SR); +		status = priv->read_reg(priv, SJA1000_REG_SR);  		/* check for absent controller due to hw unplug */  		if (status == 0xFF && sja1000_is_absent(priv))  			return IRQ_NONE; @@ -530,7 +530,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)  			/* receive interrupt */  			while (status & SR_RBS) {  				sja1000_rx(dev); -				status = priv->read_reg(priv, REG_SR); +				status = priv->read_reg(priv, SJA1000_REG_SR);  				/* check for absent controller */  				if (status == 0xFF && sja1000_is_absent(priv))  					return IRQ_NONE; diff --git a/drivers/net/can/sja1000/sja1000.h b/drivers/net/can/sja1000/sja1000.h index afa99847a51..aa48e053da2 100644 --- a/drivers/net/can/sja1000/sja1000.h +++ b/drivers/net/can/sja1000/sja1000.h @@ -56,7 +56,7 @@  /* SJA1000 registers - manual section 6.4 (Pelican Mode) */  #define REG_MOD		0x00  #define REG_CMR		0x01 -#define REG_SR		0x02 +#define SJA1000_REG_SR		0x02  #define REG_IR		0x03  #define REG_IER		0x04  #define REG_ALC		0x0B diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c index 6433b81256c..8e0c4a00193 100644 --- a/drivers/net/can/sja1000/sja1000_of_platform.c +++ b/drivers/net/can/sja1000/sja1000_of_platform.c @@ -96,8 +96,8 @@ static int sja1000_ofp_probe(struct platform_device *ofdev)  	struct net_device *dev;  	struct sja1000_priv *priv;  	struct resource res; -	const u32 *prop; -	int err, irq, res_size, prop_size; +	u32 prop; +	int err, irq, res_size;  	void __iomem *base;  	err = of_address_to_resource(np, 0, &res); @@ -138,27 +138,27 @@ static int sja1000_ofp_probe(struct platform_device *ofdev)  	priv->read_reg = sja1000_ofp_read_reg;  	priv->write_reg = sja1000_ofp_write_reg; -	prop = of_get_property(np, "nxp,external-clock-frequency", &prop_size); -	if (prop && (prop_size ==  sizeof(u32))) -		priv->can.clock.freq = *prop / 2; +	err = of_property_read_u32(np, "nxp,external-clock-frequency", &prop); +	if (!err) +		priv->can.clock.freq = prop / 2;  	else  		priv->can.clock.freq = SJA1000_OFP_CAN_CLOCK; /* default */ -	prop = of_get_property(np, "nxp,tx-output-mode", &prop_size); -	if (prop && (prop_size == sizeof(u32))) -		priv->ocr |= *prop & OCR_MODE_MASK; +	err = of_property_read_u32(np, "nxp,tx-output-mode", &prop); +	if (!err) +		priv->ocr |= prop & OCR_MODE_MASK;  	else  		priv->ocr |= OCR_MODE_NORMAL; /* default */ -	prop = of_get_property(np, "nxp,tx-output-config", &prop_size); -	if (prop && (prop_size == sizeof(u32))) -		priv->ocr |= (*prop << OCR_TX_SHIFT) & OCR_TX_MASK; +	err = of_property_read_u32(np, "nxp,tx-output-config", &prop); +	if (!err) +		priv->ocr |= (prop << OCR_TX_SHIFT) & OCR_TX_MASK;  	else  		priv->ocr |= OCR_TX0_PULLDOWN; /* default */ -	prop = of_get_property(np, "nxp,clock-out-frequency", &prop_size); -	if (prop && (prop_size == sizeof(u32)) && *prop) { -		u32 divider = priv->can.clock.freq * 2 / *prop; +	err = of_property_read_u32(np, "nxp,clock-out-frequency", &prop); +	if (!err && prop) { +		u32 divider = priv->can.clock.freq * 2 / prop;  		if (divider > 1)  			priv->cdr |= divider / 2 - 1; @@ -168,8 +168,7 @@ static int sja1000_ofp_probe(struct platform_device *ofdev)  		priv->cdr |= CDR_CLK_OFF; /* default */  	} -	prop = of_get_property(np, "nxp,no-comparator-bypass", NULL); -	if (!prop) +	if (!of_property_read_bool(np, "nxp,no-comparator-bypass"))  		priv->cdr |= CDR_CBP; /* default */  	priv->irq_flags = IRQF_SHARED; diff --git a/drivers/net/can/softing/softing_cs.c b/drivers/net/can/softing/softing_cs.c index c2c0a5bb0b2..498605f833d 100644 --- a/drivers/net/can/softing/softing_cs.c +++ b/drivers/net/can/softing/softing_cs.c @@ -27,7 +27,7 @@  #include "softing_platform.h"  static int softingcs_index; -static spinlock_t softingcs_index_lock; +static DEFINE_SPINLOCK(softingcs_index_lock);  static int softingcs_reset(struct platform_device *pdev, int v);  static int softingcs_enable_irq(struct platform_device *pdev, int v); @@ -340,19 +340,7 @@ static struct pcmcia_driver softingcs_driver = {  	.remove		= softingcs_remove,  }; -static int __init softingcs_start(void) -{ -	spin_lock_init(&softingcs_index_lock); -	return pcmcia_register_driver(&softingcs_driver); -} - -static void __exit softingcs_stop(void) -{ -	pcmcia_unregister_driver(&softingcs_driver); -} - -module_init(softingcs_start); -module_exit(softingcs_stop); +module_pcmcia_driver(softingcs_driver);  MODULE_DESCRIPTION("softing CANcard driver"  		", links PCMCIA card to softing driver"); diff --git a/drivers/net/ethernet/3com/3c574_cs.c b/drivers/net/ethernet/3com/3c574_cs.c index ffd8de28a76..6fc994fa4ab 100644 --- a/drivers/net/ethernet/3com/3c574_cs.c +++ b/drivers/net/ethernet/3com/3c574_cs.c @@ -1165,16 +1165,4 @@ static struct pcmcia_driver tc574_driver = {  	.suspend	= tc574_suspend,  	.resume		= tc574_resume,  }; - -static int __init init_tc574(void) -{ -	return pcmcia_register_driver(&tc574_driver); -} - -static void __exit exit_tc574(void) -{ -	pcmcia_unregister_driver(&tc574_driver); -} - -module_init(init_tc574); -module_exit(exit_tc574); +module_pcmcia_driver(tc574_driver); diff --git a/drivers/net/ethernet/3com/3c589_cs.c b/drivers/net/ethernet/3com/3c589_cs.c index a556c01e011..078480aaa16 100644 --- a/drivers/net/ethernet/3com/3c589_cs.c +++ b/drivers/net/ethernet/3com/3c589_cs.c @@ -928,16 +928,4 @@ static struct pcmcia_driver tc589_driver = {  	.suspend	= tc589_suspend,  	.resume		= tc589_resume,  }; - -static int __init init_tc589(void) -{ -	return pcmcia_register_driver(&tc589_driver); -} - -static void __exit exit_tc589(void) -{ -	pcmcia_unregister_driver(&tc589_driver); -} - -module_init(init_tc589); -module_exit(exit_tc589); +module_pcmcia_driver(tc589_driver); diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index cab306a9888..e1d26433d61 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -828,7 +828,7 @@ static int ax_probe(struct platform_device *pdev)  	struct ei_device *ei_local;  	struct ax_device *ax;  	struct resource *irq, *mem, *mem2; -	resource_size_t mem_size, mem2_size = 0; +	unsigned long mem_size, mem2_size = 0;  	int ret = 0;  	dev = ax__alloc_ei_netdev(sizeof(struct ax_device)); diff --git a/drivers/net/ethernet/8390/axnet_cs.c b/drivers/net/ethernet/8390/axnet_cs.c index e1b3941bd14..d801c1410fb 100644 --- a/drivers/net/ethernet/8390/axnet_cs.c +++ b/drivers/net/ethernet/8390/axnet_cs.c @@ -728,19 +728,7 @@ static struct pcmcia_driver axnet_cs_driver = {  	.suspend	= axnet_suspend,  	.resume		= axnet_resume,  }; - -static int __init init_axnet_cs(void) -{ -	return pcmcia_register_driver(&axnet_cs_driver); -} - -static void __exit exit_axnet_cs(void) -{ -	pcmcia_unregister_driver(&axnet_cs_driver); -} - -module_init(init_axnet_cs); -module_exit(exit_axnet_cs); +module_pcmcia_driver(axnet_cs_driver);  /*====================================================================*/ diff --git a/drivers/net/ethernet/8390/pcnet_cs.c b/drivers/net/ethernet/8390/pcnet_cs.c index de1af0bfed4..46c5aadaca8 100644 --- a/drivers/net/ethernet/8390/pcnet_cs.c +++ b/drivers/net/ethernet/8390/pcnet_cs.c @@ -1694,16 +1694,4 @@ static struct pcmcia_driver pcnet_driver = {  	.suspend	= pcnet_suspend,  	.resume		= pcnet_resume,  }; - -static int __init init_pcnet_cs(void) -{ -    return pcmcia_register_driver(&pcnet_driver); -} - -static void __exit exit_pcnet_cs(void) -{ -    pcmcia_unregister_driver(&pcnet_driver); -} - -module_init(init_pcnet_cs); -module_exit(exit_pcnet_cs); +module_pcmcia_driver(pcnet_driver); diff --git a/drivers/net/ethernet/amd/nmclan_cs.c b/drivers/net/ethernet/amd/nmclan_cs.c index 9f59bf63514..d4ed89130c5 100644 --- a/drivers/net/ethernet/amd/nmclan_cs.c +++ b/drivers/net/ethernet/amd/nmclan_cs.c @@ -1508,16 +1508,4 @@ static struct pcmcia_driver nmclan_cs_driver = {  	.suspend	= nmclan_suspend,  	.resume		= nmclan_resume,  }; - -static int __init init_nmclan_cs(void) -{ -	return pcmcia_register_driver(&nmclan_cs_driver); -} - -static void __exit exit_nmclan_cs(void) -{ -	pcmcia_unregister_driver(&nmclan_cs_driver); -} - -module_init(init_nmclan_cs); -module_exit(exit_nmclan_cs); +module_pcmcia_driver(nmclan_cs_driver); diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e.h b/drivers/net/ethernet/atheros/atl1e/atl1e.h index 829b5ad71d0..b5fd934585e 100644 --- a/drivers/net/ethernet/atheros/atl1e/atl1e.h +++ b/drivers/net/ethernet/atheros/atl1e/atl1e.h @@ -186,7 +186,7 @@ struct atl1e_tpd_desc {  /* how about 0x2000 */  #define MAX_TX_BUF_LEN      0x2000  #define MAX_TX_BUF_SHIFT    13 -/*#define MAX_TX_BUF_LEN  0x3000 */ +#define MAX_TSO_SEG_SIZE    0x3c00  /* rrs word 1 bit 0:31 */  #define RRS_RX_CSUM_MASK	0xFFFF @@ -438,7 +438,6 @@ struct atl1e_adapter {  	struct atl1e_hw        hw;  	struct atl1e_hw_stats  hw_stats; -	bool have_msi;  	u32 wol;  	u16 link_speed;  	u16 link_duplex; diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c index 92f4734f860..ac25f05ff68 100644 --- a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c +++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c @@ -1849,34 +1849,19 @@ static void atl1e_free_irq(struct atl1e_adapter *adapter)  	struct net_device *netdev = adapter->netdev;  	free_irq(adapter->pdev->irq, netdev); - -	if (adapter->have_msi) -		pci_disable_msi(adapter->pdev);  }  static int atl1e_request_irq(struct atl1e_adapter *adapter)  {  	struct pci_dev    *pdev   = adapter->pdev;  	struct net_device *netdev = adapter->netdev; -	int flags = 0;  	int err = 0; -	adapter->have_msi = true; -	err = pci_enable_msi(pdev); -	if (err) { -		netdev_dbg(netdev, -			   "Unable to allocate MSI interrupt Error: %d\n", err); -		adapter->have_msi = false; -	} - -	if (!adapter->have_msi) -		flags |= IRQF_SHARED; -	err = request_irq(pdev->irq, atl1e_intr, flags, netdev->name, netdev); +	err = request_irq(pdev->irq, atl1e_intr, IRQF_SHARED, netdev->name, +			  netdev);  	if (err) {  		netdev_dbg(adapter->netdev,  			   "Unable to allocate interrupt Error: %d\n", err); -		if (adapter->have_msi) -			pci_disable_msi(pdev);  		return err;  	}  	netdev_dbg(netdev, "atl1e_request_irq OK\n"); @@ -2344,6 +2329,7 @@ static int atl1e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	INIT_WORK(&adapter->reset_task, atl1e_reset_task);  	INIT_WORK(&adapter->link_chg_task, atl1e_link_chg_task); +	netif_set_gso_max_size(netdev, MAX_TSO_SEG_SIZE);  	err = register_netdev(netdev);  	if (err) {  		netdev_err(netdev, "register netdevice failed\n"); diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index 639049d7e92..da5f4397f87 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -301,12 +301,16 @@ static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring,  			bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n",  				  ring->start);  		} else { +			/* Omit CRC. */ +			len -= ETH_FCS_LEN; +  			new_skb = netdev_alloc_skb_ip_align(bgmac->net_dev, len);  			if (new_skb) {  				skb_put(new_skb, len);  				skb_copy_from_linear_data_offset(skb, BGMAC_RX_FRAME_OFFSET,  								 new_skb->data,  								 len); +				skb_checksum_none_assert(skb);  				new_skb->protocol =  					eth_type_trans(new_skb, bgmac->net_dev);  				netif_receive_skb(new_skb); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index ecac04a3687..57619dd4a92 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -2614,6 +2614,9 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)  			}  		} +		/* initialize FW coalescing state machines in RAM */ +		bnx2x_update_coalesce(bp); +  		/* setup the leading queue */  		rc = bnx2x_setup_leading(bp);  		if (rc) { @@ -2760,6 +2763,7 @@ load_error2:  	bp->port.pmf = 0;  load_error1:  	bnx2x_napi_disable(bp); +	bnx2x_del_all_napi(bp);  	/* clear pf_load status, as it was already set */  	if (IS_PF(bp)) @@ -3142,7 +3146,7 @@ static inline __le16 bnx2x_csum_fix(unsigned char *t_header, u16 csum, s8 fix)  		tsum = ~csum_fold(csum_add((__force __wsum) csum,  				  csum_partial(t_header, -fix, 0))); -	return bswab16(csum); +	return bswab16(tsum);  }  static inline u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb) @@ -4579,11 +4583,11 @@ static void storm_memset_hc_disable(struct bnx2x *bp, u8 port,  	u32 enable_flag = disable ? 0 : (1 << HC_INDEX_DATA_HC_ENABLED_SHIFT);  	u32 addr = BAR_CSTRORM_INTMEM +  		   CSTORM_STATUS_BLOCK_DATA_FLAGS_OFFSET(fw_sb_id, sb_index); -	u16 flags = REG_RD16(bp, addr); +	u8 flags = REG_RD8(bp, addr);  	/* clear and set */  	flags &= ~HC_INDEX_DATA_HC_ENABLED;  	flags |= enable_flag; -	REG_WR16(bp, addr, flags); +	REG_WR8(bp, addr, flags);  	DP(NETIF_MSG_IFUP,  	   "port %x fw_sb_id %d sb_index %d disable %d\n",  	   port, fw_sb_id, sb_index, disable); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c index c633402cbd2..4b077a7f16a 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c @@ -2139,12 +2139,12 @@ static u8 bnx2x_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap)  			break;  		default:  			BNX2X_ERR("Non valid capability ID\n"); -			rval = -EINVAL; +			rval = 1;  			break;  		}  	} else {  		DP(BNX2X_MSG_DCB, "DCB disabled\n"); -		rval = -EINVAL; +		rval = 1;  	}  	DP(BNX2X_MSG_DCB, "capid %d:%x\n", capid, *cap); @@ -2170,12 +2170,12 @@ static int bnx2x_dcbnl_get_numtcs(struct net_device *netdev, int tcid, u8 *num)  			break;  		default:  			BNX2X_ERR("Non valid TC-ID\n"); -			rval = -EINVAL; +			rval = 1;  			break;  		}  	} else {  		DP(BNX2X_MSG_DCB, "DCB disabled\n"); -		rval = -EINVAL; +		rval = 1;  	}  	return rval; @@ -2188,7 +2188,7 @@ static int bnx2x_dcbnl_set_numtcs(struct net_device *netdev, int tcid, u8 num)  	return -EINVAL;  } -static u8  bnx2x_dcbnl_get_pfc_state(struct net_device *netdev) +static u8 bnx2x_dcbnl_get_pfc_state(struct net_device *netdev)  {  	struct bnx2x *bp = netdev_priv(netdev);  	DP(BNX2X_MSG_DCB, "state = %d\n", bp->dcbx_local_feat.pfc.enabled); @@ -2390,12 +2390,12 @@ static u8 bnx2x_dcbnl_get_featcfg(struct net_device *netdev, int featid,  			break;  		default:  			BNX2X_ERR("Non valid featrue-ID\n"); -			rval = -EINVAL; +			rval = 1;  			break;  		}  	} else {  		DP(BNX2X_MSG_DCB, "DCB disabled\n"); -		rval = -EINVAL; +		rval = 1;  	}  	return rval; @@ -2431,12 +2431,12 @@ static u8 bnx2x_dcbnl_set_featcfg(struct net_device *netdev, int featid,  			break;  		default:  			BNX2X_ERR("Non valid featrue-ID\n"); -			rval = -EINVAL; +			rval = 1;  			break;  		}  	} else {  		DP(BNX2X_MSG_DCB, "dcbnl call not valid\n"); -		rval = -EINVAL; +		rval = 1;  	}  	return rval; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index 9a674b14b40..edfa67adf2f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -281,6 +281,8 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)  			cmd->lp_advertising |= ADVERTISED_2500baseX_Full;  		if (status & LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE)  			cmd->lp_advertising |= ADVERTISED_10000baseT_Full; +		if (status & LINK_STATUS_LINK_PARTNER_20GXFD_CAPABLE) +			cmd->lp_advertising |= ADVERTISED_20000baseKR2_Full;  	}  	cmd->maxtxpkt = 0; @@ -463,6 +465,10 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)  						ADVERTISED_10000baseKR_Full))  				bp->link_params.speed_cap_mask[cfg_idx] |=  					PORT_HW_CFG_SPEED_CAPABILITY_D0_10G; + +			if (cmd->advertising & ADVERTISED_20000baseKR2_Full) +				bp->link_params.speed_cap_mask[cfg_idx] |= +					PORT_HW_CFG_SPEED_CAPABILITY_D0_20G;  		}  	} else { /* forced speed */  		/* advertise the requested speed and duplex if supported */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 1663e0b6b5a..0283f343b0d 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -8647,7 +8647,9 @@ void bnx2x_handle_module_detect_int(struct link_params *params)  						MDIO_WC_DEVAD,  						MDIO_WC_REG_DIGITAL5_MISC6,  						&rx_tx_in_reset); -				if (!rx_tx_in_reset) { +				if ((!rx_tx_in_reset) && +				    (params->link_flags & +				     PHY_INITIALIZED)) {  					bnx2x_warpcore_reset_lane(bp, phy, 1);  					bnx2x_warpcore_config_sfi(phy, params);  					bnx2x_warpcore_reset_lane(bp, phy, 0); @@ -10422,6 +10424,28 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,  					 MDIO_PMA_DEVAD,  					 MDIO_PMA_REG_8481_LED1_MASK,  					 0x0); +			if (phy->type == +			    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834) { +				/* Disable MI_INT interrupt before setting LED4 +				 * source to constant off. +				 */ +				if (REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + +					   params->port*4) & +				    NIG_MASK_MI_INT) { +					params->link_flags |= +					LINK_FLAGS_INT_DISABLED; + +					bnx2x_bits_dis( +						bp, +						NIG_REG_MASK_INTERRUPT_PORT0 + +						params->port*4, +						NIG_MASK_MI_INT); +				} +				bnx2x_cl45_write(bp, phy, +						 MDIO_PMA_DEVAD, +						 MDIO_PMA_REG_8481_SIGNAL_MASK, +						 0x0); +			}  		}  		break;  	case LED_MODE_ON: @@ -10468,6 +10492,28 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,  					 MDIO_PMA_DEVAD,  					 MDIO_PMA_REG_8481_LED1_MASK,  					 0x20); +			if (phy->type == +			    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834) { +				/* Disable MI_INT interrupt before setting LED4 +				 * source to constant on. +				 */ +				if (REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + +					   params->port*4) & +				    NIG_MASK_MI_INT) { +					params->link_flags |= +					LINK_FLAGS_INT_DISABLED; + +					bnx2x_bits_dis( +						bp, +						NIG_REG_MASK_INTERRUPT_PORT0 + +						params->port*4, +						NIG_MASK_MI_INT); +				} +				bnx2x_cl45_write(bp, phy, +						 MDIO_PMA_DEVAD, +						 MDIO_PMA_REG_8481_SIGNAL_MASK, +						 0x20); +			}  		}  		break; @@ -10532,6 +10578,22 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,  					 MDIO_PMA_DEVAD,  					 MDIO_PMA_REG_8481_LINK_SIGNAL,  					 val); +			if (phy->type == +			    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834) { +				/* Restore LED4 source to external link, +				 * and re-enable interrupts. +				 */ +				bnx2x_cl45_write(bp, phy, +						 MDIO_PMA_DEVAD, +						 MDIO_PMA_REG_8481_SIGNAL_MASK, +						 0x40); +				if (params->link_flags & +				    LINK_FLAGS_INT_DISABLED) { +					bnx2x_link_int_enable(params); +					params->link_flags &= +						~LINK_FLAGS_INT_DISABLED; +				} +			}  		}  		break;  	} @@ -11791,6 +11853,8 @@ static int bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,  			phy->media_type = ETH_PHY_KR;  			phy->flags |= FLAGS_WC_DUAL_MODE;  			phy->supported &= (SUPPORTED_20000baseKR2_Full | +					   SUPPORTED_10000baseT_Full | +					   SUPPORTED_1000baseT_Full |  					   SUPPORTED_Autoneg |  					   SUPPORTED_FIBRE |  					   SUPPORTED_Pause | @@ -12465,6 +12529,8 @@ int bnx2x_phy_init(struct link_params *params, struct link_vars *vars)  	vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;  	vars->mac_type = MAC_TYPE_NONE;  	vars->phy_flags = 0; +	vars->check_kr2_recovery_cnt = 0; +	params->link_flags = PHY_INITIALIZED;  	/* Driver opens NIG-BRB filters */  	bnx2x_set_rx_filter(params, 1);  	/* Check if link flap can be avoided */ @@ -12629,6 +12695,7 @@ int bnx2x_lfa_reset(struct link_params *params,  	struct bnx2x *bp = params->bp;  	vars->link_up = 0;  	vars->phy_flags = 0; +	params->link_flags &= ~PHY_INITIALIZED;  	if (!params->lfa_base)  		return bnx2x_link_reset(params, vars, 1);  	/* @@ -13349,6 +13416,7 @@ static void bnx2x_disable_kr2(struct link_params *params,  	vars->link_attr_sync &= ~LINK_ATTR_SYNC_KR2_ENABLE;  	bnx2x_update_link_attr(params, vars->link_attr_sync); +	vars->check_kr2_recovery_cnt = CHECK_KR2_RECOVERY_CNT;  	/* Restart AN on leading lane */  	bnx2x_warpcore_restart_AN_KR(phy, params);  } @@ -13369,11 +13437,24 @@ static void bnx2x_check_kr2_wa(struct link_params *params,  {  	struct bnx2x *bp = params->bp;  	u16 base_page, next_page, not_kr2_device, lane; -	int sigdet = bnx2x_warpcore_get_sigdet(phy, params); +	int sigdet; +	/* Once KR2 was disabled, wait 5 seconds before checking KR2 recovery +	 * since some switches tend to reinit the AN process and clear the +	 * advertised BP/NP after ~2 seconds causing the KR2 to be disabled +	 * and recovered many times +	 */ +	if (vars->check_kr2_recovery_cnt > 0) { +		vars->check_kr2_recovery_cnt--; +		return; +	} + +	sigdet = bnx2x_warpcore_get_sigdet(phy, params);  	if (!sigdet) { -		if (!(vars->link_attr_sync & LINK_ATTR_SYNC_KR2_ENABLE)) +		if (!(vars->link_attr_sync & LINK_ATTR_SYNC_KR2_ENABLE)) {  			bnx2x_kr2_recovery(params, vars, phy); +			DP(NETIF_MSG_LINK, "No sigdet\n"); +		}  		return;  	} @@ -13437,7 +13518,7 @@ void bnx2x_period_func(struct link_params *params, struct link_vars *vars)  		struct bnx2x_phy *phy = ¶ms->phy[INT_PHY];  		bnx2x_set_aer_mmd(params, phy);  		if ((phy->supported & SUPPORTED_20000baseKR2_Full) && -		    (phy->speed_cap_mask & SPEED_20000)) +		    (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_20G))  			bnx2x_check_kr2_wa(params, vars, phy);  		bnx2x_check_over_curr(params, vars);  		if (vars->rx_tx_asic_rst) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h index d25c7d79787..56c2aae4e2c 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h @@ -307,7 +307,9 @@ struct link_params {  	struct bnx2x *bp;  	u16 req_fc_auto_adv; /* Should be set to TX / BOTH when  				req_flow_ctrl is set to AUTO */ -	u16 rsrv1; +	u16 link_flags; +#define LINK_FLAGS_INT_DISABLED		(1<<0) +#define PHY_INITIALIZED		(1<<1)  	u32 lfa_base;  }; @@ -341,7 +343,8 @@ struct link_vars {  	u32 link_status;  	u32 eee_status;  	u8 fault_detected; -	u8 rsrv1; +	u8 check_kr2_recovery_cnt; +#define CHECK_KR2_RECOVERY_CNT	5  	u16 periodic_flags;  #define PERIODIC_FLAGS_LINK_EVENT	0x0001 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index e81a747ea8c..c50696b396f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -4947,7 +4947,7 @@ static void bnx2x_after_function_update(struct bnx2x *bp)  				  q);  	} -	if (!NO_FCOE(bp)) { +	if (!NO_FCOE(bp) && CNIC_ENABLED(bp)) {  		fp = &bp->fp[FCOE_IDX(bp)];  		queue_params.q_obj = &bnx2x_sp_obj(bp, fp).q_obj; @@ -9878,6 +9878,10 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)  				REG_RD(bp, NIG_REG_NIG_INT_STS_CLR_0);  			}  		} +		if (!CHIP_IS_E1x(bp)) +			/* block FW from writing to host */ +			REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER, 0); +  		/* wait until BRB is empty */  		tmp_reg = REG_RD(bp, BRB1_REG_NUM_OF_FULL_BLOCKS);  		while (timer_count) { @@ -13354,6 +13358,7 @@ static int bnx2x_unregister_cnic(struct net_device *dev)  	RCU_INIT_POINTER(bp->cnic_ops, NULL);  	mutex_unlock(&bp->cnic_mutex);  	synchronize_rcu(); +	bp->cnic_enabled = false;  	kfree(bp->cnic_kwq);  	bp->cnic_kwq = NULL; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h index 364e37ecbc5..198f6f1c9ad 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h @@ -459,8 +459,9 @@ struct bnx2x_fw_port_stats_old {  #define UPDATE_QSTAT(s, t) \  	do { \ -		qstats->t##_hi = qstats_old->t##_hi + le32_to_cpu(s.hi); \  		qstats->t##_lo = qstats_old->t##_lo + le32_to_cpu(s.lo); \ +		qstats->t##_hi = qstats_old->t##_hi + le32_to_cpu(s.hi) \ +			+ ((qstats->t##_lo < qstats_old->t##_lo) ? 1 : 0); \  	} while (0)  #define UPDATE_QSTAT_OLD(f) \ diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index fdb9b565541..17a972734ba 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -1869,6 +1869,8 @@ static void tg3_link_report(struct tg3 *tp)  		tg3_ump_link_report(tp);  	} + +	tp->link_up = netif_carrier_ok(tp->dev);  }  static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl) @@ -2522,12 +2524,6 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp)  	return err;  } -static void tg3_carrier_on(struct tg3 *tp) -{ -	netif_carrier_on(tp->dev); -	tp->link_up = true; -} -  static void tg3_carrier_off(struct tg3 *tp)  {  	netif_carrier_off(tp->dev); @@ -2553,7 +2549,7 @@ static int tg3_phy_reset(struct tg3 *tp)  		return -EBUSY;  	if (netif_running(tp->dev) && tp->link_up) { -		tg3_carrier_off(tp); +		netif_carrier_off(tp->dev);  		tg3_link_report(tp);  	} @@ -4134,6 +4130,14 @@ static void tg3_phy_copper_begin(struct tg3 *tp)  		tp->link_config.active_speed = tp->link_config.speed;  		tp->link_config.active_duplex = tp->link_config.duplex; +		if (tg3_asic_rev(tp) == ASIC_REV_5714) { +			/* With autoneg disabled, 5715 only links up when the +			 * advertisement register has the configured speed +			 * enabled. +			 */ +			tg3_writephy(tp, MII_ADVERTISE, ADVERTISE_ALL); +		} +  		bmcr = 0;  		switch (tp->link_config.speed) {  		default: @@ -4262,9 +4266,9 @@ static bool tg3_test_and_report_link_chg(struct tg3 *tp, int curr_link_up)  {  	if (curr_link_up != tp->link_up) {  		if (curr_link_up) { -			tg3_carrier_on(tp); +			netif_carrier_on(tp->dev);  		} else { -			tg3_carrier_off(tp); +			netif_carrier_off(tp->dev);  			if (tp->phy_flags & TG3_PHYFLG_MII_SERDES)  				tp->phy_flags &= ~TG3_PHYFLG_PARALLEL_DETECT;  		} @@ -14600,8 +14604,11 @@ static void tg3_read_vpd(struct tg3 *tp)  		if (j + len > block_end)  			goto partno; -		memcpy(tp->fw_ver, &vpd_data[j], len); -		strncat(tp->fw_ver, " bc ", vpdlen - len - 1); +		if (len >= sizeof(tp->fw_ver)) +			len = sizeof(tp->fw_ver) - 1; +		memset(tp->fw_ver, 0, sizeof(tp->fw_ver)); +		snprintf(tp->fw_ver, sizeof(tp->fw_ver), "%.*s bc ", len, +			 &vpd_data[j]);  	}  partno: diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c index a170065b597..b0ebc9f6d55 100644 --- a/drivers/net/ethernet/calxeda/xgmac.c +++ b/drivers/net/ethernet/calxeda/xgmac.c @@ -163,6 +163,7 @@  #define XGMAC_FLOW_CTRL_FCB_BPA	0x00000001	/* Flow Control Busy ... */  /* XGMAC_INT_STAT reg */ +#define XGMAC_INT_STAT_PMTIM	0x00800000	/* PMT Interrupt Mask */  #define XGMAC_INT_STAT_PMT	0x0080		/* PMT Interrupt Status */  #define XGMAC_INT_STAT_LPI	0x0040		/* LPI Interrupt Status */ @@ -960,6 +961,9 @@ static int xgmac_hw_init(struct net_device *dev)  	writel(DMA_INTR_DEFAULT_MASK, ioaddr + XGMAC_DMA_STATUS);  	writel(DMA_INTR_DEFAULT_MASK, ioaddr + XGMAC_DMA_INTR_ENA); +	/* Mask power mgt interrupt */ +	writel(XGMAC_INT_STAT_PMTIM, ioaddr + XGMAC_INT_STAT); +  	/* XGMAC requires AXI bus init. This is a 'magic number' for now */  	writel(0x0077000E, ioaddr + XGMAC_DMA_AXI_BUS); @@ -1141,6 +1145,9 @@ static int xgmac_rx(struct xgmac_priv *priv, int limit)  		struct sk_buff *skb;  		int frame_len; +		if (!dma_ring_cnt(priv->rx_head, priv->rx_tail, DMA_RX_RING_SZ)) +			break; +  		entry = priv->rx_tail;  		p = priv->dma_rx + entry;  		if (desc_get_owner(p)) @@ -1825,7 +1832,7 @@ static void xgmac_pmt(void __iomem *ioaddr, unsigned long mode)  	unsigned int pmt = 0;  	if (mode & WAKE_MAGIC) -		pmt |= XGMAC_PMT_POWERDOWN | XGMAC_PMT_MAGIC_PKT; +		pmt |= XGMAC_PMT_POWERDOWN | XGMAC_PMT_MAGIC_PKT_EN;  	if (mode & WAKE_UCAST)  		pmt |= XGMAC_PMT_POWERDOWN | XGMAC_PMT_GLBL_UNICAST; diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 4ce62031f62..8049268ce0f 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -497,8 +497,9 @@ int t4_memory_write(struct adapter *adap, int mtype, u32 addr, u32 len,  }  #define EEPROM_STAT_ADDR   0x7bfc -#define VPD_BASE           0  #define VPD_LEN            512 +#define VPD_BASE           0x400 +#define VPD_BASE_OLD       0  /**   *	t4_seeprom_wp - enable/disable EEPROM write protection @@ -524,7 +525,7 @@ int t4_seeprom_wp(struct adapter *adapter, bool enable)  int get_vpd_params(struct adapter *adapter, struct vpd_params *p)  {  	u32 cclk_param, cclk_val; -	int i, ret; +	int i, ret, addr;  	int ec, sn;  	u8 *vpd, csum;  	unsigned int vpdr_len, kw_offset, id_len; @@ -533,7 +534,12 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p)  	if (!vpd)  		return -ENOMEM; -	ret = pci_read_vpd(adapter->pdev, VPD_BASE, VPD_LEN, vpd); +	ret = pci_read_vpd(adapter->pdev, VPD_BASE, sizeof(u32), vpd); +	if (ret < 0) +		goto out; +	addr = *vpd == 0x82 ? VPD_BASE : VPD_BASE_OLD; + +	ret = pci_read_vpd(adapter->pdev, addr, VPD_LEN, vpd);  	if (ret < 0)  		goto out; diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index 8cdf02503d1..9eada8e8607 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -257,6 +257,107 @@ static void dm9000_dumpblk_32bit(void __iomem *reg, int count)  		tmp = readl(reg);  } +/* + * Sleep, either by using msleep() or if we are suspending, then + * use mdelay() to sleep. + */ +static void dm9000_msleep(board_info_t *db, unsigned int ms) +{ +	if (db->in_suspend) +		mdelay(ms); +	else +		msleep(ms); +} + +/* Read a word from phyxcer */ +static int +dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg) +{ +	board_info_t *db = netdev_priv(dev); +	unsigned long flags; +	unsigned int reg_save; +	int ret; + +	mutex_lock(&db->addr_lock); + +	spin_lock_irqsave(&db->lock, flags); + +	/* Save previous register address */ +	reg_save = readb(db->io_addr); + +	/* Fill the phyxcer register into REG_0C */ +	iow(db, DM9000_EPAR, DM9000_PHY | reg); + +	/* Issue phyxcer read command */ +	iow(db, DM9000_EPCR, EPCR_ERPRR | EPCR_EPOS); + +	writeb(reg_save, db->io_addr); +	spin_unlock_irqrestore(&db->lock, flags); + +	dm9000_msleep(db, 1);		/* Wait read complete */ + +	spin_lock_irqsave(&db->lock, flags); +	reg_save = readb(db->io_addr); + +	iow(db, DM9000_EPCR, 0x0);	/* Clear phyxcer read command */ + +	/* The read data keeps on REG_0D & REG_0E */ +	ret = (ior(db, DM9000_EPDRH) << 8) | ior(db, DM9000_EPDRL); + +	/* restore the previous address */ +	writeb(reg_save, db->io_addr); +	spin_unlock_irqrestore(&db->lock, flags); + +	mutex_unlock(&db->addr_lock); + +	dm9000_dbg(db, 5, "phy_read[%02x] -> %04x\n", reg, ret); +	return ret; +} + +/* Write a word to phyxcer */ +static void +dm9000_phy_write(struct net_device *dev, +		 int phyaddr_unused, int reg, int value) +{ +	board_info_t *db = netdev_priv(dev); +	unsigned long flags; +	unsigned long reg_save; + +	dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value); +	mutex_lock(&db->addr_lock); + +	spin_lock_irqsave(&db->lock, flags); + +	/* Save previous register address */ +	reg_save = readb(db->io_addr); + +	/* Fill the phyxcer register into REG_0C */ +	iow(db, DM9000_EPAR, DM9000_PHY | reg); + +	/* Fill the written data into REG_0D & REG_0E */ +	iow(db, DM9000_EPDRL, value); +	iow(db, DM9000_EPDRH, value >> 8); + +	/* Issue phyxcer write command */ +	iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW); + +	writeb(reg_save, db->io_addr); +	spin_unlock_irqrestore(&db->lock, flags); + +	dm9000_msleep(db, 1);		/* Wait write complete */ + +	spin_lock_irqsave(&db->lock, flags); +	reg_save = readb(db->io_addr); + +	iow(db, DM9000_EPCR, 0x0);	/* Clear phyxcer write command */ + +	/* restore the previous address */ +	writeb(reg_save, db->io_addr); + +	spin_unlock_irqrestore(&db->lock, flags); +	mutex_unlock(&db->addr_lock); +} +  /* dm9000_set_io   *   * select the specified set of io routines to use with the @@ -795,6 +896,9 @@ dm9000_init_dm9000(struct net_device *dev)  	iow(db, DM9000_GPCR, GPCR_GEP_CNTL);	/* Let GPIO0 output */ +	dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET */ +	dm9000_phy_write(dev, 0, MII_DM_DSPCR, DSPCR_INIT_PARAM); /* Init */ +  	ncr = (db->flags & DM9000_PLATF_EXT_PHY) ? NCR_EXT_PHY : 0;  	/* if wol is needed, then always set NCR_WAKEEN otherwise we end @@ -1201,109 +1305,6 @@ dm9000_open(struct net_device *dev)  	return 0;  } -/* - * Sleep, either by using msleep() or if we are suspending, then - * use mdelay() to sleep. - */ -static void dm9000_msleep(board_info_t *db, unsigned int ms) -{ -	if (db->in_suspend) -		mdelay(ms); -	else -		msleep(ms); -} - -/* - *   Read a word from phyxcer - */ -static int -dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg) -{ -	board_info_t *db = netdev_priv(dev); -	unsigned long flags; -	unsigned int reg_save; -	int ret; - -	mutex_lock(&db->addr_lock); - -	spin_lock_irqsave(&db->lock,flags); - -	/* Save previous register address */ -	reg_save = readb(db->io_addr); - -	/* Fill the phyxcer register into REG_0C */ -	iow(db, DM9000_EPAR, DM9000_PHY | reg); - -	iow(db, DM9000_EPCR, EPCR_ERPRR | EPCR_EPOS);	/* Issue phyxcer read command */ - -	writeb(reg_save, db->io_addr); -	spin_unlock_irqrestore(&db->lock,flags); - -	dm9000_msleep(db, 1);		/* Wait read complete */ - -	spin_lock_irqsave(&db->lock,flags); -	reg_save = readb(db->io_addr); - -	iow(db, DM9000_EPCR, 0x0);	/* Clear phyxcer read command */ - -	/* The read data keeps on REG_0D & REG_0E */ -	ret = (ior(db, DM9000_EPDRH) << 8) | ior(db, DM9000_EPDRL); - -	/* restore the previous address */ -	writeb(reg_save, db->io_addr); -	spin_unlock_irqrestore(&db->lock,flags); - -	mutex_unlock(&db->addr_lock); - -	dm9000_dbg(db, 5, "phy_read[%02x] -> %04x\n", reg, ret); -	return ret; -} - -/* - *   Write a word to phyxcer - */ -static void -dm9000_phy_write(struct net_device *dev, -		 int phyaddr_unused, int reg, int value) -{ -	board_info_t *db = netdev_priv(dev); -	unsigned long flags; -	unsigned long reg_save; - -	dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value); -	mutex_lock(&db->addr_lock); - -	spin_lock_irqsave(&db->lock,flags); - -	/* Save previous register address */ -	reg_save = readb(db->io_addr); - -	/* Fill the phyxcer register into REG_0C */ -	iow(db, DM9000_EPAR, DM9000_PHY | reg); - -	/* Fill the written data into REG_0D & REG_0E */ -	iow(db, DM9000_EPDRL, value); -	iow(db, DM9000_EPDRH, value >> 8); - -	iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW);	/* Issue phyxcer write command */ - -	writeb(reg_save, db->io_addr); -	spin_unlock_irqrestore(&db->lock, flags); - -	dm9000_msleep(db, 1);		/* Wait write complete */ - -	spin_lock_irqsave(&db->lock,flags); -	reg_save = readb(db->io_addr); - -	iow(db, DM9000_EPCR, 0x0);	/* Clear phyxcer write command */ - -	/* restore the previous address */ -	writeb(reg_save, db->io_addr); - -	spin_unlock_irqrestore(&db->lock, flags); -	mutex_unlock(&db->addr_lock); -} -  static void  dm9000_shutdown(struct net_device *dev)  { @@ -1502,7 +1503,12 @@ dm9000_probe(struct platform_device *pdev)  	db->flags |= DM9000_PLATF_SIMPLE_PHY;  #endif -	dm9000_reset(db); +	/* Fixing bug on dm9000_probe, takeover dm9000_reset(db), +	 * Need 'NCR_MAC_LBK' bit to indeed stable our DM9000 fifo +	 * while probe stage. +	 */ + +	iow(db, DM9000_NCR, NCR_MAC_LBK | NCR_RST);  	/* try multiple times, DM9000 sometimes gets the read wrong */  	for (i = 0; i < 8; i++) { diff --git a/drivers/net/ethernet/davicom/dm9000.h b/drivers/net/ethernet/davicom/dm9000.h index 55688bd1a3e..9ce058adaba 100644 --- a/drivers/net/ethernet/davicom/dm9000.h +++ b/drivers/net/ethernet/davicom/dm9000.h @@ -69,7 +69,9 @@  #define NCR_WAKEEN          (1<<6)  #define NCR_FCOL            (1<<4)  #define NCR_FDX             (1<<3) -#define NCR_LBK             (3<<1) + +#define NCR_RESERVED        (3<<1) +#define NCR_MAC_LBK         (1<<1)  #define NCR_RST	            (1<<0)  #define NSR_SPEED           (1<<7) @@ -167,5 +169,12 @@  #define ISR_LNKCHNG		(1<<5)  #define ISR_UNDERRUN		(1<<4) +/* Davicom MII registers. + */ + +#define MII_DM_DSPCR		0x1b    /* DSP Control Register */ + +#define DSPCR_INIT_PARAM	0xE100	/* DSP init parameter */ +  #endif /* _DM9000X_H_ */ diff --git a/drivers/net/ethernet/dec/tulip/Kconfig b/drivers/net/ethernet/dec/tulip/Kconfig index 0c37fb2cc86..1df33c799c0 100644 --- a/drivers/net/ethernet/dec/tulip/Kconfig +++ b/drivers/net/ethernet/dec/tulip/Kconfig @@ -108,6 +108,7 @@ config TULIP_DM910X  config DE4X5  	tristate "Generic DECchip & DIGITAL EtherWORKS PCI/EISA"  	depends on (PCI || EISA) +	depends on VIRT_TO_BUS || ALPHA || PPC || SPARC  	select CRC32  	---help---  	  This is support for the DIGITAL series of PCI/EISA Ethernet cards. diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 28ceb841418..29aff55f2ee 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -349,6 +349,7 @@ struct be_adapter {  	struct pci_dev *pdev;  	struct net_device *netdev; +	u8 __iomem *csr;	/* CSR BAR used only for BE2/3 */  	u8 __iomem *db;		/* Door Bell */  	struct mutex mbox_lock; /* For serializing mbox cmds to BE card */ diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 071aea79d21..3c9b4f12e3e 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -473,19 +473,17 @@ static int be_mbox_notify_wait(struct be_adapter *adapter)  	return 0;  } -static int be_POST_stage_get(struct be_adapter *adapter, u16 *stage) +static u16 be_POST_stage_get(struct be_adapter *adapter)  {  	u32 sem; -	u32 reg = skyhawk_chip(adapter) ? SLIPORT_SEMAPHORE_OFFSET_SH : -					  SLIPORT_SEMAPHORE_OFFSET_BE; -	pci_read_config_dword(adapter->pdev, reg, &sem); -	*stage = sem & POST_STAGE_MASK; - -	if ((sem >> POST_ERR_SHIFT) & POST_ERR_MASK) -		return -1; +	if (BEx_chip(adapter)) +		sem  = ioread32(adapter->csr + SLIPORT_SEMAPHORE_OFFSET_BEx);  	else -		return 0; +		pci_read_config_dword(adapter->pdev, +				      SLIPORT_SEMAPHORE_OFFSET_SH, &sem); + +	return sem & POST_STAGE_MASK;  }  int lancer_wait_ready(struct be_adapter *adapter) @@ -579,19 +577,17 @@ int be_fw_wait_ready(struct be_adapter *adapter)  	}  	do { -		status = be_POST_stage_get(adapter, &stage); -		if (status) { -			dev_err(dev, "POST error; stage=0x%x\n", stage); -			return -1; -		} else if (stage != POST_STAGE_ARMFW_RDY) { -			if (msleep_interruptible(2000)) { -				dev_err(dev, "Waiting for POST aborted\n"); -				return -EINTR; -			} -			timeout += 2; -		} else { +		stage = be_POST_stage_get(adapter); +		if (stage == POST_STAGE_ARMFW_RDY)  			return 0; + +		dev_info(dev, "Waiting for POST, %ds elapsed\n", +			 timeout); +		if (msleep_interruptible(2000)) { +			dev_err(dev, "Waiting for POST aborted\n"); +			return -EINTR;  		} +		timeout += 2;  	} while (timeout < 60);  	dev_err(dev, "POST timeout; stage=0x%x\n", stage); diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h index 541d4530d5b..62dc220695f 100644 --- a/drivers/net/ethernet/emulex/benet/be_hw.h +++ b/drivers/net/ethernet/emulex/benet/be_hw.h @@ -32,8 +32,8 @@  #define MPU_EP_CONTROL 		0  /********** MPU semphore: used for SH & BE  *************/ -#define SLIPORT_SEMAPHORE_OFFSET_BE		0x7c -#define SLIPORT_SEMAPHORE_OFFSET_SH		0x94 +#define SLIPORT_SEMAPHORE_OFFSET_BEx		0xac  /* CSR BAR offset */ +#define SLIPORT_SEMAPHORE_OFFSET_SH		0x94  /* PCI-CFG offset */  #define POST_STAGE_MASK				0x0000FFFF  #define POST_ERR_MASK				0x1  #define POST_ERR_SHIFT				31 diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 3860888ac71..2886c9b63f9 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -759,8 +759,9 @@ static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter,  	if (vlan_tx_tag_present(skb)) {  		vlan_tag = be_get_tx_vlan_tag(adapter, skb); -		__vlan_put_tag(skb, vlan_tag); -		skb->vlan_tci = 0; +		skb = __vlan_put_tag(skb, vlan_tag); +		if (skb) +			skb->vlan_tci = 0;  	}  	return skb; @@ -3688,6 +3689,8 @@ static void be_netdev_init(struct net_device *netdev)  static void be_unmap_pci_bars(struct be_adapter *adapter)  { +	if (adapter->csr) +		pci_iounmap(adapter->pdev, adapter->csr);  	if (adapter->db)  		pci_iounmap(adapter->pdev, adapter->db);  } @@ -3721,6 +3724,12 @@ static int be_map_pci_bars(struct be_adapter *adapter)  	adapter->if_type = (sli_intf & SLI_INTF_IF_TYPE_MASK) >>  				SLI_INTF_IF_TYPE_SHIFT; +	if (BEx_chip(adapter) && be_physfn(adapter)) { +		adapter->csr = pci_iomap(adapter->pdev, 2, 0); +		if (adapter->csr == NULL) +			return -ENOMEM; +	} +  	addr = pci_iomap(adapter->pdev, db_bar(adapter), 0);  	if (addr == NULL)  		goto pci_map_err; @@ -4329,6 +4338,8 @@ static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev)  	pci_restore_state(pdev);  	/* Check if card is ok and fw is ready */ +	dev_info(&adapter->pdev->dev, +		 "Waiting for FW to be ready after EEH reset\n");  	status = be_fw_wait_ready(adapter);  	if (status)  		return PCI_ERS_RESULT_DISCONNECT; diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c index fccc3bf2141..73195f643c9 100644 --- a/drivers/net/ethernet/freescale/fec.c +++ b/drivers/net/ethernet/freescale/fec.c @@ -246,14 +246,13 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)  	struct bufdesc *bdp;  	void *bufaddr;  	unsigned short	status; -	unsigned long flags; +	unsigned int index;  	if (!fep->link) {  		/* Link is down or autonegotiation is in progress. */  		return NETDEV_TX_BUSY;  	} -	spin_lock_irqsave(&fep->hw_lock, flags);  	/* Fill in a Tx ring entry */  	bdp = fep->cur_tx; @@ -264,7 +263,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)  		 * This should not happen, since ndev->tbusy should be set.  		 */  		printk("%s: tx queue full!.\n", ndev->name); -		spin_unlock_irqrestore(&fep->hw_lock, flags);  		return NETDEV_TX_BUSY;  	} @@ -280,13 +278,13 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)  	 * 4-byte boundaries. Use bounce buffers to copy data  	 * and get it aligned. Ugh.  	 */ +	if (fep->bufdesc_ex) +		index = (struct bufdesc_ex *)bdp - +			(struct bufdesc_ex *)fep->tx_bd_base; +	else +		index = bdp - fep->tx_bd_base; +  	if (((unsigned long) bufaddr) & FEC_ALIGNMENT) { -		unsigned int index; -		if (fep->bufdesc_ex) -			index = (struct bufdesc_ex *)bdp - -				(struct bufdesc_ex *)fep->tx_bd_base; -		else -			index = bdp - fep->tx_bd_base;  		memcpy(fep->tx_bounce[index], skb->data, skb->len);  		bufaddr = fep->tx_bounce[index];  	} @@ -300,10 +298,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)  		swap_buffer(bufaddr, skb->len);  	/* Save skb pointer */ -	fep->tx_skbuff[fep->skb_cur] = skb; - -	ndev->stats.tx_bytes += skb->len; -	fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK; +	fep->tx_skbuff[index] = skb;  	/* Push the data cache so the CPM does not get stale memory  	 * data. @@ -331,29 +326,72 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)  			ebdp->cbd_esc = BD_ENET_TX_INT;  		}  	} -	/* Trigger transmission start */ -	writel(0, fep->hwp + FEC_X_DES_ACTIVE); -  	/* If this was the last BD in the ring, start at the beginning again. */  	if (status & BD_ENET_TX_WRAP)  		bdp = fep->tx_bd_base;  	else  		bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex); -	if (bdp == fep->dirty_tx) { -		fep->tx_full = 1; +	fep->cur_tx = bdp; + +	if (fep->cur_tx == fep->dirty_tx)  		netif_stop_queue(ndev); -	} -	fep->cur_tx = bdp; +	/* Trigger transmission start */ +	writel(0, fep->hwp + FEC_X_DES_ACTIVE);  	skb_tx_timestamp(skb); -	spin_unlock_irqrestore(&fep->hw_lock, flags); -  	return NETDEV_TX_OK;  } +/* Init RX & TX buffer descriptors + */ +static void fec_enet_bd_init(struct net_device *dev) +{ +	struct fec_enet_private *fep = netdev_priv(dev); +	struct bufdesc *bdp; +	unsigned int i; + +	/* Initialize the receive buffer descriptors. */ +	bdp = fep->rx_bd_base; +	for (i = 0; i < RX_RING_SIZE; i++) { + +		/* Initialize the BD for every fragment in the page. */ +		if (bdp->cbd_bufaddr) +			bdp->cbd_sc = BD_ENET_RX_EMPTY; +		else +			bdp->cbd_sc = 0; +		bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex); +	} + +	/* Set the last buffer to wrap */ +	bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex); +	bdp->cbd_sc |= BD_SC_WRAP; + +	fep->cur_rx = fep->rx_bd_base; + +	/* ...and the same for transmit */ +	bdp = fep->tx_bd_base; +	fep->cur_tx = bdp; +	for (i = 0; i < TX_RING_SIZE; i++) { + +		/* Initialize the BD for every fragment in the page. */ +		bdp->cbd_sc = 0; +		if (bdp->cbd_bufaddr && fep->tx_skbuff[i]) { +			dev_kfree_skb_any(fep->tx_skbuff[i]); +			fep->tx_skbuff[i] = NULL; +		} +		bdp->cbd_bufaddr = 0; +		bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex); +	} + +	/* Set the last buffer to wrap */ +	bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex); +	bdp->cbd_sc |= BD_SC_WRAP; +	fep->dirty_tx = bdp; +} +  /* This function is called to start or restart the FEC during a link   * change.  This only happens when switching between half and full   * duplex. @@ -397,6 +435,8 @@ fec_restart(struct net_device *ndev, int duplex)  	/* Set maximum receive buffer size. */  	writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE); +	fec_enet_bd_init(ndev); +  	/* Set receive and transmit descriptor base. */  	writel(fep->bd_dma, fep->hwp + FEC_R_DES_START);  	if (fep->bufdesc_ex) @@ -406,11 +446,7 @@ fec_restart(struct net_device *ndev, int duplex)  		writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc)  			* RX_RING_SIZE,	fep->hwp + FEC_X_DES_START); -	fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; -	fep->cur_rx = fep->rx_bd_base; -	/* Reset SKB transmit buffers. */ -	fep->skb_cur = fep->skb_dirty = 0;  	for (i = 0; i <= TX_RING_MOD_MASK; i++) {  		if (fep->tx_skbuff[i]) {  			dev_kfree_skb_any(fep->tx_skbuff[i]); @@ -573,20 +609,35 @@ fec_enet_tx(struct net_device *ndev)  	struct bufdesc *bdp;  	unsigned short status;  	struct	sk_buff	*skb; +	int	index = 0;  	fep = netdev_priv(ndev); -	spin_lock(&fep->hw_lock);  	bdp = fep->dirty_tx; +	/* get next bdp of dirty_tx */ +	if (bdp->cbd_sc & BD_ENET_TX_WRAP) +		bdp = fep->tx_bd_base; +	else +		bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex); +  	while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) { -		if (bdp == fep->cur_tx && fep->tx_full == 0) + +		/* current queue is empty */ +		if (bdp == fep->cur_tx)  			break; +		if (fep->bufdesc_ex) +			index = (struct bufdesc_ex *)bdp - +				(struct bufdesc_ex *)fep->tx_bd_base; +		else +			index = bdp - fep->tx_bd_base; +  		dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,  				FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE);  		bdp->cbd_bufaddr = 0; -		skb = fep->tx_skbuff[fep->skb_dirty]; +		skb = fep->tx_skbuff[index]; +  		/* Check for errors. */  		if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |  				   BD_ENET_TX_RL | BD_ENET_TX_UN | @@ -631,8 +682,9 @@ fec_enet_tx(struct net_device *ndev)  		/* Free the sk buffer associated with this last transmit */  		dev_kfree_skb_any(skb); -		fep->tx_skbuff[fep->skb_dirty] = NULL; -		fep->skb_dirty = (fep->skb_dirty + 1) & TX_RING_MOD_MASK; +		fep->tx_skbuff[index] = NULL; + +		fep->dirty_tx = bdp;  		/* Update pointer to next buffer descriptor to be transmitted */  		if (status & BD_ENET_TX_WRAP) @@ -642,14 +694,12 @@ fec_enet_tx(struct net_device *ndev)  		/* Since we have freed up a buffer, the ring is no longer full  		 */ -		if (fep->tx_full) { -			fep->tx_full = 0; +		if (fep->dirty_tx != fep->cur_tx) {  			if (netif_queue_stopped(ndev))  				netif_wake_queue(ndev);  		}  	} -	fep->dirty_tx = bdp; -	spin_unlock(&fep->hw_lock); +	return;  } @@ -816,7 +866,7 @@ fec_enet_interrupt(int irq, void *dev_id)  		int_events = readl(fep->hwp + FEC_IEVENT);  		writel(int_events, fep->hwp + FEC_IEVENT); -		if (int_events & FEC_ENET_RXF) { +		if (int_events & (FEC_ENET_RXF | FEC_ENET_TXF)) {  			ret = IRQ_HANDLED;  			/* Disable the RX interrupt */ @@ -827,15 +877,6 @@ fec_enet_interrupt(int irq, void *dev_id)  			}  		} -		/* Transmit OK, or non-fatal error. Update the buffer -		 * descriptors. FEC handles all errors, we just discover -		 * them as part of the transmit process. -		 */ -		if (int_events & FEC_ENET_TXF) { -			ret = IRQ_HANDLED; -			fec_enet_tx(ndev); -		} -  		if (int_events & FEC_ENET_MII) {  			ret = IRQ_HANDLED;  			complete(&fep->mdio_done); @@ -851,6 +892,8 @@ static int fec_enet_rx_napi(struct napi_struct *napi, int budget)  	int pkts = fec_enet_rx(ndev, budget);  	struct fec_enet_private *fep = netdev_priv(ndev); +	fec_enet_tx(ndev); +  	if (pkts < budget) {  		napi_complete(napi);  		writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); @@ -939,24 +982,29 @@ static void fec_enet_adjust_link(struct net_device *ndev)  		goto spin_unlock;  	} -	/* Duplex link change */  	if (phy_dev->link) { -		if (fep->full_duplex != phy_dev->duplex) { -			fec_restart(ndev, phy_dev->duplex); -			/* prevent unnecessary second fec_restart() below */ +		if (!fep->link) {  			fep->link = phy_dev->link;  			status_change = 1;  		} -	} -	/* Link on or off change */ -	if (phy_dev->link != fep->link) { -		fep->link = phy_dev->link; -		if (phy_dev->link) +		if (fep->full_duplex != phy_dev->duplex) +			status_change = 1; + +		if (phy_dev->speed != fep->speed) { +			fep->speed = phy_dev->speed; +			status_change = 1; +		} + +		/* if any of the above changed restart the FEC */ +		if (status_change)  			fec_restart(ndev, phy_dev->duplex); -		else +	} else { +		if (fep->link) {  			fec_stop(ndev); -		status_change = 1; +			fep->link = phy_dev->link; +			status_change = 1; +		}  	}  spin_unlock: @@ -1333,7 +1381,7 @@ static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)  static void fec_enet_free_buffers(struct net_device *ndev)  {  	struct fec_enet_private *fep = netdev_priv(ndev); -	int i; +	unsigned int i;  	struct sk_buff *skb;  	struct bufdesc	*bdp; @@ -1357,7 +1405,7 @@ static void fec_enet_free_buffers(struct net_device *ndev)  static int fec_enet_alloc_buffers(struct net_device *ndev)  {  	struct fec_enet_private *fep = netdev_priv(ndev); -	int i; +	unsigned int i;  	struct sk_buff *skb;  	struct bufdesc	*bdp; @@ -1442,6 +1490,7 @@ fec_enet_close(struct net_device *ndev)  	struct fec_enet_private *fep = netdev_priv(ndev);  	/* Don't know what to do yet. */ +	napi_disable(&fep->napi);  	fep->opened = 0;  	netif_stop_queue(ndev);  	fec_stop(ndev); @@ -1597,8 +1646,6 @@ static int fec_enet_init(struct net_device *ndev)  {  	struct fec_enet_private *fep = netdev_priv(ndev);  	struct bufdesc *cbd_base; -	struct bufdesc *bdp; -	int i;  	/* Allocate memory for buffer descriptors. */  	cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &fep->bd_dma, @@ -1608,6 +1655,7 @@ static int fec_enet_init(struct net_device *ndev)  		return -ENOMEM;  	} +	memset(cbd_base, 0, PAGE_SIZE);  	spin_lock_init(&fep->hw_lock);  	fep->netdev = ndev; @@ -1631,33 +1679,6 @@ static int fec_enet_init(struct net_device *ndev)  	writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK);  	netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, FEC_NAPI_WEIGHT); -	/* Initialize the receive buffer descriptors. */ -	bdp = fep->rx_bd_base; -	for (i = 0; i < RX_RING_SIZE; i++) { - -		/* Initialize the BD for every fragment in the page. */ -		bdp->cbd_sc = 0; -		bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex); -	} - -	/* Set the last buffer to wrap */ -	bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex); -	bdp->cbd_sc |= BD_SC_WRAP; - -	/* ...and the same for transmit */ -	bdp = fep->tx_bd_base; -	for (i = 0; i < TX_RING_SIZE; i++) { - -		/* Initialize the BD for every fragment in the page. */ -		bdp->cbd_sc = 0; -		bdp->cbd_bufaddr = 0; -		bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex); -	} - -	/* Set the last buffer to wrap */ -	bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex); -	bdp->cbd_sc |= BD_SC_WRAP; -  	fec_restart(ndev, 0);  	return 0; diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 01579b8e37c..eb437296283 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -97,6 +97,13 @@ struct bufdesc {  	unsigned short cbd_sc;	/* Control and status info */  	unsigned long cbd_bufaddr;	/* Buffer address */  }; +#else +struct bufdesc { +	unsigned short	cbd_sc;			/* Control and status info */ +	unsigned short	cbd_datlen;		/* Data length */ +	unsigned long	cbd_bufaddr;		/* Buffer address */ +}; +#endif  struct bufdesc_ex {  	struct bufdesc desc; @@ -107,14 +114,6 @@ struct bufdesc_ex {  	unsigned short res0[4];  }; -#else -struct bufdesc { -	unsigned short	cbd_sc;			/* Control and status info */ -	unsigned short	cbd_datlen;		/* Data length */ -	unsigned long	cbd_bufaddr;		/* Buffer address */ -}; -#endif -  /*   *	The following definitions courtesy of commproc.h, which where   *	Copyright (c) 1997 Dan Malek (dmalek@jlc.net). @@ -214,8 +213,6 @@ struct fec_enet_private {  	unsigned char *tx_bounce[TX_RING_SIZE];  	struct	sk_buff *tx_skbuff[TX_RING_SIZE];  	struct	sk_buff *rx_skbuff[RX_RING_SIZE]; -	ushort	skb_cur; -	ushort	skb_dirty;  	/* CPM dual port RAM relative addresses */  	dma_addr_t	bd_dma; @@ -227,7 +224,6 @@ struct fec_enet_private {  	/* The ring entries to be free()ed */  	struct bufdesc	*dirty_tx; -	uint	tx_full;  	/* hold while accessing the HW like ringbuffer for tx/rx but not MAC */  	spinlock_t hw_lock; @@ -244,6 +240,7 @@ struct fec_enet_private {  	phy_interface_t	phy_interface;  	int	link;  	int	full_duplex; +	int	speed;  	struct	completion mdio_done;  	int	irq[FEC_IRQ_NUM];  	int	bufdesc_ex; diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c index 1f17ca0f220..0d8df400a47 100644 --- a/drivers/net/ethernet/freescale/fec_ptp.c +++ b/drivers/net/ethernet/freescale/fec_ptp.c @@ -128,6 +128,7 @@ void fec_ptp_start_cyclecounter(struct net_device *ndev)  	spin_unlock_irqrestore(&fep->tmreg_lock, flags);  } +EXPORT_SYMBOL(fec_ptp_start_cyclecounter);  /**   * fec_ptp_adjfreq - adjust ptp cycle frequency @@ -318,6 +319,7 @@ int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)  	return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?  	    -EFAULT : 0;  } +EXPORT_SYMBOL(fec_ptp_ioctl);  /**   * fec_time_keep - call timecounter_read every second to avoid timer overrun @@ -383,3 +385,4 @@ void fec_ptp_init(struct net_device *ndev, struct platform_device *pdev)  		pr_info("registered PHC device on %s\n", ndev->name);  	}  } +EXPORT_SYMBOL(fec_ptp_init); diff --git a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c index 2418faf2251..ab98b77df30 100644 --- a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c +++ b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c @@ -705,19 +705,7 @@ static struct pcmcia_driver fmvj18x_cs_driver = {  	.suspend	= fmvj18x_suspend,  	.resume		= fmvj18x_resume,  }; - -static int __init init_fmvj18x_cs(void) -{ -	return pcmcia_register_driver(&fmvj18x_cs_driver); -} - -static void __exit exit_fmvj18x_cs(void) -{ -	pcmcia_unregister_driver(&fmvj18x_cs_driver); -} - -module_init(init_fmvj18x_cs); -module_exit(exit_fmvj18x_cs); +module_pcmcia_driver(fmvj18x_cs_driver);  /*====================================================================*/ diff --git a/drivers/net/ethernet/intel/e100.c b/drivers/net/ethernet/intel/e100.c index ec800b093e7..d2bea3f07c7 100644 --- a/drivers/net/ethernet/intel/e100.c +++ b/drivers/net/ethernet/intel/e100.c @@ -870,7 +870,7 @@ err_unlock:  }  static int e100_exec_cb(struct nic *nic, struct sk_buff *skb, -	void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *)) +	int (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *))  {  	struct cb *cb;  	unsigned long flags; @@ -888,10 +888,13 @@ static int e100_exec_cb(struct nic *nic, struct sk_buff *skb,  	nic->cbs_avail--;  	cb->skb = skb; +	err = cb_prepare(nic, cb, skb); +	if (err) +		goto err_unlock; +  	if (unlikely(!nic->cbs_avail))  		err = -ENOSPC; -	cb_prepare(nic, cb, skb);  	/* Order is important otherwise we'll be in a race with h/w:  	 * set S-bit in current first, then clear S-bit in previous. */ @@ -1091,7 +1094,7 @@ static void e100_get_defaults(struct nic *nic)  	nic->mii.mdio_write = mdio_write;  } -static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb) +static int e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb)  {  	struct config *config = &cb->u.config;  	u8 *c = (u8 *)config; @@ -1181,6 +1184,7 @@ static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb)  	netif_printk(nic, hw, KERN_DEBUG, nic->netdev,  		     "[16-23]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",  		     c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]); +	return 0;  }  /************************************************************************* @@ -1331,7 +1335,7 @@ static const struct firmware *e100_request_firmware(struct nic *nic)  	return fw;  } -static void e100_setup_ucode(struct nic *nic, struct cb *cb, +static int e100_setup_ucode(struct nic *nic, struct cb *cb,  			     struct sk_buff *skb)  {  	const struct firmware *fw = (void *)skb; @@ -1358,6 +1362,7 @@ static void e100_setup_ucode(struct nic *nic, struct cb *cb,  	cb->u.ucode[min_size] |= cpu_to_le32((BUNDLESMALL) ? 0xFFFF : 0xFF80);  	cb->command = cpu_to_le16(cb_ucode | cb_el); +	return 0;  }  static inline int e100_load_ucode_wait(struct nic *nic) @@ -1400,18 +1405,20 @@ static inline int e100_load_ucode_wait(struct nic *nic)  	return err;  } -static void e100_setup_iaaddr(struct nic *nic, struct cb *cb, +static int e100_setup_iaaddr(struct nic *nic, struct cb *cb,  	struct sk_buff *skb)  {  	cb->command = cpu_to_le16(cb_iaaddr);  	memcpy(cb->u.iaaddr, nic->netdev->dev_addr, ETH_ALEN); +	return 0;  } -static void e100_dump(struct nic *nic, struct cb *cb, struct sk_buff *skb) +static int e100_dump(struct nic *nic, struct cb *cb, struct sk_buff *skb)  {  	cb->command = cpu_to_le16(cb_dump);  	cb->u.dump_buffer_addr = cpu_to_le32(nic->dma_addr +  		offsetof(struct mem, dump_buf)); +	return 0;  }  static int e100_phy_check_without_mii(struct nic *nic) @@ -1581,7 +1588,7 @@ static int e100_hw_init(struct nic *nic)  	return 0;  } -static void e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb) +static int e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb)  {  	struct net_device *netdev = nic->netdev;  	struct netdev_hw_addr *ha; @@ -1596,6 +1603,7 @@ static void e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb)  		memcpy(&cb->u.multi.addr[i++ * ETH_ALEN], &ha->addr,  			ETH_ALEN);  	} +	return 0;  }  static void e100_set_multicast_list(struct net_device *netdev) @@ -1756,11 +1764,18 @@ static void e100_watchdog(unsigned long data)  		  round_jiffies(jiffies + E100_WATCHDOG_PERIOD));  } -static void e100_xmit_prepare(struct nic *nic, struct cb *cb, +static int e100_xmit_prepare(struct nic *nic, struct cb *cb,  	struct sk_buff *skb)  { +	dma_addr_t dma_addr;  	cb->command = nic->tx_command; +	dma_addr = pci_map_single(nic->pdev, +				  skb->data, skb->len, PCI_DMA_TODEVICE); +	/* If we can't map the skb, have the upper layer try later */ +	if (pci_dma_mapping_error(nic->pdev, dma_addr)) +		return -ENOMEM; +  	/*  	 * Use the last 4 bytes of the SKB payload packet as the CRC, used for  	 * testing, ie sending frames with bad CRC. @@ -1777,11 +1792,10 @@ static void e100_xmit_prepare(struct nic *nic, struct cb *cb,  	cb->u.tcb.tcb_byte_count = 0;  	cb->u.tcb.threshold = nic->tx_threshold;  	cb->u.tcb.tbd_count = 1; -	cb->u.tcb.tbd.buf_addr = cpu_to_le32(pci_map_single(nic->pdev, -		skb->data, skb->len, PCI_DMA_TODEVICE)); -	/* check for mapping failure? */ +	cb->u.tcb.tbd.buf_addr = cpu_to_le32(dma_addr);  	cb->u.tcb.tbd.size = cpu_to_le16(skb->len);  	skb_tx_timestamp(skb); +	return 0;  }  static netdev_tx_t e100_xmit_frame(struct sk_buff *skb, diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c index 43462d596a4..ffd287196bf 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c +++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c @@ -1053,6 +1053,10 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)  		txdr->buffer_info[i].dma =  			dma_map_single(&pdev->dev, skb->data, skb->len,  				       DMA_TO_DEVICE); +		if (dma_mapping_error(&pdev->dev, txdr->buffer_info[i].dma)) { +			ret_val = 4; +			goto err_nomem; +		}  		tx_desc->buffer_addr = cpu_to_le64(txdr->buffer_info[i].dma);  		tx_desc->lower.data = cpu_to_le32(skb->len);  		tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP | @@ -1069,7 +1073,7 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)  	rxdr->buffer_info = kcalloc(rxdr->count, sizeof(struct e1000_buffer),  				    GFP_KERNEL);  	if (!rxdr->buffer_info) { -		ret_val = 4; +		ret_val = 5;  		goto err_nomem;  	} @@ -1077,7 +1081,7 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)  	rxdr->desc = dma_alloc_coherent(&pdev->dev, rxdr->size, &rxdr->dma,  					GFP_KERNEL);  	if (!rxdr->desc) { -		ret_val = 5; +		ret_val = 6;  		goto err_nomem;  	}  	memset(rxdr->desc, 0, rxdr->size); @@ -1101,7 +1105,7 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)  		skb = alloc_skb(E1000_RXBUFFER_2048 + NET_IP_ALIGN, GFP_KERNEL);  		if (!skb) { -			ret_val = 6; +			ret_val = 7;  			goto err_nomem;  		}  		skb_reserve(skb, NET_IP_ALIGN); @@ -1110,6 +1114,10 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)  		rxdr->buffer_info[i].dma =  			dma_map_single(&pdev->dev, skb->data,  				       E1000_RXBUFFER_2048, DMA_FROM_DEVICE); +		if (dma_mapping_error(&pdev->dev, rxdr->buffer_info[i].dma)) { +			ret_val = 8; +			goto err_nomem; +		}  		rx_desc->buffer_addr = cpu_to_le64(rxdr->buffer_info[i].dma);  		memset(skb->data, 0x00, skb->len);  	} diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index 2c1813737f6..f91a8f3f9d4 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -36,6 +36,7 @@  #include <linux/delay.h>  #include <linux/vmalloc.h>  #include <linux/mdio.h> +#include <linux/pm_runtime.h>  #include "e1000.h" @@ -2229,7 +2230,19 @@ static int e1000e_get_ts_info(struct net_device *netdev,  	return 0;  } +static int e1000e_ethtool_begin(struct net_device *netdev) +{ +	return pm_runtime_get_sync(netdev->dev.parent); +} + +static void e1000e_ethtool_complete(struct net_device *netdev) +{ +	pm_runtime_put_sync(netdev->dev.parent); +} +  static const struct ethtool_ops e1000_ethtool_ops = { +	.begin			= e1000e_ethtool_begin, +	.complete		= e1000e_ethtool_complete,  	.get_settings		= e1000_get_settings,  	.set_settings		= e1000_set_settings,  	.get_drvinfo		= e1000_get_drvinfo, diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index dff7bff8b8e..121a865c7fb 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -782,6 +782,59 @@ release:  }  /** + *  e1000_k1_workaround_lpt_lp - K1 workaround on Lynxpoint-LP + *  @hw:   pointer to the HW structure + *  @link: link up bool flag + * + *  When K1 is enabled for 1Gbps, the MAC can miss 2 DMA completion indications + *  preventing further DMA write requests.  Workaround the issue by disabling + *  the de-assertion of the clock request when in 1Gpbs mode. + **/ +static s32 e1000_k1_workaround_lpt_lp(struct e1000_hw *hw, bool link) +{ +	u32 fextnvm6 = er32(FEXTNVM6); +	s32 ret_val = 0; + +	if (link && (er32(STATUS) & E1000_STATUS_SPEED_1000)) { +		u16 kmrn_reg; + +		ret_val = hw->phy.ops.acquire(hw); +		if (ret_val) +			return ret_val; + +		ret_val = +		    e1000e_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG, +						&kmrn_reg); +		if (ret_val) +			goto release; + +		ret_val = +		    e1000e_write_kmrn_reg_locked(hw, +						 E1000_KMRNCTRLSTA_K1_CONFIG, +						 kmrn_reg & +						 ~E1000_KMRNCTRLSTA_K1_ENABLE); +		if (ret_val) +			goto release; + +		usleep_range(10, 20); + +		ew32(FEXTNVM6, fextnvm6 | E1000_FEXTNVM6_REQ_PLL_CLK); + +		ret_val = +		    e1000e_write_kmrn_reg_locked(hw, +						 E1000_KMRNCTRLSTA_K1_CONFIG, +						 kmrn_reg); +release: +		hw->phy.ops.release(hw); +	} else { +		/* clear FEXTNVM6 bit 8 on link down or 10/100 */ +		ew32(FEXTNVM6, fextnvm6 & ~E1000_FEXTNVM6_REQ_PLL_CLK); +	} + +	return ret_val; +} + +/**   *  e1000_check_for_copper_link_ich8lan - Check for link (Copper)   *  @hw: pointer to the HW structure   * @@ -818,6 +871,14 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)  			return ret_val;  	} +	/* Work-around I218 hang issue */ +	if ((hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPTLP_I218_LM) || +	    (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPTLP_I218_V)) { +		ret_val = e1000_k1_workaround_lpt_lp(hw, link); +		if (ret_val) +			return ret_val; +	} +  	/* Clear link partner's EEE ability */  	hw->dev_spec.ich8lan.eee_lp_ability = 0; @@ -3954,8 +4015,16 @@ void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw)  	phy_ctrl = er32(PHY_CTRL);  	phy_ctrl |= E1000_PHY_CTRL_GBE_DISABLE; +  	if (hw->phy.type == e1000_phy_i217) { -		u16 phy_reg; +		u16 phy_reg, device_id = hw->adapter->pdev->device; + +		if ((device_id == E1000_DEV_ID_PCH_LPTLP_I218_LM) || +		    (device_id == E1000_DEV_ID_PCH_LPTLP_I218_V)) { +			u32 fextnvm6 = er32(FEXTNVM6); + +			ew32(FEXTNVM6, fextnvm6 & ~E1000_FEXTNVM6_REQ_PLL_CLK); +		}  		ret_val = hw->phy.ops.acquire(hw);  		if (ret_val) diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.h b/drivers/net/ethernet/intel/e1000e/ich8lan.h index b6d3174d7d2..8bf4655c2e1 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.h +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.h @@ -92,6 +92,8 @@  #define E1000_FEXTNVM4_BEACON_DURATION_8USEC	0x7  #define E1000_FEXTNVM4_BEACON_DURATION_16USEC	0x3 +#define E1000_FEXTNVM6_REQ_PLL_CLK	0x00000100 +  #define PCIE_ICH8_SNOOP_ALL	PCIE_NO_SNOOP_ALL  #define E1000_ICH_RAR_ENTRIES	7 diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index a177b8b65c4..7e615e2bf7e 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -848,11 +848,16 @@ check_page:  			}  		} -		if (!buffer_info->dma) +		if (!buffer_info->dma) {  			buffer_info->dma = dma_map_page(&pdev->dev,  			                                buffer_info->page, 0,  			                                PAGE_SIZE,  							DMA_FROM_DEVICE); +			if (dma_mapping_error(&pdev->dev, buffer_info->dma)) { +				adapter->alloc_rx_buff_failed++; +				break; +			} +		}  		rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);  		rx_desc->read.buffer_addr = cpu_to_le64(buffer_info->dma); @@ -4303,6 +4308,7 @@ static int e1000_open(struct net_device *netdev)  	netif_start_queue(netdev);  	adapter->idle_check = true; +	hw->mac.get_link_status = true;  	pm_runtime_put(&pdev->dev);  	/* fire a link status change interrupt to start the watchdog */ @@ -4662,6 +4668,7 @@ static void e1000_phy_read_status(struct e1000_adapter *adapter)  	    (adapter->hw.phy.media_type == e1000_media_type_copper)) {  		int ret_val; +		pm_runtime_get_sync(&adapter->pdev->dev);  		ret_val = e1e_rphy(hw, MII_BMCR, &phy->bmcr);  		ret_val |= e1e_rphy(hw, MII_BMSR, &phy->bmsr);  		ret_val |= e1e_rphy(hw, MII_ADVERTISE, &phy->advertise); @@ -4672,6 +4679,7 @@ static void e1000_phy_read_status(struct e1000_adapter *adapter)  		ret_val |= e1e_rphy(hw, MII_ESTATUS, &phy->estatus);  		if (ret_val)  			e_warn("Error reading PHY register\n"); +		pm_runtime_put_sync(&adapter->pdev->dev);  	} else {  		/* Do not read PHY registers if link is not up  		 * Set values to typical power-on defaults @@ -5887,8 +5895,7 @@ release:  	return retval;  } -static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake, -			    bool runtime) +static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)  {  	struct net_device *netdev = pci_get_drvdata(pdev);  	struct e1000_adapter *adapter = netdev_priv(netdev); @@ -5912,10 +5919,6 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake,  	}  	e1000e_reset_interrupt_capability(adapter); -	retval = pci_save_state(pdev); -	if (retval) -		return retval; -  	status = er32(STATUS);  	if (status & E1000_STATUS_LU)  		wufc &= ~E1000_WUFC_LNKC; @@ -5971,13 +5974,6 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake,  		ew32(WUFC, 0);  	} -	*enable_wake = !!wufc; - -	/* make sure adapter isn't asleep if manageability is enabled */ -	if ((adapter->flags & FLAG_MNG_PT_ENABLED) || -	    (hw->mac.ops.check_mng_mode(hw))) -		*enable_wake = true; -  	if (adapter->hw.phy.type == e1000_phy_igp_3)  		e1000e_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw); @@ -5986,27 +5982,7 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake,  	 */  	e1000e_release_hw_control(adapter); -	pci_disable_device(pdev); - -	return 0; -} - -static void e1000_power_off(struct pci_dev *pdev, bool sleep, bool wake) -{ -	if (sleep && wake) { -		pci_prepare_to_sleep(pdev); -		return; -	} - -	pci_wake_from_d3(pdev, wake); -	pci_set_power_state(pdev, PCI_D3hot); -} - -static void e1000_complete_shutdown(struct pci_dev *pdev, bool sleep, -                                    bool wake) -{ -	struct net_device *netdev = pci_get_drvdata(pdev); -	struct e1000_adapter *adapter = netdev_priv(netdev); +	pci_clear_master(pdev);  	/* The pci-e switch on some quad port adapters will report a  	 * correctable error when the MAC transitions from D0 to D3.  To @@ -6021,12 +5997,13 @@ static void e1000_complete_shutdown(struct pci_dev *pdev, bool sleep,  		pcie_capability_write_word(us_dev, PCI_EXP_DEVCTL,  					   (devctl & ~PCI_EXP_DEVCTL_CERE)); -		e1000_power_off(pdev, sleep, wake); +		pci_save_state(pdev); +		pci_prepare_to_sleep(pdev);  		pcie_capability_write_word(us_dev, PCI_EXP_DEVCTL, devctl); -	} else { -		e1000_power_off(pdev, sleep, wake);  	} + +	return 0;  }  #ifdef CONFIG_PCIEASPM @@ -6084,9 +6061,7 @@ static int __e1000_resume(struct pci_dev *pdev)  	if (aspm_disable_flag)  		e1000e_disable_aspm(pdev, aspm_disable_flag); -	pci_set_power_state(pdev, PCI_D0); -	pci_restore_state(pdev); -	pci_save_state(pdev); +	pci_set_master(pdev);  	e1000e_set_interrupt_capability(adapter);  	if (netif_running(netdev)) { @@ -6152,14 +6127,8 @@ static int __e1000_resume(struct pci_dev *pdev)  static int e1000_suspend(struct device *dev)  {  	struct pci_dev *pdev = to_pci_dev(dev); -	int retval; -	bool wake; -	retval = __e1000_shutdown(pdev, &wake, false); -	if (!retval) -		e1000_complete_shutdown(pdev, true, wake); - -	return retval; +	return __e1000_shutdown(pdev, false);  }  static int e1000_resume(struct device *dev) @@ -6182,13 +6151,10 @@ static int e1000_runtime_suspend(struct device *dev)  	struct net_device *netdev = pci_get_drvdata(pdev);  	struct e1000_adapter *adapter = netdev_priv(netdev); -	if (e1000e_pm_ready(adapter)) { -		bool wake; - -		__e1000_shutdown(pdev, &wake, true); -	} +	if (!e1000e_pm_ready(adapter)) +		return 0; -	return 0; +	return __e1000_shutdown(pdev, true);  }  static int e1000_idle(struct device *dev) @@ -6226,12 +6192,7 @@ static int e1000_runtime_resume(struct device *dev)  static void e1000_shutdown(struct pci_dev *pdev)  { -	bool wake = false; - -	__e1000_shutdown(pdev, &wake, false); - -	if (system_state == SYSTEM_POWER_OFF) -		e1000_complete_shutdown(pdev, false, wake); +	__e1000_shutdown(pdev, false);  }  #ifdef CONFIG_NET_POLL_CONTROLLER @@ -6352,9 +6313,9 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)  			"Cannot re-enable PCI device after reset.\n");  		result = PCI_ERS_RESULT_DISCONNECT;  	} else { -		pci_set_master(pdev);  		pdev->state_saved = true;  		pci_restore_state(pdev); +		pci_set_master(pdev);  		pci_enable_wake(pdev, PCI_D3hot, 0);  		pci_enable_wake(pdev, PCI_D3cold, 0); @@ -6783,7 +6744,11 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	/* initialize the wol settings based on the eeprom settings */  	adapter->wol = adapter->eeprom_wol; -	device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol); + +	/* make sure adapter isn't asleep if manageability is enabled */ +	if (adapter->wol || (adapter->flags & FLAG_MNG_PT_ENABLED) || +	    (hw->mac.ops.check_mng_mode(hw))) +		device_wakeup_enable(&pdev->dev);  	/* save off EEPROM version number */  	e1000_read_nvm(&adapter->hw, 5, 1, &adapter->eeprom_vers); diff --git a/drivers/net/ethernet/intel/e1000e/regs.h b/drivers/net/ethernet/intel/e1000e/regs.h index 794fe149766..a7e6a3e3725 100644 --- a/drivers/net/ethernet/intel/e1000e/regs.h +++ b/drivers/net/ethernet/intel/e1000e/regs.h @@ -42,6 +42,7 @@  #define E1000_FEXTNVM	0x00028	/* Future Extended NVM - RW */  #define E1000_FEXTNVM3	0x0003C	/* Future Extended NVM 3 - RW */  #define E1000_FEXTNVM4	0x00024	/* Future Extended NVM 4 - RW */ +#define E1000_FEXTNVM6	0x00010	/* Future Extended NVM 6 - RW */  #define E1000_FEXTNVM7	0x000E4	/* Future Extended NVM 7 - RW */  #define E1000_FCT	0x00030	/* Flow Control Type - RW */  #define E1000_VET	0x00038	/* VLAN Ether Type - RW */ diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index 84e7e0909de..12b1d848080 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -1361,11 +1361,16 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)  	switch (hw->phy.type) {  	case e1000_phy_i210:  	case e1000_phy_m88: -		if (hw->phy.id == I347AT4_E_PHY_ID || -		    hw->phy.id == M88E1112_E_PHY_ID) +		switch (hw->phy.id) { +		case I347AT4_E_PHY_ID: +		case M88E1112_E_PHY_ID: +		case I210_I_PHY_ID:  			ret_val = igb_copper_link_setup_m88_gen2(hw); -		else +			break; +		default:  			ret_val = igb_copper_link_setup_m88(hw); +			break; +		}  		break;  	case e1000_phy_igp_3:  		ret_val = igb_copper_link_setup_igp(hw); @@ -1813,27 +1818,32 @@ out:   **/  void igb_vmdq_set_anti_spoofing_pf(struct e1000_hw *hw, bool enable, int pf)  { -	u32 dtxswc; +	u32 reg_val, reg_offset;  	switch (hw->mac.type) {  	case e1000_82576: +		reg_offset = E1000_DTXSWC; +		break;  	case e1000_i350: -		dtxswc = rd32(E1000_DTXSWC); -		if (enable) { -			dtxswc |= (E1000_DTXSWC_MAC_SPOOF_MASK | -				   E1000_DTXSWC_VLAN_SPOOF_MASK); -			/* The PF can spoof - it has to in order to -			 * support emulation mode NICs */ -			dtxswc ^= (1 << pf | 1 << (pf + MAX_NUM_VFS)); -		} else { -			dtxswc &= ~(E1000_DTXSWC_MAC_SPOOF_MASK | -				    E1000_DTXSWC_VLAN_SPOOF_MASK); -		} -		wr32(E1000_DTXSWC, dtxswc); +		reg_offset = E1000_TXSWC;  		break;  	default: -		break; +		return; +	} + +	reg_val = rd32(reg_offset); +	if (enable) { +		reg_val |= (E1000_DTXSWC_MAC_SPOOF_MASK | +			     E1000_DTXSWC_VLAN_SPOOF_MASK); +		/* The PF can spoof - it has to in order to +		 * support emulation mode NICs +		 */ +		reg_val ^= (1 << pf | 1 << (pf + MAX_NUM_VFS)); +	} else { +		reg_val &= ~(E1000_DTXSWC_MAC_SPOOF_MASK | +			     E1000_DTXSWC_VLAN_SPOOF_MASK);  	} +	wr32(reg_offset, reg_val);  }  /** diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index d27edbc6392..ab577a763a2 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -284,18 +284,10 @@ struct igb_q_vector {  enum e1000_ring_flags_t {  	IGB_RING_FLAG_RX_SCTP_CSUM,  	IGB_RING_FLAG_RX_LB_VLAN_BSWAP, -	IGB_RING_FLAG_RX_BUILD_SKB_ENABLED,  	IGB_RING_FLAG_TX_CTX_IDX,  	IGB_RING_FLAG_TX_DETECT_HANG  }; -#define ring_uses_build_skb(ring) \ -	test_bit(IGB_RING_FLAG_RX_BUILD_SKB_ENABLED, &(ring)->flags) -#define set_ring_build_skb_enabled(ring) \ -	set_bit(IGB_RING_FLAG_RX_BUILD_SKB_ENABLED, &(ring)->flags) -#define clear_ring_build_skb_enabled(ring) \ -	clear_bit(IGB_RING_FLAG_RX_BUILD_SKB_ENABLED, &(ring)->flags) -  #define IGB_TXD_DCMD (E1000_ADVTXD_DCMD_EOP | E1000_ADVTXD_DCMD_RS)  #define IGB_RX_DESC(R, i)	    \ @@ -447,7 +439,7 @@ struct igb_adapter {  #endif  	struct i2c_algo_bit_data i2c_algo;  	struct i2c_adapter i2c_adap; -	struct igb_i2c_client_list *i2c_clients; +	struct i2c_client *i2c_client;  };  #define IGB_FLAG_HAS_MSI		(1 << 0) diff --git a/drivers/net/ethernet/intel/igb/igb_hwmon.c b/drivers/net/ethernet/intel/igb/igb_hwmon.c index 0a9b073d0b0..0478a1abe54 100644 --- a/drivers/net/ethernet/intel/igb/igb_hwmon.c +++ b/drivers/net/ethernet/intel/igb/igb_hwmon.c @@ -39,6 +39,10 @@  #include <linux/pci.h>  #ifdef CONFIG_IGB_HWMON +static struct i2c_board_info i350_sensor_info = { +	I2C_BOARD_INFO("i350bb", (0Xf8 >> 1)), +}; +  /* hwmon callback functions */  static ssize_t igb_hwmon_show_location(struct device *dev,  					 struct device_attribute *attr, @@ -188,6 +192,7 @@ int igb_sysfs_init(struct igb_adapter *adapter)  	unsigned int i;  	int n_attrs;  	int rc = 0; +	struct i2c_client *client = NULL;  	/* If this method isn't defined we don't support thermals */  	if (adapter->hw.mac.ops.init_thermal_sensor_thresh == NULL) @@ -198,6 +203,15 @@ int igb_sysfs_init(struct igb_adapter *adapter)  		if (rc)  			goto exit; +	/* init i2c_client */ +	client = i2c_new_device(&adapter->i2c_adap, &i350_sensor_info); +	if (client == NULL) { +		dev_info(&adapter->pdev->dev, +			"Failed to create new i2c device..\n"); +		goto exit; +	} +	adapter->i2c_client = client; +  	/* Allocation space for max attributes  	 * max num sensors * values (loc, temp, max, caution)  	 */ diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index ed79a1c53b5..64f75291e3a 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -1923,10 +1923,6 @@ void igb_set_fw_version(struct igb_adapter *adapter)  	return;  } -static const struct i2c_board_info i350_sensor_info = { -	I2C_BOARD_INFO("i350bb", 0Xf8), -}; -  /*  igb_init_i2c - Init I2C interface   *  @adapter: pointer to adapter structure   * @@ -2546,8 +2542,8 @@ static void igb_probe_vfs(struct igb_adapter *adapter)  	if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211))  		return; -	igb_enable_sriov(pdev, max_vfs);  	pci_sriov_set_totalvfs(pdev, 7); +	igb_enable_sriov(pdev, max_vfs);  #endif /* CONFIG_PCI_IOV */  } @@ -2656,7 +2652,7 @@ static int igb_sw_init(struct igb_adapter *adapter)  		if (max_vfs > 7) {  			dev_warn(&pdev->dev,  				 "Maximum of 7 VFs per PF, using max\n"); -			adapter->vfs_allocated_count = 7; +			max_vfs = adapter->vfs_allocated_count = 7;  		} else  			adapter->vfs_allocated_count = max_vfs;  		if (adapter->vfs_allocated_count) @@ -3354,20 +3350,6 @@ void igb_configure_rx_ring(struct igb_adapter *adapter,  	wr32(E1000_RXDCTL(reg_idx), rxdctl);  } -static void igb_set_rx_buffer_len(struct igb_adapter *adapter, -				  struct igb_ring *rx_ring) -{ -#define IGB_MAX_BUILD_SKB_SIZE \ -	(SKB_WITH_OVERHEAD(IGB_RX_BUFSZ) - \ -	 (NET_SKB_PAD + NET_IP_ALIGN + IGB_TS_HDR_LEN)) - -	/* set build_skb flag */ -	if (adapter->max_frame_size <= IGB_MAX_BUILD_SKB_SIZE) -		set_ring_build_skb_enabled(rx_ring); -	else -		clear_ring_build_skb_enabled(rx_ring); -} -  /**   * igb_configure_rx - Configure receive Unit after Reset   * @adapter: board private structure @@ -3387,11 +3369,8 @@ static void igb_configure_rx(struct igb_adapter *adapter)  	/* Setup the HW Rx Head and Tail Descriptor Pointers and  	 * the Base and Length of the Rx Descriptor Ring */ -	for (i = 0; i < adapter->num_rx_queues; i++) { -		struct igb_ring *rx_ring = adapter->rx_ring[i]; -		igb_set_rx_buffer_len(adapter, rx_ring); -		igb_configure_rx_ring(adapter, rx_ring); -	} +	for (i = 0; i < adapter->num_rx_queues; i++) +		igb_configure_rx_ring(adapter, adapter->rx_ring[i]);  }  /** @@ -6207,85 +6186,6 @@ static bool igb_add_rx_frag(struct igb_ring *rx_ring,  	return igb_can_reuse_rx_page(rx_buffer, page, truesize);  } -static struct sk_buff *igb_build_rx_buffer(struct igb_ring *rx_ring, -					   union e1000_adv_rx_desc *rx_desc) -{ -	struct igb_rx_buffer *rx_buffer; -	struct sk_buff *skb; -	struct page *page; -	void *page_addr; -	unsigned int size = le16_to_cpu(rx_desc->wb.upper.length); -#if (PAGE_SIZE < 8192) -	unsigned int truesize = IGB_RX_BUFSZ; -#else -	unsigned int truesize = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) + -				SKB_DATA_ALIGN(NET_SKB_PAD + -					       NET_IP_ALIGN + -					       size); -#endif - -	/* If we spanned a buffer we have a huge mess so test for it */ -	BUG_ON(unlikely(!igb_test_staterr(rx_desc, E1000_RXD_STAT_EOP))); - -	/* Guarantee this function can be used by verifying buffer sizes */ -	BUILD_BUG_ON(SKB_WITH_OVERHEAD(IGB_RX_BUFSZ) < (NET_SKB_PAD + -							NET_IP_ALIGN + -							IGB_TS_HDR_LEN + -							ETH_FRAME_LEN + -							ETH_FCS_LEN)); - -	rx_buffer = &rx_ring->rx_buffer_info[rx_ring->next_to_clean]; -	page = rx_buffer->page; -	prefetchw(page); - -	page_addr = page_address(page) + rx_buffer->page_offset; - -	/* prefetch first cache line of first page */ -	prefetch(page_addr + NET_SKB_PAD + NET_IP_ALIGN); -#if L1_CACHE_BYTES < 128 -	prefetch(page_addr + L1_CACHE_BYTES + NET_SKB_PAD + NET_IP_ALIGN); -#endif - -	/* build an skb to around the page buffer */ -	skb = build_skb(page_addr, truesize); -	if (unlikely(!skb)) { -		rx_ring->rx_stats.alloc_failed++; -		return NULL; -	} - -	/* we are reusing so sync this buffer for CPU use */ -	dma_sync_single_range_for_cpu(rx_ring->dev, -				      rx_buffer->dma, -				      rx_buffer->page_offset, -				      IGB_RX_BUFSZ, -				      DMA_FROM_DEVICE); - -	/* update pointers within the skb to store the data */ -	skb_reserve(skb, NET_IP_ALIGN + NET_SKB_PAD); -	__skb_put(skb, size); - -	/* pull timestamp out of packet data */ -	if (igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP)) { -		igb_ptp_rx_pktstamp(rx_ring->q_vector, skb->data, skb); -		__skb_pull(skb, IGB_TS_HDR_LEN); -	} - -	if (igb_can_reuse_rx_page(rx_buffer, page, truesize)) { -		/* hand second half of page back to the ring */ -		igb_reuse_rx_page(rx_ring, rx_buffer); -	} else { -		/* we are not reusing the buffer so unmap it */ -		dma_unmap_page(rx_ring->dev, rx_buffer->dma, -			       PAGE_SIZE, DMA_FROM_DEVICE); -	} - -	/* clear contents of buffer_info */ -	rx_buffer->dma = 0; -	rx_buffer->page = NULL; - -	return skb; -} -  static struct sk_buff *igb_fetch_rx_buffer(struct igb_ring *rx_ring,  					   union e1000_adv_rx_desc *rx_desc,  					   struct sk_buff *skb) @@ -6701,10 +6601,7 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)  		rmb();  		/* retrieve a buffer from the ring */ -		if (ring_uses_build_skb(rx_ring)) -			skb = igb_build_rx_buffer(rx_ring, rx_desc); -		else -			skb = igb_fetch_rx_buffer(rx_ring, rx_desc, skb); +		skb = igb_fetch_rx_buffer(rx_ring, rx_desc, skb);  		/* exit if we failed to retrieve a buffer */  		if (!skb) @@ -6791,14 +6688,6 @@ static bool igb_alloc_mapped_page(struct igb_ring *rx_ring,  	return true;  } -static inline unsigned int igb_rx_offset(struct igb_ring *rx_ring) -{ -	if (ring_uses_build_skb(rx_ring)) -		return NET_SKB_PAD + NET_IP_ALIGN; -	else -		return 0; -} -  /**   * igb_alloc_rx_buffers - Replace used receive buffers; packet split   * @adapter: address of board private structure @@ -6825,9 +6714,7 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)  		 * Refresh the desc even if buffer_addrs didn't change  		 * because each write-back erases this info.  		 */ -		rx_desc->read.pkt_addr = cpu_to_le64(bi->dma + -						     bi->page_offset + -						     igb_rx_offset(rx_ring)); +		rx_desc->read.pkt_addr = cpu_to_le64(bi->dma + bi->page_offset);  		rx_desc++;  		bi++; @@ -7724,67 +7611,6 @@ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba)  	}  } -static DEFINE_SPINLOCK(i2c_clients_lock); - -/*  igb_get_i2c_client - returns matching client - *  in adapters's client list. - *  @adapter: adapter struct - *  @dev_addr: device address of i2c needed. - */ -static struct i2c_client * -igb_get_i2c_client(struct igb_adapter *adapter, u8 dev_addr) -{ -	ulong flags; -	struct igb_i2c_client_list *client_list; -	struct i2c_client *client = NULL; -	struct i2c_board_info client_info = { -		I2C_BOARD_INFO("igb", 0x00), -	}; - -	spin_lock_irqsave(&i2c_clients_lock, flags); -	client_list = adapter->i2c_clients; - -	/* See if we already have an i2c_client */ -	while (client_list) { -		if (client_list->client->addr == (dev_addr >> 1)) { -			client = client_list->client; -			goto exit; -		} else { -			client_list = client_list->next; -		} -	} - -	/* no client_list found, create a new one */ -	client_list = kzalloc(sizeof(*client_list), GFP_ATOMIC); -	if (client_list == NULL) -		goto exit; - -	/* dev_addr passed to us is left-shifted by 1 bit -	 * i2c_new_device call expects it to be flush to the right. -	 */ -	client_info.addr = dev_addr >> 1; -	client_info.platform_data = adapter; -	client_list->client = i2c_new_device(&adapter->i2c_adap, &client_info); -	if (client_list->client == NULL) { -		dev_info(&adapter->pdev->dev, -			"Failed to create new i2c device..\n"); -		goto err_no_client; -	} - -	/* insert new client at head of list */ -	client_list->next = adapter->i2c_clients; -	adapter->i2c_clients = client_list; - -	client = client_list->client; -	goto exit; - -err_no_client: -	kfree(client_list); -exit: -	spin_unlock_irqrestore(&i2c_clients_lock, flags); -	return client; -} -  /*  igb_read_i2c_byte - Reads 8 bit word over I2C   *  @hw: pointer to hardware structure   *  @byte_offset: byte offset to read @@ -7798,7 +7624,7 @@ s32 igb_read_i2c_byte(struct e1000_hw *hw, u8 byte_offset,  				u8 dev_addr, u8 *data)  {  	struct igb_adapter *adapter = container_of(hw, struct igb_adapter, hw); -	struct i2c_client *this_client = igb_get_i2c_client(adapter, dev_addr); +	struct i2c_client *this_client = adapter->i2c_client;  	s32 status;  	u16 swfw_mask = 0; @@ -7835,7 +7661,7 @@ s32 igb_write_i2c_byte(struct e1000_hw *hw, u8 byte_offset,  				 u8 dev_addr, u8 data)  {  	struct igb_adapter *adapter = container_of(hw, struct igb_adapter, hw); -	struct i2c_client *this_client = igb_get_i2c_client(adapter, dev_addr); +	struct i2c_client *this_client = adapter->i2c_client;  	s32 status;  	u16 swfw_mask = E1000_SWFW_PHY0_SM; diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index 0987822359f..0a237507ee8 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -740,7 +740,7 @@ void igb_ptp_init(struct igb_adapter *adapter)  	case e1000_82576:  		snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr);  		adapter->ptp_caps.owner = THIS_MODULE; -		adapter->ptp_caps.max_adj = 1000000000; +		adapter->ptp_caps.max_adj = 999999881;  		adapter->ptp_caps.n_ext_ts = 0;  		adapter->ptp_caps.pps = 0;  		adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82576; diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c index ea480837343..b5f94abe3cf 100644 --- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c +++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c @@ -2159,6 +2159,10 @@ map_skb:  		                                  skb->data,  		                                  adapter->rx_buffer_len,  						  DMA_FROM_DEVICE); +		if (dma_mapping_error(&pdev->dev, buffer_info->dma)) { +			adapter->alloc_rx_buff_failed++; +			break; +		}  		rx_desc = IXGB_RX_DESC(*rx_ring, i);  		rx_desc->buff_addr = cpu_to_le64(buffer_info->dma); @@ -2168,7 +2172,8 @@ map_skb:  		rx_desc->status = 0; -		if (++i == rx_ring->count) i = 0; +		if (++i == rx_ring->count) +			i = 0;  		buffer_info = &rx_ring->buffer_info[i];  	} diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index db5611ae407..79f4a26ea6c 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -7922,12 +7922,19 @@ static int __init ixgbe_init_module(void)  	ixgbe_dbg_init();  #endif /* CONFIG_DEBUG_FS */ +	ret = pci_register_driver(&ixgbe_driver); +	if (ret) { +#ifdef CONFIG_DEBUG_FS +		ixgbe_dbg_exit(); +#endif /* CONFIG_DEBUG_FS */ +		return ret; +	} +  #ifdef CONFIG_IXGBE_DCA  	dca_register_notify(&dca_notifier);  #endif -	ret = pci_register_driver(&ixgbe_driver); -	return ret; +	return 0;  }  module_init(ixgbe_init_module); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c index d44b4d21268..97e33669c0b 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c @@ -1049,6 +1049,12 @@ int ixgbe_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)  	if ((vf >= adapter->num_vfs) || (vlan > 4095) || (qos > 7))  		return -EINVAL;  	if (vlan || qos) { +		if (adapter->vfinfo[vf].pf_vlan) +			err = ixgbe_set_vf_vlan(adapter, false, +						adapter->vfinfo[vf].pf_vlan, +						vf); +		if (err) +			goto out;  		err = ixgbe_set_vf_vlan(adapter, true, vlan, vf);  		if (err)  			goto out; diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index c3db6cd69b6..2b6cb5ca48e 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -944,9 +944,17 @@ free_queue_irqs:  		free_irq(adapter->msix_entries[vector].vector,  			 adapter->q_vector[vector]);  	} -	pci_disable_msix(adapter->pdev); -	kfree(adapter->msix_entries); -	adapter->msix_entries = NULL; +	/* This failure is non-recoverable - it indicates the system is +	 * out of MSIX vector resources and the VF driver cannot run +	 * without them.  Set the number of msix vectors to zero +	 * indicating that not enough can be allocated.  The error +	 * will be returned to the user indicating device open failed. +	 * Any further attempts to force the driver to open will also +	 * fail.  The only way to recover is to unload the driver and +	 * reload it again.  If the system has recovered some MSIX +	 * vectors then it may succeed. +	 */ +	adapter->num_msix_vectors = 0;  	return err;  } @@ -2572,6 +2580,15 @@ static int ixgbevf_open(struct net_device *netdev)  	struct ixgbe_hw *hw = &adapter->hw;  	int err; +	/* A previous failure to open the device because of a lack of +	 * available MSIX vector resources may have reset the number +	 * of msix vectors variable to zero.  The only way to recover +	 * is to unload/reload the driver and hope that the system has +	 * been able to recover some MSIX vector resources. +	 */ +	if (!adapter->num_msix_vectors) +		return -ENOMEM; +  	/* disallow open during test */  	if (test_bit(__IXGBEVF_TESTING, &adapter->state))  		return -EBUSY; @@ -2628,7 +2645,6 @@ static int ixgbevf_open(struct net_device *netdev)  err_req_irq:  	ixgbevf_down(adapter); -	ixgbevf_free_irq(adapter);  err_setup_rx:  	ixgbevf_free_all_rx_resources(adapter);  err_setup_tx: diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c index 6a2127489af..bfdb0686039 100644 --- a/drivers/net/ethernet/lantiq_etop.c +++ b/drivers/net/ethernet/lantiq_etop.c @@ -769,7 +769,7 @@ ltq_etop_probe(struct platform_device *pdev)  	return 0;  err_free: -	kfree(dev); +	free_netdev(dev);  err_out:  	return err;  } diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig index edfba937092..434e33c527d 100644 --- a/drivers/net/ethernet/marvell/Kconfig +++ b/drivers/net/ethernet/marvell/Kconfig @@ -33,6 +33,7 @@ config MV643XX_ETH  config MVMDIO  	tristate "Marvell MDIO interface support" +	select PHYLIB  	---help---  	  This driver supports the MDIO interface found in the network  	  interface units of the Marvell EBU SoCs (Kirkwood, Orion5x, @@ -45,7 +46,6 @@ config MVMDIO  config MVNETA  	tristate "Marvell Armada 370/XP network interface support"  	depends on MACH_ARMADA_370_XP -	select PHYLIB  	select MVMDIO  	---help---  	  This driver supports the network interface units in the diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index 29140502b71..6562c736a1d 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -1081,6 +1081,45 @@ static void txq_set_fixed_prio_mode(struct tx_queue *txq)  /* mii management interface *************************************************/ +static void mv643xx_adjust_pscr(struct mv643xx_eth_private *mp) +{ +	u32 pscr = rdlp(mp, PORT_SERIAL_CONTROL); +	u32 autoneg_disable = FORCE_LINK_PASS | +	             DISABLE_AUTO_NEG_SPEED_GMII | +		     DISABLE_AUTO_NEG_FOR_FLOW_CTRL | +		     DISABLE_AUTO_NEG_FOR_DUPLEX; + +	if (mp->phy->autoneg == AUTONEG_ENABLE) { +		/* enable auto negotiation */ +		pscr &= ~autoneg_disable; +		goto out_write; +	} + +	pscr |= autoneg_disable; + +	if (mp->phy->speed == SPEED_1000) { +		/* force gigabit, half duplex not supported */ +		pscr |= SET_GMII_SPEED_TO_1000; +		pscr |= SET_FULL_DUPLEX_MODE; +		goto out_write; +	} + +	pscr &= ~SET_GMII_SPEED_TO_1000; + +	if (mp->phy->speed == SPEED_100) +		pscr |= SET_MII_SPEED_TO_100; +	else +		pscr &= ~SET_MII_SPEED_TO_100; + +	if (mp->phy->duplex == DUPLEX_FULL) +		pscr |= SET_FULL_DUPLEX_MODE; +	else +		pscr &= ~SET_FULL_DUPLEX_MODE; + +out_write: +	wrlp(mp, PORT_SERIAL_CONTROL, pscr); +} +  static irqreturn_t mv643xx_eth_err_irq(int irq, void *dev_id)  {  	struct mv643xx_eth_shared_private *msp = dev_id; @@ -1499,6 +1538,7 @@ static int  mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)  {  	struct mv643xx_eth_private *mp = netdev_priv(dev); +	int ret;  	if (mp->phy == NULL)  		return -EINVAL; @@ -1508,7 +1548,10 @@ mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)  	 */  	cmd->advertising &= ~ADVERTISED_1000baseT_Half; -	return phy_ethtool_sset(mp->phy, cmd); +	ret = phy_ethtool_sset(mp->phy, cmd); +	if (!ret) +		mv643xx_adjust_pscr(mp); +	return ret;  }  static void mv643xx_eth_get_drvinfo(struct net_device *dev, @@ -2442,11 +2485,15 @@ static int mv643xx_eth_stop(struct net_device *dev)  static int mv643xx_eth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)  {  	struct mv643xx_eth_private *mp = netdev_priv(dev); +	int ret; -	if (mp->phy != NULL) -		return phy_mii_ioctl(mp->phy, ifr, cmd); +	if (mp->phy == NULL) +		return -ENOTSUPP; -	return -EOPNOTSUPP; +	ret = phy_mii_ioctl(mp->phy, ifr, cmd); +	if (!ret) +		mv643xx_adjust_pscr(mp); +	return ret;  }  static int mv643xx_eth_change_mtu(struct net_device *dev, int new_mtu) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index cd345b8969b..a47a097c21e 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -374,7 +374,6 @@ static int rxq_number = 8;  static int txq_number = 8;  static int rxq_def; -static int txq_def;  #define MVNETA_DRIVER_NAME "mvneta"  #define MVNETA_DRIVER_VERSION "1.0" @@ -1475,7 +1474,8 @@ error:  static int mvneta_tx(struct sk_buff *skb, struct net_device *dev)  {  	struct mvneta_port *pp = netdev_priv(dev); -	struct mvneta_tx_queue *txq = &pp->txqs[txq_def]; +	u16 txq_id = skb_get_queue_mapping(skb); +	struct mvneta_tx_queue *txq = &pp->txqs[txq_id];  	struct mvneta_tx_desc *tx_desc;  	struct netdev_queue *nq;  	int frags = 0; @@ -1485,7 +1485,7 @@ static int mvneta_tx(struct sk_buff *skb, struct net_device *dev)  		goto out;  	frags = skb_shinfo(skb)->nr_frags + 1; -	nq    = netdev_get_tx_queue(dev, txq_def); +	nq    = netdev_get_tx_queue(dev, txq_id);  	/* Get a descriptor for the first part of the packet */  	tx_desc = mvneta_txq_next_desc_get(txq); @@ -2689,7 +2689,7 @@ static int mvneta_probe(struct platform_device *pdev)  		return -EINVAL;  	} -	dev = alloc_etherdev_mq(sizeof(struct mvneta_port), 8); +	dev = alloc_etherdev_mqs(sizeof(struct mvneta_port), txq_number, rxq_number);  	if (!dev)  		return -ENOMEM; @@ -2771,16 +2771,17 @@ static int mvneta_probe(struct platform_device *pdev)  	netif_napi_add(dev, &pp->napi, mvneta_poll, pp->weight); +	dev->features = NETIF_F_SG | NETIF_F_IP_CSUM; +	dev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM; +	dev->vlan_features |= NETIF_F_SG | NETIF_F_IP_CSUM; +	dev->priv_flags |= IFF_UNICAST_FLT; +  	err = register_netdev(dev);  	if (err < 0) {  		dev_err(&pdev->dev, "failed to register\n");  		goto err_deinit;  	} -	dev->features = NETIF_F_SG | NETIF_F_IP_CSUM; -	dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM; -	dev->priv_flags |= IFF_UNICAST_FLT; -  	netdev_info(dev, "mac: %pM\n", dev->dev_addr);  	platform_set_drvdata(pdev, pp->dev); @@ -2843,4 +2844,3 @@ module_param(rxq_number, int, S_IRUGO);  module_param(txq_number, int, S_IRUGO);  module_param(rxq_def, int, S_IRUGO); -module_param(txq_def, int, S_IRUGO); diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index fc07ca35721..6a0e671fcec 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -1067,7 +1067,7 @@ static void sky2_ramset(struct sky2_hw *hw, u16 q, u32 start, u32 space)  		sky2_write32(hw, RB_ADDR(q, RB_RX_UTHP), tp);  		sky2_write32(hw, RB_ADDR(q, RB_RX_LTHP), space/2); -		tp = space - 2048/8; +		tp = space - 8192/8;  		sky2_write32(hw, RB_ADDR(q, RB_RX_UTPP), tp);  		sky2_write32(hw, RB_ADDR(q, RB_RX_LTPP), space/4);  	} else { diff --git a/drivers/net/ethernet/marvell/sky2.h b/drivers/net/ethernet/marvell/sky2.h index 615ac63ea86..ec6dcd80152 100644 --- a/drivers/net/ethernet/marvell/sky2.h +++ b/drivers/net/ethernet/marvell/sky2.h @@ -2074,7 +2074,7 @@ enum {  	GM_IS_RX_FF_OR	= 1<<1,	/* Receive FIFO Overrun */  	GM_IS_RX_COMPL	= 1<<0,	/* Frame Reception Complete */ -#define GMAC_DEF_MSK     GM_IS_TX_FF_UR +#define GMAC_DEF_MSK     (GM_IS_TX_FF_UR | GM_IS_RX_FF_OR)  };  /*	GMAC_LINK_CTRL	16 bit	GMAC Link Control Reg (YUKON only) */ diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c index 7e64033d7de..0706623cfb9 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cq.c +++ b/drivers/net/ethernet/mellanox/mlx4/cq.c @@ -226,7 +226,7 @@ void __mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn)  static void mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn)  { -	u64 in_param; +	u64 in_param = 0;  	int err;  	if (mlx4_is_mfunc(dev)) { diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index bb4d8d99f36..30d78f806dc 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -411,8 +411,8 @@ static int mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)  static void mlx4_en_u64_to_mac(unsigned char dst_mac[ETH_ALEN + 2], u64 src_mac)  { -	unsigned int i; -	for (i = ETH_ALEN - 1; i; --i) { +	int i; +	for (i = ETH_ALEN - 1; i >= 0; --i) {  		dst_mac[i] = src_mac & 0xff;  		src_mac >>= 8;  	} @@ -565,34 +565,38 @@ static void mlx4_en_put_qp(struct mlx4_en_priv *priv)  	struct mlx4_en_dev *mdev = priv->mdev;  	struct mlx4_dev *dev = mdev->dev;  	int qpn = priv->base_qpn; -	u64 mac = mlx4_en_mac_to_u64(priv->dev->dev_addr); - -	en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n", -	       priv->dev->dev_addr); -	mlx4_unregister_mac(dev, priv->port, mac); +	u64 mac; -	if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) { +	if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) { +		mac = mlx4_en_mac_to_u64(priv->dev->dev_addr); +		en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n", +		       priv->dev->dev_addr); +		mlx4_unregister_mac(dev, priv->port, mac); +	} else {  		struct mlx4_mac_entry *entry;  		struct hlist_node *tmp;  		struct hlist_head *bucket; -		unsigned int mac_hash; +		unsigned int i; -		mac_hash = priv->dev->dev_addr[MLX4_EN_MAC_HASH_IDX]; -		bucket = &priv->mac_hash[mac_hash]; -		hlist_for_each_entry_safe(entry, tmp, bucket, hlist) { -			if (ether_addr_equal_64bits(entry->mac, -						    priv->dev->dev_addr)) { -				en_dbg(DRV, priv, "Releasing qp: port %d, MAC %pM, qpn %d\n", -				       priv->port, priv->dev->dev_addr, qpn); +		for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) { +			bucket = &priv->mac_hash[i]; +			hlist_for_each_entry_safe(entry, tmp, bucket, hlist) { +				mac = mlx4_en_mac_to_u64(entry->mac); +				en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n", +				       entry->mac);  				mlx4_en_uc_steer_release(priv, entry->mac,  							 qpn, entry->reg_id); -				mlx4_qp_release_range(dev, qpn, 1); +				mlx4_unregister_mac(dev, priv->port, mac);  				hlist_del_rcu(&entry->hlist);  				kfree_rcu(entry, rcu); -				break;  			}  		} + +		en_dbg(DRV, priv, "Releasing qp: port %d, qpn %d\n", +		       priv->port, qpn); +		mlx4_qp_release_range(dev, qpn, 1); +		priv->flags &= ~MLX4_EN_FLAG_FORCE_PROMISC;  	}  } @@ -650,28 +654,10 @@ u64 mlx4_en_mac_to_u64(u8 *addr)  	return mac;  } -static int mlx4_en_set_mac(struct net_device *dev, void *addr) +static int mlx4_en_do_set_mac(struct mlx4_en_priv *priv)  { -	struct mlx4_en_priv *priv = netdev_priv(dev); -	struct mlx4_en_dev *mdev = priv->mdev; -	struct sockaddr *saddr = addr; - -	if (!is_valid_ether_addr(saddr->sa_data)) -		return -EADDRNOTAVAIL; - -	memcpy(dev->dev_addr, saddr->sa_data, ETH_ALEN); -	queue_work(mdev->workqueue, &priv->mac_task); -	return 0; -} - -static void mlx4_en_do_set_mac(struct work_struct *work) -{ -	struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, -						 mac_task); -	struct mlx4_en_dev *mdev = priv->mdev;  	int err = 0; -	mutex_lock(&mdev->state_lock);  	if (priv->port_up) {  		/* Remove old MAC and insert the new one */  		err = mlx4_en_replace_mac(priv, priv->base_qpn, @@ -683,7 +669,26 @@ static void mlx4_en_do_set_mac(struct work_struct *work)  	} else  		en_dbg(HW, priv, "Port is down while registering mac, exiting...\n"); +	return err; +} + +static int mlx4_en_set_mac(struct net_device *dev, void *addr) +{ +	struct mlx4_en_priv *priv = netdev_priv(dev); +	struct mlx4_en_dev *mdev = priv->mdev; +	struct sockaddr *saddr = addr; +	int err; + +	if (!is_valid_ether_addr(saddr->sa_data)) +		return -EADDRNOTAVAIL; + +	memcpy(dev->dev_addr, saddr->sa_data, ETH_ALEN); + +	mutex_lock(&mdev->state_lock); +	err = mlx4_en_do_set_mac(priv);  	mutex_unlock(&mdev->state_lock); + +	return err;  }  static void mlx4_en_clear_list(struct net_device *dev) @@ -1348,7 +1353,7 @@ static void mlx4_en_do_get_stats(struct work_struct *work)  		queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY);  	}  	if (mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port]) { -		queue_work(mdev->workqueue, &priv->mac_task); +		mlx4_en_do_set_mac(priv);  		mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port] = 0;  	}  	mutex_unlock(&mdev->state_lock); @@ -1632,6 +1637,17 @@ void mlx4_en_stop_port(struct net_device *dev, int detach)  	/* Flush multicast filter */  	mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 1, MLX4_MCAST_CONFIG); +	/* Remove flow steering rules for the port*/ +	if (mdev->dev->caps.steering_mode == +	    MLX4_STEERING_MODE_DEVICE_MANAGED) { +		ASSERT_RTNL(); +		list_for_each_entry_safe(flow, tmp_flow, +					 &priv->ethtool_list, list) { +			mlx4_flow_detach(mdev->dev, flow->id); +			list_del(&flow->list); +		} +	} +  	mlx4_en_destroy_drop_qp(priv);  	/* Free TX Rings */ @@ -1652,17 +1668,6 @@ void mlx4_en_stop_port(struct net_device *dev, int detach)  	if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAGS2_REASSIGN_MAC_EN))  		mdev->mac_removed[priv->port] = 1; -	/* Remove flow steering rules for the port*/ -	if (mdev->dev->caps.steering_mode == -	    MLX4_STEERING_MODE_DEVICE_MANAGED) { -		ASSERT_RTNL(); -		list_for_each_entry_safe(flow, tmp_flow, -					 &priv->ethtool_list, list) { -			mlx4_flow_detach(mdev->dev, flow->id); -			list_del(&flow->list); -		} -	} -  	/* Free RX Rings */  	for (i = 0; i < priv->rx_ring_num; i++) {  		mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]); @@ -1828,9 +1833,11 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv)  	}  #ifdef CONFIG_RFS_ACCEL -	priv->dev->rx_cpu_rmap = alloc_irq_cpu_rmap(priv->mdev->dev->caps.comp_pool); -	if (!priv->dev->rx_cpu_rmap) -		goto err; +	if (priv->mdev->dev->caps.comp_pool) { +		priv->dev->rx_cpu_rmap = alloc_irq_cpu_rmap(priv->mdev->dev->caps.comp_pool); +		if (!priv->dev->rx_cpu_rmap) +			goto err; +	}  #endif  	return 0; @@ -2078,7 +2085,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,  	priv->msg_enable = MLX4_EN_MSG_LEVEL;  	spin_lock_init(&priv->stats_lock);  	INIT_WORK(&priv->rx_mode_task, mlx4_en_do_set_rx_mode); -	INIT_WORK(&priv->mac_task, mlx4_en_do_set_mac);  	INIT_WORK(&priv->watchdog_task, mlx4_en_restart);  	INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate);  	INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats); diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index 251ae2f9311..8e3123a1df8 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -771,7 +771,7 @@ int mlx4_MAP_EQ_wrapper(struct mlx4_dev *dev, int slave,  	struct mlx4_slave_event_eq_info *event_eq =  		priv->mfunc.master.slave_state[slave].event_eq;  	u32 in_modifier = vhcr->in_modifier; -	u32 eqn = in_modifier & 0x1FF; +	u32 eqn = in_modifier & 0x3FF;  	u64 in_param =  vhcr->in_param;  	int err = 0;  	int i; diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 50917eb3013..f6245579962 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -787,6 +787,14 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,  	bmme_flags &= ~MLX4_BMME_FLAG_TYPE_2_WIN;  	MLX4_PUT(outbox->buf, bmme_flags, QUERY_DEV_CAP_BMME_FLAGS_OFFSET); +	/* turn off device-managed steering capability if not enabled */ +	if (dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED) { +		MLX4_GET(field, outbox->buf, +			 QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET); +		field &= 0x7f; +		MLX4_PUT(outbox->buf, field, +			 QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET); +	}  	return 0;  } diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index d180bc46826..16abde20e1f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -1555,7 +1555,7 @@ void __mlx4_counter_free(struct mlx4_dev *dev, u32 idx)  void mlx4_counter_free(struct mlx4_dev *dev, u32 idx)  { -	u64 in_param; +	u64 in_param = 0;  	if (mlx4_is_mfunc(dev)) {  		set_param_l(&in_param, idx); diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index cf883345af8..d738454116a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -1235,7 +1235,7 @@ int mlx4_get_qp_per_mgm(struct mlx4_dev *dev);  static inline void set_param_l(u64 *arg, u32 val)  { -	*((u32 *)arg) = val; +	*arg = (*arg & 0xffffffff00000000ULL) | (u64) val;  }  static inline void set_param_h(u64 *arg, u32 val) diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index c313d7e943a..f710b7ce0dc 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -509,7 +509,6 @@ struct mlx4_en_priv {  	struct mlx4_en_cq rx_cq[MAX_RX_RINGS];  	struct mlx4_qp drop_qp;  	struct work_struct rx_mode_task; -	struct work_struct mac_task;  	struct work_struct watchdog_task;  	struct work_struct linkstate_task;  	struct delayed_work stats_task; diff --git a/drivers/net/ethernet/mellanox/mlx4/mr.c b/drivers/net/ethernet/mellanox/mlx4/mr.c index 602ca9bf78e..f91719a08cb 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mr.c +++ b/drivers/net/ethernet/mellanox/mlx4/mr.c @@ -183,7 +183,7 @@ u32 __mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order)  static u32 mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order)  { -	u64 in_param; +	u64 in_param = 0;  	u64 out_param;  	int err; @@ -240,7 +240,7 @@ void __mlx4_free_mtt_range(struct mlx4_dev *dev, u32 offset, int order)  static void mlx4_free_mtt_range(struct mlx4_dev *dev, u32 offset, int order)  { -	u64 in_param; +	u64 in_param = 0;  	int err;  	if (mlx4_is_mfunc(dev)) { @@ -351,7 +351,7 @@ void __mlx4_mpt_release(struct mlx4_dev *dev, u32 index)  static void mlx4_mpt_release(struct mlx4_dev *dev, u32 index)  { -	u64 in_param; +	u64 in_param = 0;  	if (mlx4_is_mfunc(dev)) {  		set_param_l(&in_param, index); @@ -374,7 +374,7 @@ int __mlx4_mpt_alloc_icm(struct mlx4_dev *dev, u32 index)  static int mlx4_mpt_alloc_icm(struct mlx4_dev *dev, u32 index)  { -	u64 param; +	u64 param = 0;  	if (mlx4_is_mfunc(dev)) {  		set_param_l(¶m, index); @@ -395,7 +395,7 @@ void __mlx4_mpt_free_icm(struct mlx4_dev *dev, u32 index)  static void mlx4_mpt_free_icm(struct mlx4_dev *dev, u32 index)  { -	u64 in_param; +	u64 in_param = 0;  	if (mlx4_is_mfunc(dev)) {  		set_param_l(&in_param, index); diff --git a/drivers/net/ethernet/mellanox/mlx4/pd.c b/drivers/net/ethernet/mellanox/mlx4/pd.c index 1ac88637ad9..00f223acada 100644 --- a/drivers/net/ethernet/mellanox/mlx4/pd.c +++ b/drivers/net/ethernet/mellanox/mlx4/pd.c @@ -101,7 +101,7 @@ void __mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn)  void mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn)  { -	u64 in_param; +	u64 in_param = 0;  	int err;  	if (mlx4_is_mfunc(dev)) { diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c index 719ead15e49..10c57c86388 100644 --- a/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/drivers/net/ethernet/mellanox/mlx4/port.c @@ -175,7 +175,7 @@ EXPORT_SYMBOL_GPL(__mlx4_register_mac);  int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)  { -	u64 out_param; +	u64 out_param = 0;  	int err;  	if (mlx4_is_mfunc(dev)) { @@ -222,7 +222,7 @@ EXPORT_SYMBOL_GPL(__mlx4_unregister_mac);  void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)  { -	u64 out_param; +	u64 out_param = 0;  	if (mlx4_is_mfunc(dev)) {  		set_param_l(&out_param, port); @@ -361,7 +361,7 @@ out:  int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index)  { -	u64 out_param; +	u64 out_param = 0;  	int err;  	if (mlx4_is_mfunc(dev)) { @@ -406,7 +406,7 @@ out:  void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index)  { -	u64 in_param; +	u64 in_param = 0;  	int err;  	if (mlx4_is_mfunc(dev)) { diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c index 81e2abe07bb..e891b058c1b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/qp.c +++ b/drivers/net/ethernet/mellanox/mlx4/qp.c @@ -222,7 +222,7 @@ int __mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align,  int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, int *base)  { -	u64 in_param; +	u64 in_param = 0;  	u64 out_param;  	int err; @@ -255,7 +255,7 @@ void __mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt)  void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt)  { -	u64 in_param; +	u64 in_param = 0;  	int err;  	if (mlx4_is_mfunc(dev)) { @@ -319,7 +319,7 @@ err_out:  static int mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn)  { -	u64 param; +	u64 param = 0;  	if (mlx4_is_mfunc(dev)) {  		set_param_l(¶m, qpn); @@ -344,7 +344,7 @@ void __mlx4_qp_free_icm(struct mlx4_dev *dev, int qpn)  static void mlx4_qp_free_icm(struct mlx4_dev *dev, int qpn)  { -	u64 in_param; +	u64 in_param = 0;  	if (mlx4_is_mfunc(dev)) {  		set_param_l(&in_param, qpn); diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 083fb48dc3d..1391b52f443 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -99,6 +99,7 @@ struct res_qp {  	struct list_head	mcg_list;  	spinlock_t		mcg_spl;  	int			local_qpn; +	atomic_t		ref_count;  };  enum res_mtt_states { @@ -197,6 +198,7 @@ enum res_fs_rule_states {  struct res_fs_rule {  	struct res_common	com; +	int			qpn;  };  static void *res_tracker_lookup(struct rb_root *root, u64 res_id) @@ -355,7 +357,7 @@ static int mpt_mask(struct mlx4_dev *dev)  	return dev->caps.num_mpts - 1;  } -static void *find_res(struct mlx4_dev *dev, int res_id, +static void *find_res(struct mlx4_dev *dev, u64 res_id,  		      enum mlx4_resource type)  {  	struct mlx4_priv *priv = mlx4_priv(dev); @@ -447,6 +449,7 @@ static struct res_common *alloc_qp_tr(int id)  	ret->local_qpn = id;  	INIT_LIST_HEAD(&ret->mcg_list);  	spin_lock_init(&ret->mcg_spl); +	atomic_set(&ret->ref_count, 0);  	return &ret->com;  } @@ -554,7 +557,7 @@ static struct res_common *alloc_xrcdn_tr(int id)  	return &ret->com;  } -static struct res_common *alloc_fs_rule_tr(u64 id) +static struct res_common *alloc_fs_rule_tr(u64 id, int qpn)  {  	struct res_fs_rule *ret; @@ -564,7 +567,7 @@ static struct res_common *alloc_fs_rule_tr(u64 id)  	ret->com.res_id = id;  	ret->com.state = RES_FS_RULE_ALLOCATED; - +	ret->qpn = qpn;  	return &ret->com;  } @@ -602,7 +605,7 @@ static struct res_common *alloc_tr(u64 id, enum mlx4_resource type, int slave,  		ret = alloc_xrcdn_tr(id);  		break;  	case RES_FS_RULE: -		ret = alloc_fs_rule_tr(id); +		ret = alloc_fs_rule_tr(id, extra);  		break;  	default:  		return NULL; @@ -671,10 +674,14 @@ undo:  static int remove_qp_ok(struct res_qp *res)  { -	if (res->com.state == RES_QP_BUSY) +	if (res->com.state == RES_QP_BUSY || atomic_read(&res->ref_count) || +	    !list_empty(&res->mcg_list)) { +		pr_err("resource tracker: fail to remove qp, state %d, ref_count %d\n", +		       res->com.state, atomic_read(&res->ref_count));  		return -EBUSY; -	else if (res->com.state != RES_QP_RESERVED) +	} else if (res->com.state != RES_QP_RESERVED) {  		return -EPERM; +	}  	return 0;  } @@ -2990,6 +2997,9 @@ int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave,  	u8 steer_type_mask = 2;  	enum mlx4_steer_type type = (gid[7] & steer_type_mask) >> 1; +	if (dev->caps.steering_mode != MLX4_STEERING_MODE_B0) +		return -EINVAL; +  	qpn = vhcr->in_modifier & 0xffffff;  	err = get_res(dev, slave, qpn, RES_QP, &rqp);  	if (err) @@ -3121,6 +3131,7 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,  	struct list_head *rlist = &tracker->slave_list[slave].res_list[RES_MAC];  	int err;  	int qpn; +	struct res_qp *rqp;  	struct mlx4_net_trans_rule_hw_ctrl *ctrl;  	struct _rule_hw  *rule_header;  	int header_id; @@ -3131,7 +3142,7 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,  	ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf;  	qpn = be32_to_cpu(ctrl->qpn) & 0xffffff; -	err = get_res(dev, slave, qpn, RES_QP, NULL); +	err = get_res(dev, slave, qpn, RES_QP, &rqp);  	if (err) {  		pr_err("Steering rule with qpn 0x%x rejected.\n", qpn);  		return err; @@ -3172,14 +3183,16 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,  	if (err)  		goto err_put; -	err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, 0); +	err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, qpn);  	if (err) {  		mlx4_err(dev, "Fail to add flow steering resources.\n ");  		/* detach rule*/  		mlx4_cmd(dev, vhcr->out_param, 0, 0,  			 MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,  			 MLX4_CMD_NATIVE); +		goto err_put;  	} +	atomic_inc(&rqp->ref_count);  err_put:  	put_res(dev, slave, qpn, RES_QP);  	return err; @@ -3192,20 +3205,35 @@ int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave,  					 struct mlx4_cmd_info *cmd)  {  	int err; +	struct res_qp *rqp; +	struct res_fs_rule *rrule;  	if (dev->caps.steering_mode !=  	    MLX4_STEERING_MODE_DEVICE_MANAGED)  		return -EOPNOTSUPP; +	err = get_res(dev, slave, vhcr->in_param, RES_FS_RULE, &rrule); +	if (err) +		return err; +	/* Release the rule form busy state before removal */ +	put_res(dev, slave, vhcr->in_param, RES_FS_RULE); +	err = get_res(dev, slave, rrule->qpn, RES_QP, &rqp); +	if (err) +		return err; +  	err = rem_res_range(dev, slave, vhcr->in_param, 1, RES_FS_RULE, 0);  	if (err) {  		mlx4_err(dev, "Fail to remove flow steering resources.\n "); -		return err; +		goto out;  	}  	err = mlx4_cmd(dev, vhcr->in_param, 0, 0,  		       MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,  		       MLX4_CMD_NATIVE); +	if (!err) +		atomic_dec(&rqp->ref_count); +out: +	put_res(dev, slave, rrule->qpn, RES_QP);  	return err;  } @@ -3803,6 +3831,7 @@ void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave)  	mutex_lock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex);  	/*VLAN*/  	rem_slave_macs(dev, slave); +	rem_slave_fs_rule(dev, slave);  	rem_slave_qps(dev, slave);  	rem_slave_srqs(dev, slave);  	rem_slave_cqs(dev, slave); @@ -3811,6 +3840,5 @@ void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave)  	rem_slave_mtts(dev, slave);  	rem_slave_counters(dev, slave);  	rem_slave_xrcdns(dev, slave); -	rem_slave_fs_rule(dev, slave);  	mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex);  } diff --git a/drivers/net/ethernet/mellanox/mlx4/srq.c b/drivers/net/ethernet/mellanox/mlx4/srq.c index feda6c00829..e329fe1f11b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/srq.c +++ b/drivers/net/ethernet/mellanox/mlx4/srq.c @@ -149,7 +149,7 @@ void __mlx4_srq_free_icm(struct mlx4_dev *dev, int srqn)  static void mlx4_srq_free_icm(struct mlx4_dev *dev, int srqn)  { -	u64 in_param; +	u64 in_param = 0;  	if (mlx4_is_mfunc(dev)) {  		set_param_l(&in_param, srqn); diff --git a/drivers/net/ethernet/micrel/ks8851.c b/drivers/net/ethernet/micrel/ks8851.c index 33bcb63d56a..8fb481252e2 100644 --- a/drivers/net/ethernet/micrel/ks8851.c +++ b/drivers/net/ethernet/micrel/ks8851.c @@ -528,7 +528,7 @@ static void ks8851_rx_pkts(struct ks8851_net *ks)  	for (; rxfc != 0; rxfc--) {  		rxh = ks8851_rdreg32(ks, KS_RXFHSR);  		rxstat = rxh & 0xffff; -		rxlen = rxh >> 16; +		rxlen = (rxh >> 16) & 0xfff;  		netif_dbg(ks, rx_status, ks->netdev,  			  "rx: stat 0x%04x, len 0x%04x\n", rxstat, rxlen); diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c index c4122c86f82..efa29b712d5 100644 --- a/drivers/net/ethernet/nxp/lpc_eth.c +++ b/drivers/net/ethernet/nxp/lpc_eth.c @@ -1472,7 +1472,8 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)  	}  	platform_set_drvdata(pdev, ndev); -	if (lpc_mii_init(pldat) != 0) +	ret = lpc_mii_init(pldat); +	if (ret)  		goto err_out_unregister_netdev;  	netdev_info(ndev, "LPC mac at 0x%08x irq %d\n", diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c index 39ab4d09faa..73ce7dd6b95 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c @@ -1726,9 +1726,9 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,  			skb->protocol = eth_type_trans(skb, netdev);  			if (tcp_ip_status & PCH_GBE_RXD_ACC_STAT_TCPIPOK) -				skb->ip_summed = CHECKSUM_NONE; -			else  				skb->ip_summed = CHECKSUM_UNNECESSARY; +			else +				skb->ip_summed = CHECKSUM_NONE;  			napi_gro_receive(&adapter->napi, skb);  			(*work_done)++; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index cd5ae8813cb..edd63f1230f 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -1500,6 +1500,12 @@ int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode)  		}  	} while ((adapter->ahw->linkup && ahw->has_link_events) != 1); +	/* Make sure carrier is off and queue is stopped during loopback */ +	if (netif_running(netdev)) { +		netif_carrier_off(netdev); +		netif_stop_queue(netdev); +	} +  	ret = qlcnic_do_lb_test(adapter, mode);  	qlcnic_83xx_clear_lb_mode(adapter, mode); @@ -2780,6 +2786,7 @@ static u64 *qlcnic_83xx_fill_stats(struct qlcnic_adapter *adapter,  void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data)  {  	struct qlcnic_cmd_args cmd; +	struct net_device *netdev = adapter->netdev;  	int ret = 0;  	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_STATISTICS); @@ -2789,7 +2796,7 @@ void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data)  	data = qlcnic_83xx_fill_stats(adapter, &cmd, data,  				      QLC_83XX_STAT_TX, &ret);  	if (ret) { -		dev_info(&adapter->pdev->dev, "Error getting MAC stats\n"); +		netdev_err(netdev, "Error getting Tx stats\n");  		goto out;  	}  	/* Get MAC stats */ @@ -2799,8 +2806,7 @@ void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data)  	data = qlcnic_83xx_fill_stats(adapter, &cmd, data,  				      QLC_83XX_STAT_MAC, &ret);  	if (ret) { -		dev_info(&adapter->pdev->dev, -			 "Error getting Rx stats\n"); +		netdev_err(netdev, "Error getting MAC stats\n");  		goto out;  	}  	/* Get Rx stats */ @@ -2810,8 +2816,7 @@ void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data)  	data = qlcnic_83xx_fill_stats(adapter, &cmd, data,  				      QLC_83XX_STAT_RX, &ret);  	if (ret) -		dev_info(&adapter->pdev->dev, -			 "Error getting Tx stats\n"); +		netdev_err(netdev, "Error getting Rx stats\n");  out:  	qlcnic_free_mbx_args(&cmd);  } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index 0e630061bff..5fa847fe388 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c @@ -358,8 +358,7 @@ set_flags:  		memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN);  	}  	opcode = TX_ETHER_PKT; -	if ((adapter->netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) && -	    skb_shinfo(skb)->gso_size > 0) { +	if (skb_is_gso(skb)) {  		hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);  		first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);  		first_desc->total_hdr_length = hdr_len; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c index 987fb6f8adc..5ef328af61d 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c @@ -200,10 +200,10 @@ beacon_err:  	}  	err = qlcnic_config_led(adapter, b_state, b_rate); -	if (!err) +	if (!err) {  		err = len; -	else  		ahw->beacon_state = b_state; +	}  	if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state))  		qlcnic_diag_free_res(adapter->netdev, max_sds_rings); diff --git a/drivers/net/ethernet/qlogic/qlge/qlge.h b/drivers/net/ethernet/qlogic/qlge/qlge.h index a131d7b5d2f..7e8d6826396 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge.h +++ b/drivers/net/ethernet/qlogic/qlge/qlge.h @@ -18,7 +18,7 @@   */  #define DRV_NAME  	"qlge"  #define DRV_STRING 	"QLogic 10 Gigabit PCI-E Ethernet Driver " -#define DRV_VERSION	"v1.00.00.31" +#define DRV_VERSION	"v1.00.00.32"  #define WQ_ADDR_ALIGN	0x3	/* 4 byte alignment */ diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_ethtool.c b/drivers/net/ethernet/qlogic/qlge/qlge_ethtool.c index 6f316ab2325..0780e039b27 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_ethtool.c @@ -379,13 +379,13 @@ static int ql_get_settings(struct net_device *ndev,  	ecmd->supported = SUPPORTED_10000baseT_Full;  	ecmd->advertising = ADVERTISED_10000baseT_Full; -	ecmd->autoneg = AUTONEG_ENABLE;  	ecmd->transceiver = XCVR_EXTERNAL;  	if ((qdev->link_status & STS_LINK_TYPE_MASK) ==  				STS_LINK_TYPE_10GBASET) {  		ecmd->supported |= (SUPPORTED_TP | SUPPORTED_Autoneg);  		ecmd->advertising |= (ADVERTISED_TP | ADVERTISED_Autoneg);  		ecmd->port = PORT_TP; +		ecmd->autoneg = AUTONEG_ENABLE;  	} else {  		ecmd->supported |= SUPPORTED_FIBRE;  		ecmd->advertising |= ADVERTISED_FIBRE; diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c index b13ab544a7e..8033555e53c 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c @@ -1434,11 +1434,13 @@ map_error:  }  /* Categorizing receive firmware frame errors */ -static void ql_categorize_rx_err(struct ql_adapter *qdev, u8 rx_err) +static void ql_categorize_rx_err(struct ql_adapter *qdev, u8 rx_err, +				 struct rx_ring *rx_ring)  {  	struct nic_stats *stats = &qdev->nic_stats;  	stats->rx_err_count++; +	rx_ring->rx_errors++;  	switch (rx_err & IB_MAC_IOCB_RSP_ERR_MASK) {  	case IB_MAC_IOCB_RSP_ERR_CODE_ERR: @@ -1474,6 +1476,12 @@ static void ql_process_mac_rx_gro_page(struct ql_adapter *qdev,  	struct bq_desc *lbq_desc = ql_get_curr_lchunk(qdev, rx_ring);  	struct napi_struct *napi = &rx_ring->napi; +	/* Frame error, so drop the packet. */ +	if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) { +		ql_categorize_rx_err(qdev, ib_mac_rsp->flags2, rx_ring); +		put_page(lbq_desc->p.pg_chunk.page); +		return; +	}  	napi->dev = qdev->ndev;  	skb = napi_get_frags(napi); @@ -1529,6 +1537,12 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev,  	addr = lbq_desc->p.pg_chunk.va;  	prefetch(addr); +	/* Frame error, so drop the packet. */ +	if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) { +		ql_categorize_rx_err(qdev, ib_mac_rsp->flags2, rx_ring); +		goto err_out; +	} +  	/* The max framesize filter on this chip is set higher than  	 * MTU since FCoE uses 2k frames.  	 */ @@ -1614,6 +1628,13 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev,  	memcpy(skb_put(new_skb, length), skb->data, length);  	skb = new_skb; +	/* Frame error, so drop the packet. */ +	if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) { +		ql_categorize_rx_err(qdev, ib_mac_rsp->flags2, rx_ring); +		dev_kfree_skb_any(skb); +		return; +	} +  	/* loopback self test for ethtool */  	if (test_bit(QL_SELFTEST, &qdev->flags)) {  		ql_check_lb_frame(qdev, skb); @@ -1919,6 +1940,13 @@ static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev,  		return;  	} +	/* Frame error, so drop the packet. */ +	if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) { +		ql_categorize_rx_err(qdev, ib_mac_rsp->flags2, rx_ring); +		dev_kfree_skb_any(skb); +		return; +	} +  	/* The max framesize filter on this chip is set higher than  	 * MTU since FCoE uses 2k frames.  	 */ @@ -2000,12 +2028,6 @@ static unsigned long ql_process_mac_rx_intr(struct ql_adapter *qdev,  	QL_DUMP_IB_MAC_RSP(ib_mac_rsp); -	/* Frame error, so drop the packet. */ -	if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) { -		ql_categorize_rx_err(qdev, ib_mac_rsp->flags2); -		return (unsigned long)length; -	} -  	if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HV) {  		/* The data and headers are split into  		 * separate buffers. diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 8900398ba10..4ecbe64a758 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -3818,6 +3818,30 @@ static void rtl_init_mdio_ops(struct rtl8169_private *tp)  	}  } +static void rtl_speed_down(struct rtl8169_private *tp) +{ +	u32 adv; +	int lpa; + +	rtl_writephy(tp, 0x1f, 0x0000); +	lpa = rtl_readphy(tp, MII_LPA); + +	if (lpa & (LPA_10HALF | LPA_10FULL)) +		adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full; +	else if (lpa & (LPA_100HALF | LPA_100FULL)) +		adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | +		      ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full; +	else +		adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | +		      ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | +		      (tp->mii.supports_gmii ? +		       ADVERTISED_1000baseT_Half | +		       ADVERTISED_1000baseT_Full : 0); + +	rtl8169_set_speed(tp->dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL, +			  adv); +} +  static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)  {  	void __iomem *ioaddr = tp->mmio_addr; @@ -3848,9 +3872,7 @@ static bool rtl_wol_pll_power_down(struct rtl8169_private *tp)  	if (!(__rtl8169_get_wol(tp) & WAKE_ANY))  		return false; -	rtl_writephy(tp, 0x1f, 0x0000); -	rtl_writephy(tp, MII_BMCR, 0x0000); - +	rtl_speed_down(tp);  	rtl_wol_suspend_quirk(tp);  	return true; @@ -4765,8 +4787,10 @@ static void rtl_hw_start_8168bb(struct rtl8169_private *tp)  	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); -	rtl_tx_performance_tweak(pdev, -		(0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN); +	if (tp->dev->mtu <= ETH_DATA_LEN) { +		rtl_tx_performance_tweak(pdev, (0x5 << MAX_READ_REQUEST_SHIFT) | +					 PCI_EXP_DEVCTL_NOSNOOP_EN); +	}  }  static void rtl_hw_start_8168bef(struct rtl8169_private *tp) @@ -4789,7 +4813,8 @@ static void __rtl_hw_start_8168cp(struct rtl8169_private *tp)  	RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); -	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); +	if (tp->dev->mtu <= ETH_DATA_LEN) +		rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);  	rtl_disable_clock_request(pdev); @@ -4822,7 +4847,8 @@ static void rtl_hw_start_8168cp_2(struct rtl8169_private *tp)  	RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); -	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); +	if (tp->dev->mtu <= ETH_DATA_LEN) +		rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);  	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);  } @@ -4841,7 +4867,8 @@ static void rtl_hw_start_8168cp_3(struct rtl8169_private *tp)  	RTL_W8(MaxTxPacketSize, TxPacketMax); -	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); +	if (tp->dev->mtu <= ETH_DATA_LEN) +		rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);  	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);  } @@ -4901,7 +4928,8 @@ static void rtl_hw_start_8168d(struct rtl8169_private *tp)  	RTL_W8(MaxTxPacketSize, TxPacketMax); -	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); +	if (tp->dev->mtu <= ETH_DATA_LEN) +		rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);  	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);  } @@ -4913,7 +4941,8 @@ static void rtl_hw_start_8168dp(struct rtl8169_private *tp)  	rtl_csi_access_enable_1(tp); -	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); +	if (tp->dev->mtu <= ETH_DATA_LEN) +		rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);  	RTL_W8(MaxTxPacketSize, TxPacketMax); @@ -4972,7 +5001,8 @@ static void rtl_hw_start_8168e_1(struct rtl8169_private *tp)  	rtl_ephy_init(tp, e_info_8168e_1, ARRAY_SIZE(e_info_8168e_1)); -	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); +	if (tp->dev->mtu <= ETH_DATA_LEN) +		rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);  	RTL_W8(MaxTxPacketSize, TxPacketMax); @@ -4998,7 +5028,8 @@ static void rtl_hw_start_8168e_2(struct rtl8169_private *tp)  	rtl_ephy_init(tp, e_info_8168e_2, ARRAY_SIZE(e_info_8168e_2)); -	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); +	if (tp->dev->mtu <= ETH_DATA_LEN) +		rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);  	rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);  	rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC); diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 33e96176e4d..6ed333fe5c0 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -1216,10 +1216,7 @@ static void sh_eth_error(struct net_device *ndev, int intr_status)  		if (felic_stat & ECSR_LCHNG) {  			/* Link Changed */  			if (mdp->cd->no_psr || mdp->no_ether_link) { -				if (mdp->link == PHY_DOWN) -					link_stat = 0; -				else -					link_stat = PHY_ST_LINK; +				goto ignore_link;  			} else {  				link_stat = (sh_eth_read(ndev, PSR));  				if (mdp->ether_link_active_low) @@ -1242,6 +1239,7 @@ static void sh_eth_error(struct net_device *ndev, int intr_status)  		}  	} +ignore_link:  	if (intr_status & EESR_TWB) {  		/* Write buck end. unused write back interrupt */  		if (intr_status & EESR_TABT)	/* Transmit Abort int */ @@ -1326,12 +1324,18 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)  	struct sh_eth_private *mdp = netdev_priv(ndev);  	struct sh_eth_cpu_data *cd = mdp->cd;  	irqreturn_t ret = IRQ_NONE; -	u32 intr_status = 0; +	unsigned long intr_status;  	spin_lock(&mdp->lock); -	/* Get interrpt stat */ +	/* Get interrupt status */  	intr_status = sh_eth_read(ndev, EESR); +	/* Mask it with the interrupt mask, forcing ECI interrupt to be always +	 * enabled since it's the one that  comes thru regardless of the mask, +	 * and we need to fully handle it in sh_eth_error() in order to quench +	 * it as it doesn't get cleared by just writing 1 to the ECI bit... +	 */ +	intr_status &= sh_eth_read(ndev, EESIPR) | DMAC_M_ECI;  	/* Clear interrupt */  	if (intr_status & (EESR_FRC | EESR_RMAF | EESR_RRF |  			EESR_RTLF | EESR_RTSF | EESR_PRE | EESR_CERF | @@ -1373,7 +1377,7 @@ static void sh_eth_adjust_link(struct net_device *ndev)  	struct phy_device *phydev = mdp->phydev;  	int new_state = 0; -	if (phydev->link != PHY_DOWN) { +	if (phydev->link) {  		if (phydev->duplex != mdp->duplex) {  			new_state = 1;  			mdp->duplex = phydev->duplex; @@ -1387,17 +1391,21 @@ static void sh_eth_adjust_link(struct net_device *ndev)  			if (mdp->cd->set_rate)  				mdp->cd->set_rate(ndev);  		} -		if (mdp->link == PHY_DOWN) { +		if (!mdp->link) {  			sh_eth_write(ndev,  				(sh_eth_read(ndev, ECMR) & ~ECMR_TXF), ECMR);  			new_state = 1;  			mdp->link = phydev->link; +			if (mdp->cd->no_psr || mdp->no_ether_link) +				sh_eth_rcv_snd_enable(ndev);  		}  	} else if (mdp->link) {  		new_state = 1; -		mdp->link = PHY_DOWN; +		mdp->link = 0;  		mdp->speed = 0;  		mdp->duplex = -1; +		if (mdp->cd->no_psr || mdp->no_ether_link) +			sh_eth_rcv_snd_disable(ndev);  	}  	if (new_state && netif_msg_link(mdp)) @@ -1414,7 +1422,7 @@ static int sh_eth_phy_init(struct net_device *ndev)  	snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,  		mdp->mii_bus->id , mdp->phy_id); -	mdp->link = PHY_DOWN; +	mdp->link = 0;  	mdp->speed = 0;  	mdp->duplex = -1; @@ -2220,6 +2228,7 @@ static void sh_eth_tsu_init(struct sh_eth_private *mdp)  /* MDIO bus release function */  static int sh_mdio_release(struct net_device *ndev)  { +	struct sh_eth_private *mdp = netdev_priv(ndev);  	struct mii_bus *bus = dev_get_drvdata(&ndev->dev);  	/* unregister mdio bus */ @@ -2234,6 +2243,9 @@ static int sh_mdio_release(struct net_device *ndev)  	/* free bitbang info */  	free_mdio_bitbang(bus); +	/* free bitbang memory */ +	kfree(mdp->bitbang); +  	return 0;  } @@ -2262,6 +2274,7 @@ static int sh_mdio_init(struct net_device *ndev, int id,  	bitbang->ctrl.ops = &bb_ops;  	/* MII controller setting */ +	mdp->bitbang = bitbang;  	mdp->mii_bus = alloc_mdio_bitbang(&bitbang->ctrl);  	if (!mdp->mii_bus) {  		ret = -ENOMEM; @@ -2441,6 +2454,11 @@ static int sh_eth_drv_probe(struct platform_device *pdev)  		}  		mdp->tsu_addr = ioremap(rtsu->start,  					resource_size(rtsu)); +		if (mdp->tsu_addr == NULL) { +			ret = -ENOMEM; +			dev_err(&pdev->dev, "TSU ioremap failed.\n"); +			goto out_release; +		}  		mdp->port = devno % 2;  		ndev->features = NETIF_F_HW_VLAN_FILTER;  	} diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index bae84fd2e73..828be451500 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h @@ -705,6 +705,7 @@ struct sh_eth_private {  	const u16 *reg_offset;  	void __iomem *addr;  	void __iomem *tsu_addr; +	struct bb_info *bitbang;  	u32 num_rx_ring;  	u32 num_tx_ring;  	dma_addr_t rx_desc_dma; @@ -722,7 +723,7 @@ struct sh_eth_private {  	u32 phy_id;					/* PHY ID */  	struct mii_bus *mii_bus;	/* MDIO bus control */  	struct phy_device *phydev;	/* PHY device control */ -	enum phy_state link; +	int link;  	phy_interface_t phy_interface;  	int msg_enable;  	int speed; diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index bf57b3cb16a..0bc00991d31 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -779,6 +779,7 @@ efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries)  						tx_queue->txd.entries);  	} +	efx_device_detach_sync(efx);  	efx_stop_all(efx);  	efx_stop_interrupts(efx, true); @@ -832,6 +833,7 @@ out:  	efx_start_interrupts(efx, true);  	efx_start_all(efx); +	netif_device_attach(efx->net_dev);  	return rc;  rollback: @@ -1641,8 +1643,12 @@ static void efx_stop_all(struct efx_nic *efx)  	/* Flush efx_mac_work(), refill_workqueue, monitor_work */  	efx_flush_all(efx); -	/* Stop the kernel transmit interface late, so the watchdog -	 * timer isn't ticking over the flush */ +	/* Stop the kernel transmit interface.  This is only valid if +	 * the device is stopped or detached; otherwise the watchdog +	 * may fire immediately. +	 */ +	WARN_ON(netif_running(efx->net_dev) && +		netif_device_present(efx->net_dev));  	netif_tx_disable(efx->net_dev);  	efx_stop_datapath(efx); @@ -1963,16 +1969,18 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu)  	if (new_mtu > EFX_MAX_MTU)  		return -EINVAL; -	efx_stop_all(efx); -  	netif_dbg(efx, drv, efx->net_dev, "changing MTU to %d\n", new_mtu); +	efx_device_detach_sync(efx); +	efx_stop_all(efx); +  	mutex_lock(&efx->mac_lock);  	net_dev->mtu = new_mtu;  	efx->type->reconfigure_mac(efx);  	mutex_unlock(&efx->mac_lock);  	efx_start_all(efx); +	netif_device_attach(efx->net_dev);  	return 0;  } diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index 50247dfe8f5..d2f790df6dc 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h @@ -171,9 +171,9 @@ static inline void efx_device_detach_sync(struct efx_nic *efx)  	 * TX scheduler is stopped when we're done and before  	 * netif_device_present() becomes false.  	 */ -	netif_tx_lock(dev); +	netif_tx_lock_bh(dev);  	netif_device_detach(dev); -	netif_tx_unlock(dev); +	netif_tx_unlock_bh(dev);  }  #endif /* EFX_EFX_H */ diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 2d756c1d714..0a90abd2421 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -210,6 +210,7 @@ struct efx_tx_queue {   *	Will be %NULL if the buffer slot is currently free.   * @page: The associated page buffer. Valif iff @flags & %EFX_RX_BUF_PAGE.   *	Will be %NULL if the buffer slot is currently free. + * @page_offset: Offset within page. Valid iff @flags & %EFX_RX_BUF_PAGE.   * @len: Buffer length, in bytes.   * @flags: Flags for buffer and packet state.   */ @@ -219,7 +220,8 @@ struct efx_rx_buffer {  		struct sk_buff *skb;  		struct page *page;  	} u; -	unsigned int len; +	u16 page_offset; +	u16 len;  	u16 flags;  };  #define EFX_RX_BUF_PAGE		0x0001 diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c index 0ad790cc473..eaa8e874a3c 100644 --- a/drivers/net/ethernet/sfc/nic.c +++ b/drivers/net/ethernet/sfc/nic.c @@ -376,7 +376,8 @@ efx_may_push_tx_desc(struct efx_tx_queue *tx_queue, unsigned int write_count)  		return false;  	tx_queue->empty_read_count = 0; -	return ((empty_read_count ^ write_count) & ~EFX_EMPTY_COUNT_VALID) == 0; +	return ((empty_read_count ^ write_count) & ~EFX_EMPTY_COUNT_VALID) == 0 +		&& tx_queue->write_count - write_count == 1;  }  /* For each entry inserted into the software descriptor ring, create a diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index d780a0d096b..bb579a6128c 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c @@ -90,11 +90,7 @@ static unsigned int rx_refill_threshold;  static inline unsigned int efx_rx_buf_offset(struct efx_nic *efx,  					     struct efx_rx_buffer *buf)  { -	/* Offset is always within one page, so we don't need to consider -	 * the page order. -	 */ -	return ((unsigned int) buf->dma_addr & (PAGE_SIZE - 1)) + -		efx->type->rx_buffer_hash_size; +	return buf->page_offset + efx->type->rx_buffer_hash_size;  }  static inline unsigned int efx_rx_buf_size(struct efx_nic *efx)  { @@ -187,6 +183,7 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue)  	struct efx_nic *efx = rx_queue->efx;  	struct efx_rx_buffer *rx_buf;  	struct page *page; +	unsigned int page_offset;  	struct efx_rx_page_state *state;  	dma_addr_t dma_addr;  	unsigned index, count; @@ -211,12 +208,14 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue)  		state->dma_addr = dma_addr;  		dma_addr += sizeof(struct efx_rx_page_state); +		page_offset = sizeof(struct efx_rx_page_state);  	split:  		index = rx_queue->added_count & rx_queue->ptr_mask;  		rx_buf = efx_rx_buffer(rx_queue, index);  		rx_buf->dma_addr = dma_addr + EFX_PAGE_IP_ALIGN;  		rx_buf->u.page = page; +		rx_buf->page_offset = page_offset + EFX_PAGE_IP_ALIGN;  		rx_buf->len = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN;  		rx_buf->flags = EFX_RX_BUF_PAGE;  		++rx_queue->added_count; @@ -227,6 +226,7 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue)  			/* Use the second half of the page */  			get_page(page);  			dma_addr += (PAGE_SIZE >> 1); +			page_offset += (PAGE_SIZE >> 1);  			++count;  			goto split;  		} @@ -236,7 +236,8 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue)  }  static void efx_unmap_rx_buffer(struct efx_nic *efx, -				struct efx_rx_buffer *rx_buf) +				struct efx_rx_buffer *rx_buf, +				unsigned int used_len)  {  	if ((rx_buf->flags & EFX_RX_BUF_PAGE) && rx_buf->u.page) {  		struct efx_rx_page_state *state; @@ -247,6 +248,10 @@ static void efx_unmap_rx_buffer(struct efx_nic *efx,  				       state->dma_addr,  				       efx_rx_buf_size(efx),  				       DMA_FROM_DEVICE); +		} else if (used_len) { +			dma_sync_single_for_cpu(&efx->pci_dev->dev, +						rx_buf->dma_addr, used_len, +						DMA_FROM_DEVICE);  		}  	} else if (!(rx_buf->flags & EFX_RX_BUF_PAGE) && rx_buf->u.skb) {  		dma_unmap_single(&efx->pci_dev->dev, rx_buf->dma_addr, @@ -269,7 +274,7 @@ static void efx_free_rx_buffer(struct efx_nic *efx,  static void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,  			       struct efx_rx_buffer *rx_buf)  { -	efx_unmap_rx_buffer(rx_queue->efx, rx_buf); +	efx_unmap_rx_buffer(rx_queue->efx, rx_buf, 0);  	efx_free_rx_buffer(rx_queue->efx, rx_buf);  } @@ -535,10 +540,10 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,  		goto out;  	} -	/* Release card resources - assumes all RX buffers consumed in-order -	 * per RX queue +	/* Release and/or sync DMA mapping - assumes all RX buffers +	 * consumed in-order per RX queue  	 */ -	efx_unmap_rx_buffer(efx, rx_buf); +	efx_unmap_rx_buffer(efx, rx_buf, len);  	/* Prefetch nice and early so data will (hopefully) be in cache by  	 * the time we look at it. diff --git a/drivers/net/ethernet/smsc/smc91c92_cs.c b/drivers/net/ethernet/smsc/smc91c92_cs.c index 04393b5fef7..656d2e2ebfc 100644 --- a/drivers/net/ethernet/smsc/smc91c92_cs.c +++ b/drivers/net/ethernet/smsc/smc91c92_cs.c @@ -2054,16 +2054,4 @@ static struct pcmcia_driver smc91c92_cs_driver = {  	.suspend	= smc91c92_suspend,  	.resume		= smc91c92_resume,  }; - -static int __init init_smc91c92_cs(void) -{ -	return pcmcia_register_driver(&smc91c92_cs_driver); -} - -static void __exit exit_smc91c92_cs(void) -{ -	pcmcia_unregister_driver(&smc91c92_cs_driver); -} - -module_init(init_smc91c92_cs); -module_exit(exit_smc91c92_cs); +module_pcmcia_driver(smc91c92_cs_driver); diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c index 0c74a702d46..50617c5a0bd 100644 --- a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c @@ -149,6 +149,7 @@ void dwmac_mmc_intr_all_mask(void __iomem *ioaddr)  {  	writel(MMC_DEFAULT_MASK, ioaddr + MMC_RX_INTR_MASK);  	writel(MMC_DEFAULT_MASK, ioaddr + MMC_TX_INTR_MASK); +	writel(MMC_DEFAULT_MASK, ioaddr + MMC_RX_IPC_INTR_MASK);  }  /* This reads the MAC core counters (if actaully supported). diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 7e93df6585e..4781d3d8e18 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -436,7 +436,7 @@ void cpsw_tx_handler(void *token, int len, int status)  	 * queue is stopped then start the queue as we have free desc for tx  	 */  	if (unlikely(netif_queue_stopped(ndev))) -		netif_start_queue(ndev); +		netif_wake_queue(ndev);  	cpts_tx_timestamp(priv->cpts, skb);  	priv->stats.tx_packets++;  	priv->stats.tx_bytes += len; @@ -731,7 +731,7 @@ static inline void cpsw_add_default_vlan(struct cpsw_priv *priv)  	writel(vlan, &priv->host_port_regs->port_vlan); -	for (i = 0; i < 2; i++) +	for (i = 0; i < priv->data.slaves; i++)  		slave_write(priv->slaves + i, vlan, reg);  	cpsw_ale_add_vlan(priv->ale, vlan, ALE_ALL_PORTS << port, @@ -905,7 +905,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,  	/* If there is no more tx desc left free then we need to  	 * tell the kernel to stop sending us tx frames.  	 */ -	if (unlikely(cpdma_check_free_tx_desc(priv->txch))) +	if (unlikely(!cpdma_check_free_tx_desc(priv->txch)))  		netif_stop_queue(ndev);  	return NETDEV_TX_OK; @@ -1364,7 +1364,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,  		struct platform_device *mdio;  		parp = of_get_property(slave_node, "phy_id", &lenp); -		if ((parp == NULL) && (lenp != (sizeof(void *) * 2))) { +		if ((parp == NULL) || (lenp != (sizeof(void *) * 2))) {  			pr_err("Missing slave[%d] phy_id property\n", i);  			ret = -EINVAL;  			goto error_ret; @@ -1380,7 +1380,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,  			memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN);  		if (data->dual_emac) { -			if (of_property_read_u32(node, "dual_emac_res_vlan", +			if (of_property_read_u32(slave_node, "dual_emac_res_vlan",  						 &prop)) {  				pr_err("Missing dual_emac_res_vlan in DT.\n");  				slave_data->dual_emac_res_vlan = i+1; diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index 52c05366599..72300bc9e37 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -1053,7 +1053,7 @@ static void emac_tx_handler(void *token, int len, int status)  	 * queue is stopped then start the queue as we have free desc for tx  	 */  	if (unlikely(netif_queue_stopped(ndev))) -		netif_start_queue(ndev); +		netif_wake_queue(ndev);  	ndev->stats.tx_packets++;  	ndev->stats.tx_bytes += len;  	dev_kfree_skb_any(skb); @@ -1102,7 +1102,7 @@ static int emac_dev_xmit(struct sk_buff *skb, struct net_device *ndev)  	/* If there is no more tx desc left free then we need to  	 * tell the kernel to stop sending us tx frames.  	 */ -	if (unlikely(cpdma_check_free_tx_desc(priv->txchan))) +	if (unlikely(!cpdma_check_free_tx_desc(priv->txchan)))  		netif_stop_queue(ndev);  	return NETDEV_TX_OK; diff --git a/drivers/net/ethernet/xircom/xirc2ps_cs.c b/drivers/net/ethernet/xircom/xirc2ps_cs.c index 98e09d0d3ce..1025b4e937d 100644 --- a/drivers/net/ethernet/xircom/xirc2ps_cs.c +++ b/drivers/net/ethernet/xircom/xirc2ps_cs.c @@ -1775,21 +1775,7 @@ static struct pcmcia_driver xirc2ps_cs_driver = {  	.suspend	= xirc2ps_suspend,  	.resume		= xirc2ps_resume,  }; - -static int __init -init_xirc2ps_cs(void) -{ -	return pcmcia_register_driver(&xirc2ps_cs_driver); -} - -static void __exit -exit_xirc2ps_cs(void) -{ -	pcmcia_unregister_driver(&xirc2ps_cs_driver); -} - -module_init(init_xirc2ps_cs); -module_exit(exit_xirc2ps_cs); +module_pcmcia_driver(xirc2ps_cs_driver);  #ifndef MODULE  static int __init setup_xirc2ps_cs(char *str) diff --git a/drivers/net/hippi/rrunner.c b/drivers/net/hippi/rrunner.c index e5b19b05690..3c4d6274bb9 100644 --- a/drivers/net/hippi/rrunner.c +++ b/drivers/net/hippi/rrunner.c @@ -202,6 +202,9 @@ static int rr_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  	return 0;   out: +	if (rrpriv->evt_ring) +		pci_free_consistent(pdev, EVT_RING_SIZE, rrpriv->evt_ring, +				    rrpriv->evt_ring_dma);  	if (rrpriv->rx_ring)  		pci_free_consistent(pdev, RX_TOTAL_SIZE, rrpriv->rx_ring,  				    rrpriv->rx_ring_dma); diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 1cd77483da5..f5f0f09e4cc 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -470,8 +470,10 @@ static void netvsc_send_completion(struct hv_device *device,  			packet->trans_id;  		/* Notify the layer above us */ -		nvsc_packet->completion.send.send_completion( -			nvsc_packet->completion.send.send_completion_ctx); +		if (nvsc_packet) +			nvsc_packet->completion.send.send_completion( +				nvsc_packet->completion.send. +				send_completion_ctx);  		num_outstanding_sends =  			atomic_dec_return(&net_device->num_outstanding_sends); @@ -498,6 +500,7 @@ int netvsc_send(struct hv_device *device,  	int ret = 0;  	struct nvsp_message sendMessage;  	struct net_device *ndev; +	u64 req_id;  	net_device = get_outbound_net_device(device);  	if (!net_device) @@ -518,20 +521,24 @@ int netvsc_send(struct hv_device *device,  		0xFFFFFFFF;  	sendMessage.msg.v1_msg.send_rndis_pkt.send_buf_section_size = 0; +	if (packet->completion.send.send_completion) +		req_id = (u64)packet; +	else +		req_id = 0; +  	if (packet->page_buf_cnt) {  		ret = vmbus_sendpacket_pagebuffer(device->channel,  						  packet->page_buf,  						  packet->page_buf_cnt,  						  &sendMessage,  						  sizeof(struct nvsp_message), -						  (unsigned long)packet); +						  req_id);  	} else {  		ret = vmbus_sendpacket(device->channel, &sendMessage,  				sizeof(struct nvsp_message), -				(unsigned long)packet, +				req_id,  				VM_PKT_DATA_INBAND,  				VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); -  	}  	if (ret == 0) { diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 5f85205cd12..8341b62e552 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -241,13 +241,11 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj,  	if (status == 1) {  		netif_carrier_on(net); -		netif_wake_queue(net);  		ndev_ctx = netdev_priv(net);  		schedule_delayed_work(&ndev_ctx->dwork, 0);  		schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20));  	} else {  		netif_carrier_off(net); -		netif_tx_disable(net);  	}  } diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 2b657d4d63a..0775f0aefd1 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -61,9 +61,6 @@ struct rndis_request {  static void rndis_filter_send_completion(void *ctx); -static void rndis_filter_send_request_completion(void *ctx); - -  static struct rndis_device *get_rndis_device(void)  { @@ -241,10 +238,7 @@ static int rndis_filter_send_request(struct rndis_device *dev,  			packet->page_buf[0].len;  	} -	packet->completion.send.send_completion_ctx = req;/* packet; */ -	packet->completion.send.send_completion = -		rndis_filter_send_request_completion; -	packet->completion.send.send_completion_tid = (unsigned long)dev; +	packet->completion.send.send_completion = NULL;  	ret = netvsc_send(dev->net_dev->dev, packet);  	return ret; @@ -999,9 +993,3 @@ static void rndis_filter_send_completion(void *ctx)  	/* Pass it back to the original handler */  	filter_pkt->completion(filter_pkt->completion_ctx);  } - - -static void rndis_filter_send_request_completion(void *ctx) -{ -	/* Noop */ -} diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 417b2af1aa8..73abbc1655d 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -660,6 +660,7 @@ void macvlan_common_setup(struct net_device *dev)  	ether_setup(dev);  	dev->priv_flags	       &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING); +	dev->priv_flags	       |= IFF_UNICAST_FLT;  	dev->netdev_ops		= &macvlan_netdev_ops;  	dev->destructor		= free_netdev;  	dev->header_ops		= &macvlan_hard_header_ops, diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 37add21a3d7..59ac143dec2 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -666,6 +666,7 @@ static int netconsole_netdev_event(struct notifier_block *this,  		goto done;  	spin_lock_irqsave(&target_list_lock, flags); +restart:  	list_for_each_entry(nt, &target_list, list) {  		netconsole_target_get(nt);  		if (nt->np.dev == dev) { @@ -678,15 +679,17 @@ static int netconsole_netdev_event(struct notifier_block *this,  			case NETDEV_UNREGISTER:  				/*  				 * rtnl_lock already held +				 * we might sleep in __netpoll_cleanup()  				 */ -				if (nt->np.dev) { -					__netpoll_cleanup(&nt->np); -					dev_put(nt->np.dev); -					nt->np.dev = NULL; -				} +				spin_unlock_irqrestore(&target_list_lock, flags); +				__netpoll_cleanup(&nt->np); +				spin_lock_irqsave(&target_list_lock, flags); +				dev_put(nt->np.dev); +				nt->np.dev = NULL;  				nt->enabled = 0;  				stopped = true; -				break; +				netconsole_target_put(nt); +				goto restart;  			}  		}  		netconsole_target_put(nt); diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 29934446436..abf7b6153d0 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -257,8 +257,7 @@ static struct phy_driver ksphy_driver[] = {  	.phy_id		= PHY_ID_KSZ9021,  	.phy_id_mask	= 0x000ffffe,  	.name		= "Micrel KSZ9021 Gigabit PHY", -	.features	= (PHY_GBIT_FEATURES | SUPPORTED_Pause -				| SUPPORTED_Asym_Pause), +	.features	= (PHY_GBIT_FEATURES | SUPPORTED_Pause),  	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,  	.config_init	= kszphy_config_init,  	.config_aneg	= genphy_config_aneg, diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 9930f999956..3657b4a2912 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -44,13 +44,13 @@ MODULE_LICENSE("GPL");  void phy_device_free(struct phy_device *phydev)  { -	kfree(phydev); +	put_device(&phydev->dev);  }  EXPORT_SYMBOL(phy_device_free);  static void phy_device_release(struct device *dev)  { -	phy_device_free(to_phy_device(dev)); +	kfree(to_phy_device(dev));  }  static struct phy_driver genphy_driver; @@ -201,6 +201,8 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id,  	   there's no driver _already_ loaded. */  	request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, MDIO_ID_ARGS(phy_id)); +	device_initialize(&dev->dev); +  	return dev;  }  EXPORT_SYMBOL(phy_device_create); @@ -363,9 +365,9 @@ int phy_device_register(struct phy_device *phydev)  	/* Run all of the fixups for this PHY */  	phy_scan_fixups(phydev); -	err = device_register(&phydev->dev); +	err = device_add(&phydev->dev);  	if (err) { -		pr_err("phy %d failed to register\n", phydev->addr); +		pr_err("PHY %d failed to add\n", phydev->addr);  		goto out;  	} diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c index a031f6b456b..9c889e0303d 100644 --- a/drivers/net/ppp/ppp_async.c +++ b/drivers/net/ppp/ppp_async.c @@ -314,7 +314,7 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,  		/* flush our buffers and the serial port's buffer */  		if (arg == TCIOFLUSH || arg == TCOFLUSH)  			ppp_async_flush_output(ap); -		err = tty_perform_flush(tty, arg); +		err = n_tty_ioctl_helper(tty, file, cmd, arg);  		break;  	case FIONREAD: diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c index 1a12033d2ef..bdf3b13a71a 100644 --- a/drivers/net/ppp/ppp_synctty.c +++ b/drivers/net/ppp/ppp_synctty.c @@ -355,7 +355,7 @@ ppp_synctty_ioctl(struct tty_struct *tty, struct file *file,  		/* flush our buffers and the serial port's buffer */  		if (arg == TCIOFLUSH || arg == TCOFLUSH)  			ppp_sync_flush_output(ap); -		err = tty_perform_flush(tty, arg); +		err = n_tty_ioctl_helper(tty, file, cmd, arg);  		break;  	case FIONREAD: diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 05c5efe8459..bf341929787 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1138,6 +1138,8 @@ static int team_port_del(struct team *team, struct net_device *port_dev)  	netdev_upper_dev_unlink(port_dev, dev);  	team_port_disable_netpoll(port);  	vlan_vids_del_by_dev(port_dev, dev); +	dev_uc_unsync(port_dev, dev); +	dev_mc_unsync(port_dev, dev);  	dev_close(port_dev);  	team_port_leave(team, port); diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 2c6a22e278e..729ed533bb3 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -747,6 +747,8 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)  		goto drop;  	skb_orphan(skb); +	nf_reset(skb); +  	/* Enqueue packet */  	skb_queue_tail(&tfile->socket.sk->sk_receive_queue, skb); @@ -1592,7 +1594,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)  		if (tun->flags & TUN_TAP_MQ &&  		    (tun->numqueues + tun->numdisabled > 1)) -			return err; +			return -EBUSY;  	}  	else {  		char *name; diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index da92ed3797a..7c769d8e25a 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -156,6 +156,24 @@ config USB_NET_AX8817X  	  This driver creates an interface named "ethX", where X depends on  	  what other networking devices you have in use. +config USB_NET_AX88179_178A +	tristate "ASIX AX88179/178A USB 3.0/2.0 to Gigabit Ethernet" +	depends on USB_USBNET +	select CRC32 +	select PHYLIB +	default y +	help +	  This option adds support for ASIX AX88179 based USB 3.0/2.0 +	  to Gigabit Ethernet adapters. + +	  This driver should work with at least the following devices: +	    * ASIX AX88179 +	    * ASIX AX88178A +	    * Sitcomm LN-032 + +	  This driver creates an interface named "ethX", where X depends on +	  what other networking devices you have in use. +  config USB_NET_CDCETHER  	tristate "CDC Ethernet support (smart devices such as cable modems)"  	depends on USB_USBNET @@ -250,7 +268,7 @@ config USB_NET_SMSC75XX  	select CRC16  	select CRC32  	help -	  This option adds support for SMSC LAN95XX based USB 2.0 +	  This option adds support for SMSC LAN75XX based USB 2.0  	  Gigabit Ethernet adapters.  config USB_NET_SMSC95XX diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile index 478691326f3..119b06c9aa1 100644 --- a/drivers/net/usb/Makefile +++ b/drivers/net/usb/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_USB_RTL8150)	+= rtl8150.o  obj-$(CONFIG_USB_HSO)		+= hso.o  obj-$(CONFIG_USB_NET_AX8817X)	+= asix.o  asix-y := asix_devices.o asix_common.o ax88172a.o +obj-$(CONFIG_USB_NET_AX88179_178A)      += ax88179_178a.o  obj-$(CONFIG_USB_NET_CDCETHER)	+= cdc_ether.o  obj-$(CONFIG_USB_NET_CDC_EEM)	+= cdc_eem.o  obj-$(CONFIG_USB_NET_DM9601)	+= dm9601.o diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 2205dbc8d32..70975346909 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c @@ -924,6 +924,29 @@ static const struct driver_info ax88178_info = {  	.tx_fixup = asix_tx_fixup,  }; +/* + * USBLINK 20F9 "USB 2.0 LAN" USB ethernet adapter, typically found in + * no-name packaging. + * USB device strings are: + *   1: Manufacturer: USBLINK + *   2: Product: HG20F9 USB2.0 + *   3: Serial: 000003 + * Appears to be compatible with Asix 88772B. + */ +static const struct driver_info hg20f9_info = { +	.description = "HG20F9 USB 2.0 Ethernet", +	.bind = ax88772_bind, +	.unbind = ax88772_unbind, +	.status = asix_status, +	.link_reset = ax88772_link_reset, +	.reset = ax88772_reset, +	.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | +	         FLAG_MULTI_PACKET, +	.rx_fixup = asix_rx_fixup_common, +	.tx_fixup = asix_tx_fixup, +	.data = FLAG_EEPROM_MAC, +}; +  extern const struct driver_info ax88172a_info;  static const struct usb_device_id	products [] = { @@ -1063,6 +1086,14 @@ static const struct usb_device_id	products [] = {  	/* ASIX 88172a demo board */  	USB_DEVICE(0x0b95, 0x172a),  	.driver_info = (unsigned long) &ax88172a_info, +}, { +	/* +	 * USBLINK HG20F9 "USB 2.0 LAN" +	 * Appears to have gazumped Linksys's manufacturer ID but +	 * doesn't (yet) conflict with any known Linksys product. +	 */ +	USB_DEVICE(0x066b, 0x20f9), +	.driver_info = (unsigned long) &hg20f9_info,  },  	{ },		// END  }; diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c new file mode 100644 index 00000000000..71c27d8d214 --- /dev/null +++ b/drivers/net/usb/ax88179_178a.c @@ -0,0 +1,1448 @@ +/* + * ASIX AX88179/178A USB 3.0/2.0 to Gigabit Ethernet Devices + * + * Copyright (C) 2011-2013 ASIX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. + */ + +#include <linux/module.h> +#include <linux/etherdevice.h> +#include <linux/mii.h> +#include <linux/usb.h> +#include <linux/crc32.h> +#include <linux/usb/usbnet.h> + +#define AX88179_PHY_ID				0x03 +#define AX_EEPROM_LEN				0x100 +#define AX88179_EEPROM_MAGIC			0x17900b95 +#define AX_MCAST_FLTSIZE			8 +#define AX_MAX_MCAST				64 +#define AX_INT_PPLS_LINK			((u32)BIT(16)) +#define AX_RXHDR_L4_TYPE_MASK			0x1c +#define AX_RXHDR_L4_TYPE_UDP			4 +#define AX_RXHDR_L4_TYPE_TCP			16 +#define AX_RXHDR_L3CSUM_ERR			2 +#define AX_RXHDR_L4CSUM_ERR			1 +#define AX_RXHDR_CRC_ERR			((u32)BIT(31)) +#define AX_RXHDR_DROP_ERR			((u32)BIT(30)) +#define AX_ACCESS_MAC				0x01 +#define AX_ACCESS_PHY				0x02 +#define AX_ACCESS_EEPROM			0x04 +#define AX_ACCESS_EFUS				0x05 +#define AX_PAUSE_WATERLVL_HIGH			0x54 +#define AX_PAUSE_WATERLVL_LOW			0x55 + +#define PHYSICAL_LINK_STATUS			0x02 +	#define	AX_USB_SS		0x04 +	#define	AX_USB_HS		0x02 + +#define GENERAL_STATUS				0x03 +/* Check AX88179 version. UA1:Bit2 = 0,  UA2:Bit2 = 1 */ +	#define	AX_SECLD		0x04 + +#define AX_SROM_ADDR				0x07 +#define AX_SROM_CMD				0x0a +	#define EEP_RD			0x04 +	#define EEP_BUSY		0x10 + +#define AX_SROM_DATA_LOW			0x08 +#define AX_SROM_DATA_HIGH			0x09 + +#define AX_RX_CTL				0x0b +	#define AX_RX_CTL_DROPCRCERR	0x0100 +	#define AX_RX_CTL_IPE		0x0200 +	#define AX_RX_CTL_START		0x0080 +	#define AX_RX_CTL_AP		0x0020 +	#define AX_RX_CTL_AM		0x0010 +	#define AX_RX_CTL_AB		0x0008 +	#define AX_RX_CTL_AMALL		0x0002 +	#define AX_RX_CTL_PRO		0x0001 +	#define AX_RX_CTL_STOP		0x0000 + +#define AX_NODE_ID				0x10 +#define AX_MULFLTARY				0x16 + +#define AX_MEDIUM_STATUS_MODE			0x22 +	#define AX_MEDIUM_GIGAMODE	0x01 +	#define AX_MEDIUM_FULL_DUPLEX	0x02 +	#define AX_MEDIUM_ALWAYS_ONE	0x04 +	#define AX_MEDIUM_EN_125MHZ	0x08 +	#define AX_MEDIUM_RXFLOW_CTRLEN	0x10 +	#define AX_MEDIUM_TXFLOW_CTRLEN	0x20 +	#define AX_MEDIUM_RECEIVE_EN	0x100 +	#define AX_MEDIUM_PS		0x200 +	#define AX_MEDIUM_JUMBO_EN	0x8040 + +#define AX_MONITOR_MOD				0x24 +	#define AX_MONITOR_MODE_RWLC	0x02 +	#define AX_MONITOR_MODE_RWMP	0x04 +	#define AX_MONITOR_MODE_PMEPOL	0x20 +	#define AX_MONITOR_MODE_PMETYPE	0x40 + +#define AX_GPIO_CTRL				0x25 +	#define AX_GPIO_CTRL_GPIO3EN	0x80 +	#define AX_GPIO_CTRL_GPIO2EN	0x40 +	#define AX_GPIO_CTRL_GPIO1EN	0x20 + +#define AX_PHYPWR_RSTCTL			0x26 +	#define AX_PHYPWR_RSTCTL_BZ	0x0010 +	#define AX_PHYPWR_RSTCTL_IPRL	0x0020 +	#define AX_PHYPWR_RSTCTL_AT	0x1000 + +#define AX_RX_BULKIN_QCTRL			0x2e +#define AX_CLK_SELECT				0x33 +	#define AX_CLK_SELECT_BCS	0x01 +	#define AX_CLK_SELECT_ACS	0x02 +	#define AX_CLK_SELECT_ULR	0x08 + +#define AX_RXCOE_CTL				0x34 +	#define AX_RXCOE_IP		0x01 +	#define AX_RXCOE_TCP		0x02 +	#define AX_RXCOE_UDP		0x04 +	#define AX_RXCOE_TCPV6		0x20 +	#define AX_RXCOE_UDPV6		0x40 + +#define AX_TXCOE_CTL				0x35 +	#define AX_TXCOE_IP		0x01 +	#define AX_TXCOE_TCP		0x02 +	#define AX_TXCOE_UDP		0x04 +	#define AX_TXCOE_TCPV6		0x20 +	#define AX_TXCOE_UDPV6		0x40 + +#define AX_LEDCTRL				0x73 + +#define GMII_PHY_PHYSR				0x11 +	#define GMII_PHY_PHYSR_SMASK	0xc000 +	#define GMII_PHY_PHYSR_GIGA	0x8000 +	#define GMII_PHY_PHYSR_100	0x4000 +	#define GMII_PHY_PHYSR_FULL	0x2000 +	#define GMII_PHY_PHYSR_LINK	0x400 + +#define GMII_LED_ACT				0x1a +	#define	GMII_LED_ACTIVE_MASK	0xff8f +	#define	GMII_LED0_ACTIVE	BIT(4) +	#define	GMII_LED1_ACTIVE	BIT(5) +	#define	GMII_LED2_ACTIVE	BIT(6) + +#define GMII_LED_LINK				0x1c +	#define	GMII_LED_LINK_MASK	0xf888 +	#define	GMII_LED0_LINK_10	BIT(0) +	#define	GMII_LED0_LINK_100	BIT(1) +	#define	GMII_LED0_LINK_1000	BIT(2) +	#define	GMII_LED1_LINK_10	BIT(4) +	#define	GMII_LED1_LINK_100	BIT(5) +	#define	GMII_LED1_LINK_1000	BIT(6) +	#define	GMII_LED2_LINK_10	BIT(8) +	#define	GMII_LED2_LINK_100	BIT(9) +	#define	GMII_LED2_LINK_1000	BIT(10) +	#define	LED0_ACTIVE		BIT(0) +	#define	LED0_LINK_10		BIT(1) +	#define	LED0_LINK_100		BIT(2) +	#define	LED0_LINK_1000		BIT(3) +	#define	LED0_FD			BIT(4) +	#define	LED0_USB3_MASK		0x001f +	#define	LED1_ACTIVE		BIT(5) +	#define	LED1_LINK_10		BIT(6) +	#define	LED1_LINK_100		BIT(7) +	#define	LED1_LINK_1000		BIT(8) +	#define	LED1_FD			BIT(9) +	#define	LED1_USB3_MASK		0x03e0 +	#define	LED2_ACTIVE		BIT(10) +	#define	LED2_LINK_1000		BIT(13) +	#define	LED2_LINK_100		BIT(12) +	#define	LED2_LINK_10		BIT(11) +	#define	LED2_FD			BIT(14) +	#define	LED_VALID		BIT(15) +	#define	LED2_USB3_MASK		0x7c00 + +#define GMII_PHYPAGE				0x1e +#define GMII_PHY_PAGE_SELECT			0x1f +	#define GMII_PHY_PGSEL_EXT	0x0007 +	#define GMII_PHY_PGSEL_PAGE0	0x0000 + +struct ax88179_data { +	u16 rxctl; +	u16 reserved; +}; + +struct ax88179_int_data { +	__le32 intdata1; +	__le32 intdata2; +}; + +static const struct { +	unsigned char ctrl, timer_l, timer_h, size, ifg; +} AX88179_BULKIN_SIZE[] =	{ +	{7, 0x4f, 0,	0x12, 0xff}, +	{7, 0x20, 3,	0x16, 0xff}, +	{7, 0xae, 7,	0x18, 0xff}, +	{7, 0xcc, 0x4c, 0x18, 8}, +}; + +static int __ax88179_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, +			      u16 size, void *data, int in_pm) +{ +	int ret; +	int (*fn)(struct usbnet *, u8, u8, u16, u16, void *, u16); + +	BUG_ON(!dev); + +	if (!in_pm) +		fn = usbnet_read_cmd; +	else +		fn = usbnet_read_cmd_nopm; + +	ret = fn(dev, cmd, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, +		 value, index, data, size); + +	if (unlikely(ret < 0)) +		netdev_warn(dev->net, "Failed to read reg index 0x%04x: %d\n", +			    index, ret); + +	return ret; +} + +static int __ax88179_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, +			       u16 size, void *data, int in_pm) +{ +	int ret; +	int (*fn)(struct usbnet *, u8, u8, u16, u16, const void *, u16); + +	BUG_ON(!dev); + +	if (!in_pm) +		fn = usbnet_write_cmd; +	else +		fn = usbnet_write_cmd_nopm; + +	ret = fn(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, +		 value, index, data, size); + +	if (unlikely(ret < 0)) +		netdev_warn(dev->net, "Failed to write reg index 0x%04x: %d\n", +			    index, ret); + +	return ret; +} + +static void ax88179_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, +				    u16 index, u16 size, void *data) +{ +	u16 buf; + +	if (2 == size) { +		buf = *((u16 *)data); +		cpu_to_le16s(&buf); +		usbnet_write_cmd_async(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | +				       USB_RECIP_DEVICE, value, index, &buf, +				       size); +	} else { +		usbnet_write_cmd_async(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | +				       USB_RECIP_DEVICE, value, index, data, +				       size); +	} +} + +static int ax88179_read_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, +				 u16 index, u16 size, void *data) +{ +	int ret; + +	if (2 == size) { +		u16 buf; +		ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 1); +		le16_to_cpus(&buf); +		*((u16 *)data) = buf; +	} else if (4 == size) { +		u32 buf; +		ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 1); +		le32_to_cpus(&buf); +		*((u32 *)data) = buf; +	} else { +		ret = __ax88179_read_cmd(dev, cmd, value, index, size, data, 1); +	} + +	return ret; +} + +static int ax88179_write_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, +				  u16 index, u16 size, void *data) +{ +	int ret; + +	if (2 == size) { +		u16 buf; +		buf = *((u16 *)data); +		cpu_to_le16s(&buf); +		ret = __ax88179_write_cmd(dev, cmd, value, index, +					  size, &buf, 1); +	} else { +		ret = __ax88179_write_cmd(dev, cmd, value, index, +					  size, data, 1); +	} + +	return ret; +} + +static int ax88179_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, +			    u16 size, void *data) +{ +	int ret; + +	if (2 == size) { +		u16 buf; +		ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 0); +		le16_to_cpus(&buf); +		*((u16 *)data) = buf; +	} else if (4 == size) { +		u32 buf; +		ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 0); +		le32_to_cpus(&buf); +		*((u32 *)data) = buf; +	} else { +		ret = __ax88179_read_cmd(dev, cmd, value, index, size, data, 0); +	} + +	return ret; +} + +static int ax88179_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, +			     u16 size, void *data) +{ +	int ret; + +	if (2 == size) { +		u16 buf; +		buf = *((u16 *)data); +		cpu_to_le16s(&buf); +		ret = __ax88179_write_cmd(dev, cmd, value, index, +					  size, &buf, 0); +	} else { +		ret = __ax88179_write_cmd(dev, cmd, value, index, +					  size, data, 0); +	} + +	return ret; +} + +static void ax88179_status(struct usbnet *dev, struct urb *urb) +{ +	struct ax88179_int_data *event; +	u32 link; + +	if (urb->actual_length < 8) +		return; + +	event = urb->transfer_buffer; +	le32_to_cpus((void *)&event->intdata1); + +	link = (((__force u32)event->intdata1) & AX_INT_PPLS_LINK) >> 16; + +	if (netif_carrier_ok(dev->net) != link) { +		if (link) +			usbnet_defer_kevent(dev, EVENT_LINK_RESET); +		else +			netif_carrier_off(dev->net); + +		netdev_info(dev->net, "ax88179 - Link status is: %d\n", link); +	} +} + +static int ax88179_mdio_read(struct net_device *netdev, int phy_id, int loc) +{ +	struct usbnet *dev = netdev_priv(netdev); +	u16 res; + +	ax88179_read_cmd(dev, AX_ACCESS_PHY, phy_id, (__u16)loc, 2, &res); +	return res; +} + +static void ax88179_mdio_write(struct net_device *netdev, int phy_id, int loc, +			       int val) +{ +	struct usbnet *dev = netdev_priv(netdev); +	u16 res = (u16) val; + +	ax88179_write_cmd(dev, AX_ACCESS_PHY, phy_id, (__u16)loc, 2, &res); +} + +static int ax88179_suspend(struct usb_interface *intf, pm_message_t message) +{ +	struct usbnet *dev = usb_get_intfdata(intf); +	u16 tmp16; +	u8 tmp8; + +	usbnet_suspend(intf, message); + +	/* Disable RX path */ +	ax88179_read_cmd_nopm(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, +			      2, 2, &tmp16); +	tmp16 &= ~AX_MEDIUM_RECEIVE_EN; +	ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, +			       2, 2, &tmp16); + +	/* Force bulk-in zero length */ +	ax88179_read_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, +			      2, 2, &tmp16); + +	tmp16 |= AX_PHYPWR_RSTCTL_BZ | AX_PHYPWR_RSTCTL_IPRL; +	ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, +			       2, 2, &tmp16); + +	/* change clock */ +	tmp8 = 0; +	ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8); + +	/* Configure RX control register => stop operation */ +	tmp16 = AX_RX_CTL_STOP; +	ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &tmp16); + +	return 0; +} + +/* This function is used to enable the autodetach function. */ +/* This function is determined by offset 0x43 of EEPROM */ +static int ax88179_auto_detach(struct usbnet *dev, int in_pm) +{ +	u16 tmp16; +	u8 tmp8; +	int (*fnr)(struct usbnet *, u8, u16, u16, u16, void *); +	int (*fnw)(struct usbnet *, u8, u16, u16, u16, void *); + +	if (!in_pm) { +		fnr = ax88179_read_cmd; +		fnw = ax88179_write_cmd; +	} else { +		fnr = ax88179_read_cmd_nopm; +		fnw = ax88179_write_cmd_nopm; +	} + +	if (fnr(dev, AX_ACCESS_EEPROM, 0x43, 1, 2, &tmp16) < 0) +		return 0; + +	if ((tmp16 == 0xFFFF) || (!(tmp16 & 0x0100))) +		return 0; + +	/* Enable Auto Detach bit */ +	tmp8 = 0; +	fnr(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8); +	tmp8 |= AX_CLK_SELECT_ULR; +	fnw(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8); + +	fnr(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, &tmp16); +	tmp16 |= AX_PHYPWR_RSTCTL_AT; +	fnw(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, &tmp16); + +	return 0; +} + +static int ax88179_resume(struct usb_interface *intf) +{ +	struct usbnet *dev = usb_get_intfdata(intf); +	u16 tmp16; +	u8 tmp8; + +	netif_carrier_off(dev->net); + +	/* Power up ethernet PHY */ +	tmp16 = 0; +	ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, +			       2, 2, &tmp16); +	udelay(1000); + +	tmp16 = AX_PHYPWR_RSTCTL_IPRL; +	ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, +			       2, 2, &tmp16); +	msleep(200); + +	/* Ethernet PHY Auto Detach*/ +	ax88179_auto_detach(dev, 1); + +	/* Enable clock */ +	ax88179_read_cmd_nopm(dev, AX_ACCESS_MAC,  AX_CLK_SELECT, 1, 1, &tmp8); +	tmp8 |= AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS; +	ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8); +	msleep(100); + +	/* Configure RX control register => start operation */ +	tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_IPE | AX_RX_CTL_START | +		AX_RX_CTL_AP | AX_RX_CTL_AMALL | AX_RX_CTL_AB; +	ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &tmp16); + +	return usbnet_resume(intf); +} + +static void +ax88179_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) +{ +	struct usbnet *dev = netdev_priv(net); +	u8 opt; + +	if (ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MOD, +			     1, 1, &opt) < 0) { +		wolinfo->supported = 0; +		wolinfo->wolopts = 0; +		return; +	} + +	wolinfo->supported = WAKE_PHY | WAKE_MAGIC; +	wolinfo->wolopts = 0; +	if (opt & AX_MONITOR_MODE_RWLC) +		wolinfo->wolopts |= WAKE_PHY; +	if (opt & AX_MONITOR_MODE_RWMP) +		wolinfo->wolopts |= WAKE_MAGIC; +} + +static int +ax88179_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) +{ +	struct usbnet *dev = netdev_priv(net); +	u8 opt = 0; + +	if (wolinfo->wolopts & WAKE_PHY) +		opt |= AX_MONITOR_MODE_RWLC; +	if (wolinfo->wolopts & WAKE_MAGIC) +		opt |= AX_MONITOR_MODE_RWMP; + +	if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MOD, +			      1, 1, &opt) < 0) +		return -EINVAL; + +	return 0; +} + +static int ax88179_get_eeprom_len(struct net_device *net) +{ +	return AX_EEPROM_LEN; +} + +static int +ax88179_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, +		   u8 *data) +{ +	struct usbnet *dev = netdev_priv(net); +	u16 *eeprom_buff; +	int first_word, last_word; +	int i, ret; + +	if (eeprom->len == 0) +		return -EINVAL; + +	eeprom->magic = AX88179_EEPROM_MAGIC; + +	first_word = eeprom->offset >> 1; +	last_word = (eeprom->offset + eeprom->len - 1) >> 1; +	eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1), +			      GFP_KERNEL); +	if (!eeprom_buff) +		return -ENOMEM; + +	/* ax88179/178A returns 2 bytes from eeprom on read */ +	for (i = first_word; i <= last_word; i++) { +		ret = __ax88179_read_cmd(dev, AX_ACCESS_EEPROM, i, 1, 2, +					 &eeprom_buff[i - first_word], +					 0); +		if (ret < 0) { +			kfree(eeprom_buff); +			return -EIO; +		} +	} + +	memcpy(data, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len); +	kfree(eeprom_buff); +	return 0; +} + +static int ax88179_get_settings(struct net_device *net, struct ethtool_cmd *cmd) +{ +	struct usbnet *dev = netdev_priv(net); +	return mii_ethtool_gset(&dev->mii, cmd); +} + +static int ax88179_set_settings(struct net_device *net, struct ethtool_cmd *cmd) +{ +	struct usbnet *dev = netdev_priv(net); +	return mii_ethtool_sset(&dev->mii, cmd); +} + + +static int ax88179_ioctl(struct net_device *net, struct ifreq *rq, int cmd) +{ +	struct usbnet *dev = netdev_priv(net); +	return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); +} + +static const struct ethtool_ops ax88179_ethtool_ops = { +	.get_link		= ethtool_op_get_link, +	.get_msglevel		= usbnet_get_msglevel, +	.set_msglevel		= usbnet_set_msglevel, +	.get_wol		= ax88179_get_wol, +	.set_wol		= ax88179_set_wol, +	.get_eeprom_len		= ax88179_get_eeprom_len, +	.get_eeprom		= ax88179_get_eeprom, +	.get_settings		= ax88179_get_settings, +	.set_settings		= ax88179_set_settings, +	.nway_reset		= usbnet_nway_reset, +}; + +static void ax88179_set_multicast(struct net_device *net) +{ +	struct usbnet *dev = netdev_priv(net); +	struct ax88179_data *data = (struct ax88179_data *)dev->data; +	u8 *m_filter = ((u8 *)dev->data) + 12; + +	data->rxctl = (AX_RX_CTL_START | AX_RX_CTL_AB | AX_RX_CTL_IPE); + +	if (net->flags & IFF_PROMISC) { +		data->rxctl |= AX_RX_CTL_PRO; +	} else if (net->flags & IFF_ALLMULTI || +		   netdev_mc_count(net) > AX_MAX_MCAST) { +		data->rxctl |= AX_RX_CTL_AMALL; +	} else if (netdev_mc_empty(net)) { +		/* just broadcast and directed */ +	} else { +		/* We use the 20 byte dev->data for our 8 byte filter buffer +		 * to avoid allocating memory that is tricky to free later +		 */ +		u32 crc_bits; +		struct netdev_hw_addr *ha; + +		memset(m_filter, 0, AX_MCAST_FLTSIZE); + +		netdev_for_each_mc_addr(ha, net) { +			crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; +			*(m_filter + (crc_bits >> 3)) |= (1 << (crc_bits & 7)); +		} + +		ax88179_write_cmd_async(dev, AX_ACCESS_MAC, AX_MULFLTARY, +					AX_MCAST_FLTSIZE, AX_MCAST_FLTSIZE, +					m_filter); + +		data->rxctl |= AX_RX_CTL_AM; +	} + +	ax88179_write_cmd_async(dev, AX_ACCESS_MAC, AX_RX_CTL, +				2, 2, &data->rxctl); +} + +static int +ax88179_set_features(struct net_device *net, netdev_features_t features) +{ +	u8 tmp; +	struct usbnet *dev = netdev_priv(net); +	netdev_features_t changed = net->features ^ features; + +	if (changed & NETIF_F_IP_CSUM) { +		ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, &tmp); +		tmp ^= AX_TXCOE_TCP | AX_TXCOE_UDP; +		ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, &tmp); +	} + +	if (changed & NETIF_F_IPV6_CSUM) { +		ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, &tmp); +		tmp ^= AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6; +		ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, &tmp); +	} + +	if (changed & NETIF_F_RXCSUM) { +		ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, &tmp); +		tmp ^= AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP | +		       AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6; +		ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, &tmp); +	} + +	return 0; +} + +static int ax88179_change_mtu(struct net_device *net, int new_mtu) +{ +	struct usbnet *dev = netdev_priv(net); +	u16 tmp16; + +	if (new_mtu <= 0 || new_mtu > 4088) +		return -EINVAL; + +	net->mtu = new_mtu; +	dev->hard_mtu = net->mtu + net->hard_header_len; + +	if (net->mtu > 1500) { +		ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, +				 2, 2, &tmp16); +		tmp16 |= AX_MEDIUM_JUMBO_EN; +		ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, +				  2, 2, &tmp16); +	} else { +		ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, +				 2, 2, &tmp16); +		tmp16 &= ~AX_MEDIUM_JUMBO_EN; +		ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, +				  2, 2, &tmp16); +	} + +	return 0; +} + +static int ax88179_set_mac_addr(struct net_device *net, void *p) +{ +	struct usbnet *dev = netdev_priv(net); +	struct sockaddr *addr = p; + +	if (netif_running(net)) +		return -EBUSY; +	if (!is_valid_ether_addr(addr->sa_data)) +		return -EADDRNOTAVAIL; + +	memcpy(net->dev_addr, addr->sa_data, ETH_ALEN); + +	/* Set the MAC address */ +	return ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, +				 ETH_ALEN, net->dev_addr); +} + +static const struct net_device_ops ax88179_netdev_ops = { +	.ndo_open		= usbnet_open, +	.ndo_stop		= usbnet_stop, +	.ndo_start_xmit		= usbnet_start_xmit, +	.ndo_tx_timeout		= usbnet_tx_timeout, +	.ndo_change_mtu		= ax88179_change_mtu, +	.ndo_set_mac_address	= ax88179_set_mac_addr, +	.ndo_validate_addr	= eth_validate_addr, +	.ndo_do_ioctl		= ax88179_ioctl, +	.ndo_set_rx_mode	= ax88179_set_multicast, +	.ndo_set_features	= ax88179_set_features, +}; + +static int ax88179_check_eeprom(struct usbnet *dev) +{ +	u8 i, buf, eeprom[20]; +	u16 csum, delay = HZ / 10; +	unsigned long jtimeout; + +	/* Read EEPROM content */ +	for (i = 0; i < 6; i++) { +		buf = i; +		if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_ADDR, +				      1, 1, &buf) < 0) +			return -EINVAL; + +		buf = EEP_RD; +		if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD, +				      1, 1, &buf) < 0) +			return -EINVAL; + +		jtimeout = jiffies + delay; +		do { +			ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD, +					 1, 1, &buf); + +			if (time_after(jiffies, jtimeout)) +				return -EINVAL; + +		} while (buf & EEP_BUSY); + +		__ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_DATA_LOW, +				   2, 2, &eeprom[i * 2], 0); + +		if ((i == 0) && (eeprom[0] == 0xFF)) +			return -EINVAL; +	} + +	csum = eeprom[6] + eeprom[7] + eeprom[8] + eeprom[9]; +	csum = (csum >> 8) + (csum & 0xff); +	if ((csum + eeprom[10]) != 0xff) +		return -EINVAL; + +	return 0; +} + +static int ax88179_check_efuse(struct usbnet *dev, u16 *ledmode) +{ +	u8	i; +	u8	efuse[64]; +	u16	csum = 0; + +	if (ax88179_read_cmd(dev, AX_ACCESS_EFUS, 0, 64, 64, efuse) < 0) +		return -EINVAL; + +	if (*efuse == 0xFF) +		return -EINVAL; + +	for (i = 0; i < 64; i++) +		csum = csum + efuse[i]; + +	while (csum > 255) +		csum = (csum & 0x00FF) + ((csum >> 8) & 0x00FF); + +	if (csum != 0xFF) +		return -EINVAL; + +	*ledmode = (efuse[51] << 8) | efuse[52]; + +	return 0; +} + +static int ax88179_convert_old_led(struct usbnet *dev, u16 *ledvalue) +{ +	u16 led; + +	/* Loaded the old eFuse LED Mode */ +	if (ax88179_read_cmd(dev, AX_ACCESS_EEPROM, 0x3C, 1, 2, &led) < 0) +		return -EINVAL; + +	led >>= 8; +	switch (led) { +	case 0xFF: +		led = LED0_ACTIVE | LED1_LINK_10 | LED1_LINK_100 | +		      LED1_LINK_1000 | LED2_ACTIVE | LED2_LINK_10 | +		      LED2_LINK_100 | LED2_LINK_1000 | LED_VALID; +		break; +	case 0xFE: +		led = LED0_ACTIVE | LED1_LINK_1000 | LED2_LINK_100 | LED_VALID; +		break; +	case 0xFD: +		led = LED0_ACTIVE | LED1_LINK_1000 | LED2_LINK_100 | +		      LED2_LINK_10 | LED_VALID; +		break; +	case 0xFC: +		led = LED0_ACTIVE | LED1_ACTIVE | LED1_LINK_1000 | LED2_ACTIVE | +		      LED2_LINK_100 | LED2_LINK_10 | LED_VALID; +		break; +	default: +		led = LED0_ACTIVE | LED1_LINK_10 | LED1_LINK_100 | +		      LED1_LINK_1000 | LED2_ACTIVE | LED2_LINK_10 | +		      LED2_LINK_100 | LED2_LINK_1000 | LED_VALID; +		break; +	} + +	*ledvalue = led; + +	return 0; +} + +static int ax88179_led_setting(struct usbnet *dev) +{ +	u8 ledfd, value = 0; +	u16 tmp, ledact, ledlink, ledvalue = 0, delay = HZ / 10; +	unsigned long jtimeout; + +	/* Check AX88179 version. UA1 or UA2*/ +	ax88179_read_cmd(dev, AX_ACCESS_MAC, GENERAL_STATUS, 1, 1, &value); + +	if (!(value & AX_SECLD)) {	/* UA1 */ +		value = AX_GPIO_CTRL_GPIO3EN | AX_GPIO_CTRL_GPIO2EN | +			AX_GPIO_CTRL_GPIO1EN; +		if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_GPIO_CTRL, +				      1, 1, &value) < 0) +			return -EINVAL; +	} + +	/* Check EEPROM */ +	if (!ax88179_check_eeprom(dev)) { +		value = 0x42; +		if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_ADDR, +				      1, 1, &value) < 0) +			return -EINVAL; + +		value = EEP_RD; +		if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD, +				      1, 1, &value) < 0) +			return -EINVAL; + +		jtimeout = jiffies + delay; +		do { +			ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD, +					 1, 1, &value); + +			if (time_after(jiffies, jtimeout)) +				return -EINVAL; + +		} while (value & EEP_BUSY); + +		ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_DATA_HIGH, +				 1, 1, &value); +		ledvalue = (value << 8); + +		ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_DATA_LOW, +				 1, 1, &value); +		ledvalue |= value; + +		/* load internal ROM for defaule setting */ +		if ((ledvalue == 0xFFFF) || ((ledvalue & LED_VALID) == 0)) +			ax88179_convert_old_led(dev, &ledvalue); + +	} else if (!ax88179_check_efuse(dev, &ledvalue)) { +		if ((ledvalue == 0xFFFF) || ((ledvalue & LED_VALID) == 0)) +			ax88179_convert_old_led(dev, &ledvalue); +	} else { +		ax88179_convert_old_led(dev, &ledvalue); +	} + +	tmp = GMII_PHY_PGSEL_EXT; +	ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, +			  GMII_PHY_PAGE_SELECT, 2, &tmp); + +	tmp = 0x2c; +	ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, +			  GMII_PHYPAGE, 2, &tmp); + +	ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, +			 GMII_LED_ACT, 2, &ledact); + +	ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, +			 GMII_LED_LINK, 2, &ledlink); + +	ledact &= GMII_LED_ACTIVE_MASK; +	ledlink &= GMII_LED_LINK_MASK; + +	if (ledvalue & LED0_ACTIVE) +		ledact |= GMII_LED0_ACTIVE; + +	if (ledvalue & LED1_ACTIVE) +		ledact |= GMII_LED1_ACTIVE; + +	if (ledvalue & LED2_ACTIVE) +		ledact |= GMII_LED2_ACTIVE; + +	if (ledvalue & LED0_LINK_10) +		ledlink |= GMII_LED0_LINK_10; + +	if (ledvalue & LED1_LINK_10) +		ledlink |= GMII_LED1_LINK_10; + +	if (ledvalue & LED2_LINK_10) +		ledlink |= GMII_LED2_LINK_10; + +	if (ledvalue & LED0_LINK_100) +		ledlink |= GMII_LED0_LINK_100; + +	if (ledvalue & LED1_LINK_100) +		ledlink |= GMII_LED1_LINK_100; + +	if (ledvalue & LED2_LINK_100) +		ledlink |= GMII_LED2_LINK_100; + +	if (ledvalue & LED0_LINK_1000) +		ledlink |= GMII_LED0_LINK_1000; + +	if (ledvalue & LED1_LINK_1000) +		ledlink |= GMII_LED1_LINK_1000; + +	if (ledvalue & LED2_LINK_1000) +		ledlink |= GMII_LED2_LINK_1000; + +	tmp = ledact; +	ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, +			  GMII_LED_ACT, 2, &tmp); + +	tmp = ledlink; +	ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, +			  GMII_LED_LINK, 2, &tmp); + +	tmp = GMII_PHY_PGSEL_PAGE0; +	ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, +			  GMII_PHY_PAGE_SELECT, 2, &tmp); + +	/* LED full duplex setting */ +	ledfd = 0; +	if (ledvalue & LED0_FD) +		ledfd |= 0x01; +	else if ((ledvalue & LED0_USB3_MASK) == 0) +		ledfd |= 0x02; + +	if (ledvalue & LED1_FD) +		ledfd |= 0x04; +	else if ((ledvalue & LED1_USB3_MASK) == 0) +		ledfd |= 0x08; + +	if (ledvalue & LED2_FD) +		ledfd |= 0x10; +	else if ((ledvalue & LED2_USB3_MASK) == 0) +		ledfd |= 0x20; + +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_LEDCTRL, 1, 1, &ledfd); + +	return 0; +} + +static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf) +{ +	u8 buf[5]; +	u16 *tmp16; +	u8 *tmp; +	struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data; + +	usbnet_get_endpoints(dev, intf); + +	tmp16 = (u16 *)buf; +	tmp = (u8 *)buf; + +	memset(ax179_data, 0, sizeof(*ax179_data)); + +	/* Power up ethernet PHY */ +	*tmp16 = 0; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16); +	*tmp16 = AX_PHYPWR_RSTCTL_IPRL; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16); +	msleep(200); + +	*tmp = AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp); +	msleep(100); + +	ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, +			 ETH_ALEN, dev->net->dev_addr); +	memcpy(dev->net->perm_addr, dev->net->dev_addr, ETH_ALEN); + +	/* RX bulk configuration */ +	memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5); +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp); + +	dev->rx_urb_size = 1024 * 20; + +	*tmp = 0x34; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_LOW, 1, 1, tmp); + +	*tmp = 0x52; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_HIGH, +			  1, 1, tmp); + +	dev->net->netdev_ops = &ax88179_netdev_ops; +	dev->net->ethtool_ops = &ax88179_ethtool_ops; +	dev->net->needed_headroom = 8; + +	/* Initialize MII structure */ +	dev->mii.dev = dev->net; +	dev->mii.mdio_read = ax88179_mdio_read; +	dev->mii.mdio_write = ax88179_mdio_write; +	dev->mii.phy_id_mask = 0xff; +	dev->mii.reg_num_mask = 0xff; +	dev->mii.phy_id = 0x03; +	dev->mii.supports_gmii = 1; + +	dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | +			      NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO; + +	dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | +				 NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO; + +	/* Enable checksum offload */ +	*tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP | +	       AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, tmp); + +	*tmp = AX_TXCOE_IP | AX_TXCOE_TCP | AX_TXCOE_UDP | +	       AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, tmp); + +	/* Configure RX control register => start operation */ +	*tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_IPE | AX_RX_CTL_START | +		 AX_RX_CTL_AP | AX_RX_CTL_AMALL | AX_RX_CTL_AB; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, tmp16); + +	*tmp = AX_MONITOR_MODE_PMETYPE | AX_MONITOR_MODE_PMEPOL | +	       AX_MONITOR_MODE_RWMP; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MOD, 1, 1, tmp); + +	/* Configure default medium type => giga */ +	*tmp16 = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN | +		 AX_MEDIUM_RXFLOW_CTRLEN | AX_MEDIUM_ALWAYS_ONE | +		 AX_MEDIUM_FULL_DUPLEX | AX_MEDIUM_GIGAMODE; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, +			  2, 2, tmp16); + +	ax88179_led_setting(dev); + +	/* Restart autoneg */ +	mii_nway_restart(&dev->mii); + +	netif_carrier_off(dev->net); + +	return 0; +} + +static void ax88179_unbind(struct usbnet *dev, struct usb_interface *intf) +{ +	u16 tmp16; + +	/* Configure RX control register => stop operation */ +	tmp16 = AX_RX_CTL_STOP; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &tmp16); + +	tmp16 = 0; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp16); + +	/* Power down ethernet PHY */ +	tmp16 = 0; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, &tmp16); +} + +static void +ax88179_rx_checksum(struct sk_buff *skb, u32 *pkt_hdr) +{ +	skb->ip_summed = CHECKSUM_NONE; + +	/* checksum error bit is set */ +	if ((*pkt_hdr & AX_RXHDR_L3CSUM_ERR) || +	    (*pkt_hdr & AX_RXHDR_L4CSUM_ERR)) +		return; + +	/* It must be a TCP or UDP packet with a valid checksum */ +	if (((*pkt_hdr & AX_RXHDR_L4_TYPE_MASK) == AX_RXHDR_L4_TYPE_TCP) || +	    ((*pkt_hdr & AX_RXHDR_L4_TYPE_MASK) == AX_RXHDR_L4_TYPE_UDP)) +		skb->ip_summed = CHECKSUM_UNNECESSARY; +} + +static int ax88179_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ +	struct sk_buff *ax_skb; +	int pkt_cnt; +	u32 rx_hdr; +	u16 hdr_off; +	u32 *pkt_hdr; + +	skb_trim(skb, skb->len - 4); +	memcpy(&rx_hdr, skb_tail_pointer(skb), 4); +	le32_to_cpus(&rx_hdr); + +	pkt_cnt = (u16)rx_hdr; +	hdr_off = (u16)(rx_hdr >> 16); +	pkt_hdr = (u32 *)(skb->data + hdr_off); + +	while (pkt_cnt--) { +		u16 pkt_len; + +		le32_to_cpus(pkt_hdr); +		pkt_len = (*pkt_hdr >> 16) & 0x1fff; + +		/* Check CRC or runt packet */ +		if ((*pkt_hdr & AX_RXHDR_CRC_ERR) || +		    (*pkt_hdr & AX_RXHDR_DROP_ERR)) { +			skb_pull(skb, (pkt_len + 7) & 0xFFF8); +			pkt_hdr++; +			continue; +		} + +		if (pkt_cnt == 0) { +			/* Skip IP alignment psudo header */ +			skb_pull(skb, 2); +			skb->len = pkt_len; +			skb_set_tail_pointer(skb, pkt_len); +			skb->truesize = pkt_len + sizeof(struct sk_buff); +			ax88179_rx_checksum(skb, pkt_hdr); +			return 1; +		} + +		ax_skb = skb_clone(skb, GFP_ATOMIC); +		if (ax_skb) { +			ax_skb->len = pkt_len; +			ax_skb->data = skb->data + 2; +			skb_set_tail_pointer(ax_skb, pkt_len); +			ax_skb->truesize = pkt_len + sizeof(struct sk_buff); +			ax88179_rx_checksum(ax_skb, pkt_hdr); +			usbnet_skb_return(dev, ax_skb); +		} else { +			return 0; +		} + +		skb_pull(skb, (pkt_len + 7) & 0xFFF8); +		pkt_hdr++; +	} +	return 1; +} + +static struct sk_buff * +ax88179_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) +{ +	u32 tx_hdr1, tx_hdr2; +	int frame_size = dev->maxpacket; +	int mss = skb_shinfo(skb)->gso_size; +	int headroom; +	int tailroom; + +	tx_hdr1 = skb->len; +	tx_hdr2 = mss; +	if (((skb->len + 8) % frame_size) == 0) +		tx_hdr2 |= 0x80008000;	/* Enable padding */ + +	skb_linearize(skb); +	headroom = skb_headroom(skb); +	tailroom = skb_tailroom(skb); + +	if (!skb_header_cloned(skb) && +	    !skb_cloned(skb) && +	    (headroom + tailroom) >= 8) { +		if (headroom < 8) { +			skb->data = memmove(skb->head + 8, skb->data, skb->len); +			skb_set_tail_pointer(skb, skb->len); +		} +	} else { +		struct sk_buff *skb2; + +		skb2 = skb_copy_expand(skb, 8, 0, flags); +		dev_kfree_skb_any(skb); +		skb = skb2; +		if (!skb) +			return NULL; +	} + +	skb_push(skb, 4); +	cpu_to_le32s(&tx_hdr2); +	skb_copy_to_linear_data(skb, &tx_hdr2, 4); + +	skb_push(skb, 4); +	cpu_to_le32s(&tx_hdr1); +	skb_copy_to_linear_data(skb, &tx_hdr1, 4); + +	return skb; +} + +static int ax88179_link_reset(struct usbnet *dev) +{ +	struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data; +	u8 tmp[5], link_sts; +	u16 mode, tmp16, delay = HZ / 10; +	u32 tmp32 = 0x40000000; +	unsigned long jtimeout; + +	jtimeout = jiffies + delay; +	while (tmp32 & 0x40000000) { +		mode = 0; +		ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &mode); +		ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, +				  &ax179_data->rxctl); + +		/*link up, check the usb device control TX FIFO full or empty*/ +		ax88179_read_cmd(dev, 0x81, 0x8c, 0, 4, &tmp32); + +		if (time_after(jiffies, jtimeout)) +			return 0; +	} + +	mode = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN | +	       AX_MEDIUM_RXFLOW_CTRLEN | AX_MEDIUM_ALWAYS_ONE; + +	ax88179_read_cmd(dev, AX_ACCESS_MAC, PHYSICAL_LINK_STATUS, +			 1, 1, &link_sts); + +	ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, +			 GMII_PHY_PHYSR, 2, &tmp16); + +	if (!(tmp16 & GMII_PHY_PHYSR_LINK)) { +		return 0; +	} else if (GMII_PHY_PHYSR_GIGA == (tmp16 & GMII_PHY_PHYSR_SMASK)) { +		mode |= AX_MEDIUM_GIGAMODE | AX_MEDIUM_EN_125MHZ; +		if (dev->net->mtu > 1500) +			mode |= AX_MEDIUM_JUMBO_EN; + +		if (link_sts & AX_USB_SS) +			memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5); +		else if (link_sts & AX_USB_HS) +			memcpy(tmp, &AX88179_BULKIN_SIZE[1], 5); +		else +			memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5); +	} else if (GMII_PHY_PHYSR_100 == (tmp16 & GMII_PHY_PHYSR_SMASK)) { +		mode |= AX_MEDIUM_PS; + +		if (link_sts & (AX_USB_SS | AX_USB_HS)) +			memcpy(tmp, &AX88179_BULKIN_SIZE[2], 5); +		else +			memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5); +	} else { +		memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5); +	} + +	/* RX bulk configuration */ +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp); + +	dev->rx_urb_size = (1024 * (tmp[3] + 2)); + +	if (tmp16 & GMII_PHY_PHYSR_FULL) +		mode |= AX_MEDIUM_FULL_DUPLEX; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, +			  2, 2, &mode); + +	netif_carrier_on(dev->net); + +	return 0; +} + +static int ax88179_reset(struct usbnet *dev) +{ +	u8 buf[5]; +	u16 *tmp16; +	u8 *tmp; + +	tmp16 = (u16 *)buf; +	tmp = (u8 *)buf; + +	/* Power up ethernet PHY */ +	*tmp16 = 0; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16); + +	*tmp16 = AX_PHYPWR_RSTCTL_IPRL; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16); +	msleep(200); + +	*tmp = AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp); +	msleep(100); + +	/* Ethernet PHY Auto Detach*/ +	ax88179_auto_detach(dev, 0); + +	ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, ETH_ALEN, +			 dev->net->dev_addr); +	memcpy(dev->net->perm_addr, dev->net->dev_addr, ETH_ALEN); + +	/* RX bulk configuration */ +	memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5); +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp); + +	dev->rx_urb_size = 1024 * 20; + +	*tmp = 0x34; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_LOW, 1, 1, tmp); + +	*tmp = 0x52; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_HIGH, +			  1, 1, tmp); + +	dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | +			      NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO; + +	dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | +				 NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO; + +	/* Enable checksum offload */ +	*tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP | +	       AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, tmp); + +	*tmp = AX_TXCOE_IP | AX_TXCOE_TCP | AX_TXCOE_UDP | +	       AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, tmp); + +	/* Configure RX control register => start operation */ +	*tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_IPE | AX_RX_CTL_START | +		 AX_RX_CTL_AP | AX_RX_CTL_AMALL | AX_RX_CTL_AB; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, tmp16); + +	*tmp = AX_MONITOR_MODE_PMETYPE | AX_MONITOR_MODE_PMEPOL | +	       AX_MONITOR_MODE_RWMP; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MOD, 1, 1, tmp); + +	/* Configure default medium type => giga */ +	*tmp16 = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN | +		 AX_MEDIUM_RXFLOW_CTRLEN | AX_MEDIUM_ALWAYS_ONE | +		 AX_MEDIUM_FULL_DUPLEX | AX_MEDIUM_GIGAMODE; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, +			  2, 2, tmp16); + +	ax88179_led_setting(dev); + +	/* Restart autoneg */ +	mii_nway_restart(&dev->mii); + +	netif_carrier_off(dev->net); + +	return 0; +} + +static int ax88179_stop(struct usbnet *dev) +{ +	u16 tmp16; + +	ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, +			 2, 2, &tmp16); +	tmp16 &= ~AX_MEDIUM_RECEIVE_EN; +	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, +			  2, 2, &tmp16); + +	return 0; +} + +static const struct driver_info ax88179_info = { +	.description = "ASIX AX88179 USB 3.0 Gigibit Ethernet", +	.bind = ax88179_bind, +	.unbind = ax88179_unbind, +	.status = ax88179_status, +	.link_reset = ax88179_link_reset, +	.reset = ax88179_reset, +	.stop = ax88179_stop, +	.flags = FLAG_ETHER | FLAG_FRAMING_AX, +	.rx_fixup = ax88179_rx_fixup, +	.tx_fixup = ax88179_tx_fixup, +}; + +static const struct driver_info ax88178a_info = { +	.description = "ASIX AX88178A USB 2.0 Gigibit Ethernet", +	.bind = ax88179_bind, +	.unbind = ax88179_unbind, +	.status = ax88179_status, +	.link_reset = ax88179_link_reset, +	.reset = ax88179_reset, +	.stop = ax88179_stop, +	.flags = FLAG_ETHER | FLAG_FRAMING_AX, +	.rx_fixup = ax88179_rx_fixup, +	.tx_fixup = ax88179_tx_fixup, +}; + +static const struct driver_info sitecom_info = { +	.description = "Sitecom USB 3.0 to Gigabit Adapter", +	.bind = ax88179_bind, +	.unbind = ax88179_unbind, +	.status = ax88179_status, +	.link_reset = ax88179_link_reset, +	.reset = ax88179_reset, +	.stop = ax88179_stop, +	.flags = FLAG_ETHER | FLAG_FRAMING_AX, +	.rx_fixup = ax88179_rx_fixup, +	.tx_fixup = ax88179_tx_fixup, +}; + +static const struct usb_device_id products[] = { +{ +	/* ASIX AX88179 10/100/1000 */ +	USB_DEVICE(0x0b95, 0x1790), +	.driver_info = (unsigned long)&ax88179_info, +}, { +	/* ASIX AX88178A 10/100/1000 */ +	USB_DEVICE(0x0b95, 0x178a), +	.driver_info = (unsigned long)&ax88178a_info, +}, { +	/* Sitecom USB 3.0 to Gigabit Adapter */ +	USB_DEVICE(0x0df6, 0x0072), +	.driver_info = (unsigned long) &sitecom_info, +}, +	{ }, +}; +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver ax88179_178a_driver = { +	.name =		"ax88179_178a", +	.id_table =	products, +	.probe =	usbnet_probe, +	.suspend =	ax88179_suspend, +	.resume =	ax88179_resume, +	.disconnect =	usbnet_disconnect, +	.supports_autosuspend = 1, +	.disable_hub_initiated_lpm = 1, +}; + +module_usb_driver(ax88179_178a_driver); + +MODULE_DESCRIPTION("ASIX AX88179/178A based USB 3.0/2.0 Gigabit Ethernet Devices"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c index 248d2dc765a..32a76059e7d 100644 --- a/drivers/net/usb/cdc_mbim.c +++ b/drivers/net/usb/cdc_mbim.c @@ -68,18 +68,9 @@ static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf)  	struct cdc_ncm_ctx *ctx;  	struct usb_driver *subdriver = ERR_PTR(-ENODEV);  	int ret = -ENODEV; -	u8 data_altsetting = CDC_NCM_DATA_ALTSETTING_NCM; +	u8 data_altsetting = cdc_ncm_select_altsetting(dev, intf);  	struct cdc_mbim_state *info = (void *)&dev->data; -	/* see if interface supports MBIM alternate setting */ -	if (intf->num_altsetting == 2) { -		if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) -			usb_set_interface(dev->udev, -					  intf->cur_altsetting->desc.bInterfaceNumber, -					  CDC_NCM_COMM_ALTSETTING_MBIM); -		data_altsetting = CDC_NCM_DATA_ALTSETTING_MBIM; -	} -  	/* Probably NCM, defer for cdc_ncm_bind */  	if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting))  		goto err; @@ -143,7 +134,7 @@ static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb  		goto error;  	if (skb) { -		if (skb->len <= sizeof(ETH_HLEN)) +		if (skb->len <= ETH_HLEN)  			goto error;  		/* mapping VLANs to MBIM sessions: @@ -332,6 +323,11 @@ static int cdc_mbim_suspend(struct usb_interface *intf, pm_message_t message)  		goto error;  	} +	/* +	 * Both usbnet_suspend() and subdriver->suspend() MUST return 0 +	 * in system sleep context, otherwise, the resume callback has +	 * to recover device from previous suspend failure. +	 */  	ret = usbnet_suspend(intf, message);  	if (ret < 0)  		goto error; diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 4a8c25a2229..4709fa3497c 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -55,6 +55,14 @@  #define	DRIVER_VERSION				"14-Mar-2012" +#if IS_ENABLED(CONFIG_USB_NET_CDC_MBIM) +static bool prefer_mbim = true; +#else +static bool prefer_mbim; +#endif +module_param(prefer_mbim, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(prefer_mbim, "Prefer MBIM setting on dual NCM/MBIM functions"); +  static void cdc_ncm_txpath_bh(unsigned long param);  static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx);  static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *hr_timer); @@ -550,9 +558,12 @@ void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf)  }  EXPORT_SYMBOL_GPL(cdc_ncm_unbind); -static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) +/* Select the MBIM altsetting iff it is preferred and available, + * returning the number of the corresponding data interface altsetting + */ +u8 cdc_ncm_select_altsetting(struct usbnet *dev, struct usb_interface *intf)  { -	int ret; +	struct usb_host_interface *alt;  	/* The MBIM spec defines a NCM compatible default altsetting,  	 * which we may have matched: @@ -568,23 +579,27 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)  	 *   endpoint descriptors, shall be constructed according to  	 *   the rules given in section 6 (USB Device Model) of this  	 *   specification." -	 * -	 * Do not bind to such interfaces, allowing cdc_mbim to handle -	 * them  	 */ -#if IS_ENABLED(CONFIG_USB_NET_CDC_MBIM) -	if ((intf->num_altsetting == 2) && -	    !usb_set_interface(dev->udev, -			       intf->cur_altsetting->desc.bInterfaceNumber, -			       CDC_NCM_COMM_ALTSETTING_MBIM)) { -		if (cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) -			return -ENODEV; -		else -			usb_set_interface(dev->udev, -					  intf->cur_altsetting->desc.bInterfaceNumber, -					  CDC_NCM_COMM_ALTSETTING_NCM); +	if (prefer_mbim && intf->num_altsetting == 2) { +		alt = usb_altnum_to_altsetting(intf, CDC_NCM_COMM_ALTSETTING_MBIM); +		if (alt && cdc_ncm_comm_intf_is_mbim(alt) && +		    !usb_set_interface(dev->udev, +				       intf->cur_altsetting->desc.bInterfaceNumber, +				       CDC_NCM_COMM_ALTSETTING_MBIM)) +			return CDC_NCM_DATA_ALTSETTING_MBIM;  	} -#endif +	return CDC_NCM_DATA_ALTSETTING_NCM; +} +EXPORT_SYMBOL_GPL(cdc_ncm_select_altsetting); + +static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) +{ +	int ret; + +	/* MBIM backwards compatible function? */ +	cdc_ncm_select_altsetting(dev, intf); +	if (cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) +		return -ENODEV;  	/* NCM data altsetting is always 1 */  	ret = cdc_ncm_bind_common(dev, intf, 1); @@ -1213,6 +1228,14 @@ static const struct usb_device_id cdc_devs[] = {  	  .driver_info = (unsigned long) &wwan_info,  	}, +	/* tag Huawei devices as wwan */ +	{ USB_VENDOR_AND_INTERFACE_INFO(0x12d1, +					USB_CLASS_COMM, +					USB_CDC_SUBCLASS_NCM, +					USB_CDC_PROTO_NONE), +	  .driver_info = (unsigned long)&wwan_info, +	}, +  	/* Huawei NCM devices disguised as vendor specific */  	{ USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x16),  	  .driver_info = (unsigned long)&wwan_info, diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index e2dd3249b6b..cba1d46e672 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -1925,7 +1925,6 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)  {  	struct hso_serial *serial = urb->context;  	int status = urb->status; -	struct tty_struct *tty;  	/* sanity check */  	if (!serial) { @@ -1941,11 +1940,7 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)  		return;  	}  	hso_put_activity(serial->parent); -	tty = tty_port_tty_get(&serial->port); -	if (tty) { -		tty_wakeup(tty); -		tty_kref_put(tty); -	} +	tty_port_tty_wakeup(&serial->port);  	hso_kick_transmit(serial);  	D1(" "); @@ -2008,12 +2003,8 @@ static void ctrl_callback(struct urb *urb)  		put_rxbuf_data_and_resubmit_ctrl_urb(serial);  		spin_unlock(&serial->serial_lock);  	} else { -		struct tty_struct *tty = tty_port_tty_get(&serial->port);  		hso_put_activity(serial->parent); -		if (tty) { -			tty_wakeup(tty); -			tty_kref_put(tty); -		} +		tty_port_tty_wakeup(&serial->port);  		/* response to a write command */  		hso_kick_transmit(serial);  	} @@ -3133,18 +3124,13 @@ static void hso_serial_ref_free(struct kref *ref)  static void hso_free_interface(struct usb_interface *interface)  {  	struct hso_serial *hso_dev; -	struct tty_struct *tty;  	int i;  	for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {  		if (serial_table[i] &&  		    (serial_table[i]->interface == interface)) {  			hso_dev = dev2ser(serial_table[i]); -			tty = tty_port_tty_get(&hso_dev->port); -			if (tty) { -				tty_hangup(tty); -				tty_kref_put(tty); -			} +			tty_port_tty_hangup(&hso_dev->port, false);  			mutex_lock(&hso_dev->parent->mutex);  			hso_dev->parent->usb_gone = 1;  			mutex_unlock(&hso_dev->parent->mutex); diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index efb5c7c33a2..5a88e72090c 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -13,6 +13,7 @@  #include <linux/module.h>  #include <linux/netdevice.h>  #include <linux/ethtool.h> +#include <linux/etherdevice.h>  #include <linux/mii.h>  #include <linux/usb.h>  #include <linux/usb/cdc.h> @@ -52,6 +53,96 @@ struct qmi_wwan_state {  	struct usb_interface *data;  }; +/* default ethernet address used by the modem */ +static const u8 default_modem_addr[ETH_ALEN] = {0x02, 0x50, 0xf3}; + +/* Make up an ethernet header if the packet doesn't have one. + * + * A firmware bug common among several devices cause them to send raw + * IP packets under some circumstances.  There is no way for the + * driver/host to know when this will happen.  And even when the bug + * hits, some packets will still arrive with an intact header. + * + * The supported devices are only capably of sending IPv4, IPv6 and + * ARP packets on a point-to-point link. Any packet with an ethernet + * header will have either our address or a broadcast/multicast + * address as destination.  ARP packets will always have a header. + * + * This means that this function will reliably add the appropriate + * header iff necessary, provided our hardware address does not start + * with 4 or 6. + * + * Another common firmware bug results in all packets being addressed + * to 00:a0:c6:00:00:00 despite the host address being different. + * This function will also fixup such packets. + */ +static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ +	__be16 proto; + +	/* usbnet rx_complete guarantees that skb->len is at least +	 * hard_header_len, so we can inspect the dest address without +	 * checking skb->len +	 */ +	switch (skb->data[0] & 0xf0) { +	case 0x40: +		proto = htons(ETH_P_IP); +		break; +	case 0x60: +		proto = htons(ETH_P_IPV6); +		break; +	case 0x00: +		if (is_multicast_ether_addr(skb->data)) +			return 1; +		/* possibly bogus destination - rewrite just in case */ +		skb_reset_mac_header(skb); +		goto fix_dest; +	default: +		/* pass along other packets without modifications */ +		return 1; +	} +	if (skb_headroom(skb) < ETH_HLEN) +		return 0; +	skb_push(skb, ETH_HLEN); +	skb_reset_mac_header(skb); +	eth_hdr(skb)->h_proto = proto; +	memset(eth_hdr(skb)->h_source, 0, ETH_ALEN); +fix_dest: +	memcpy(eth_hdr(skb)->h_dest, dev->net->dev_addr, ETH_ALEN); +	return 1; +} + +/* very simplistic detection of IPv4 or IPv6 headers */ +static bool possibly_iphdr(const char *data) +{ +	return (data[0] & 0xd0) == 0x40; +} + +/* disallow addresses which may be confused with IP headers */ +static int qmi_wwan_mac_addr(struct net_device *dev, void *p) +{ +	int ret; +	struct sockaddr *addr = p; + +	ret = eth_prepare_mac_addr_change(dev, p); +	if (ret < 0) +		return ret; +	if (possibly_iphdr(addr->sa_data)) +		return -EADDRNOTAVAIL; +	eth_commit_mac_addr_change(dev, p); +	return 0; +} + +static const struct net_device_ops qmi_wwan_netdev_ops = { +	.ndo_open		= usbnet_open, +	.ndo_stop		= usbnet_stop, +	.ndo_start_xmit		= usbnet_start_xmit, +	.ndo_tx_timeout		= usbnet_tx_timeout, +	.ndo_change_mtu		= usbnet_change_mtu, +	.ndo_set_mac_address	= qmi_wwan_mac_addr, +	.ndo_validate_addr	= eth_validate_addr, +}; +  /* using a counter to merge subdriver requests with our own into a combined state */  static int qmi_wwan_manage_power(struct usbnet *dev, int on)  { @@ -139,16 +230,9 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)  	BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data) < sizeof(struct qmi_wwan_state))); -	/* control and data is shared? */ -	if (intf->cur_altsetting->desc.bNumEndpoints == 3) { -		info->control = intf; -		info->data = intf; -		goto shared; -	} - -	/* else require a single interrupt status endpoint on control intf */ -	if (intf->cur_altsetting->desc.bNumEndpoints != 1) -		goto err; +	/* set up initial state */ +	info->control = intf; +	info->data = intf;  	/* and a number of CDC descriptors */  	while (len > 3) { @@ -207,25 +291,14 @@ next_desc:  		buf += h->bLength;  	} -	/* did we find all the required ones? */ -	if (!(found & (1 << USB_CDC_HEADER_TYPE)) || -	    !(found & (1 << USB_CDC_UNION_TYPE))) { -		dev_err(&intf->dev, "CDC functional descriptors missing\n"); -		goto err; -	} - -	/* verify CDC Union */ -	if (desc->bInterfaceNumber != cdc_union->bMasterInterface0) { -		dev_err(&intf->dev, "bogus CDC Union: master=%u\n", cdc_union->bMasterInterface0); -		goto err; -	} - -	/* need to save these for unbind */ -	info->control = intf; -	info->data = usb_ifnum_to_if(dev->udev,	cdc_union->bSlaveInterface0); -	if (!info->data) { -		dev_err(&intf->dev, "bogus CDC Union: slave=%u\n", cdc_union->bSlaveInterface0); -		goto err; +	/* Use separate control and data interfaces if we found a CDC Union */ +	if (cdc_union) { +		info->data = usb_ifnum_to_if(dev->udev, cdc_union->bSlaveInterface0); +		if (desc->bInterfaceNumber != cdc_union->bMasterInterface0 || !info->data) { +			dev_err(&intf->dev, "bogus CDC Union: master=%u, slave=%u\n", +				cdc_union->bMasterInterface0, cdc_union->bSlaveInterface0); +			goto err; +		}  	}  	/* errors aren't fatal - we can live with the dynamic address */ @@ -235,17 +308,30 @@ next_desc:  	}  	/* claim data interface and set it up */ -	status = usb_driver_claim_interface(driver, info->data, dev); -	if (status < 0) -		goto err; +	if (info->control != info->data) { +		status = usb_driver_claim_interface(driver, info->data, dev); +		if (status < 0) +			goto err; +	} -shared:  	status = qmi_wwan_register_subdriver(dev);  	if (status < 0 && info->control != info->data) {  		usb_set_intfdata(info->data, NULL);  		usb_driver_release_interface(driver, info->data);  	} +	/* Never use the same address on both ends of the link, even +	 * if the buggy firmware told us to. +	 */ +	if (!compare_ether_addr(dev->net->dev_addr, default_modem_addr)) +		eth_hw_addr_random(dev->net); + +	/* make MAC addr easily distinguishable from an IP header */ +	if (possibly_iphdr(dev->net->dev_addr)) { +		dev->net->dev_addr[0] |= 0x02;	/* set local assignment bit */ +		dev->net->dev_addr[0] &= 0xbf;	/* clear "IP" bit */ +	} +	dev->net->netdev_ops = &qmi_wwan_netdev_ops;  err:  	return status;  } @@ -288,6 +374,11 @@ static int qmi_wwan_suspend(struct usb_interface *intf, pm_message_t message)  	struct qmi_wwan_state *info = (void *)&dev->data;  	int ret; +	/* +	 * Both usbnet_suspend() and subdriver->suspend() MUST return 0 +	 * in system sleep context, otherwise, the resume callback has +	 * to recover device from previous suspend failure. +	 */  	ret = usbnet_suspend(intf, message);  	if (ret < 0)  		goto err; @@ -324,6 +415,7 @@ static const struct driver_info	qmi_wwan_info = {  	.bind		= qmi_wwan_bind,  	.unbind		= qmi_wwan_unbind,  	.manage_power	= qmi_wwan_manage_power, +	.rx_fixup       = qmi_wwan_rx_fixup,  };  #define HUAWEI_VENDOR_ID	0x12D1 diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 9abe51710f2..75409748c77 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -914,8 +914,12 @@ static int smsc75xx_set_rx_max_frame_length(struct usbnet *dev, int size)  static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu)  {  	struct usbnet *dev = netdev_priv(netdev); +	int ret; + +	if (new_mtu > MAX_SINGLE_PACKET_SIZE) +		return -EINVAL; -	int ret = smsc75xx_set_rx_max_frame_length(dev, new_mtu); +	ret = smsc75xx_set_rx_max_frame_length(dev, new_mtu + ETH_HLEN);  	if (ret < 0) {  		netdev_warn(dev->net, "Failed to set mac rx frame length\n");  		return ret; @@ -1324,7 +1328,7 @@ static int smsc75xx_reset(struct usbnet *dev)  	netif_dbg(dev, ifup, dev->net, "FCT_TX_CTL set to 0x%08x\n", buf); -	ret = smsc75xx_set_rx_max_frame_length(dev, 1514); +	ret = smsc75xx_set_rx_max_frame_length(dev, dev->net->mtu + ETH_HLEN);  	if (ret < 0) {  		netdev_warn(dev->net, "Failed to set max rx frame length\n");  		return ret; @@ -2011,7 +2015,11 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)  	ret = smsc75xx_enter_suspend0(dev);  done: -	if (ret) +	/* +	 * TODO: resume() might need to handle the suspend failure +	 * in system sleep +	 */ +	if (ret && PMSG_IS_AUTO(message))  		usbnet_resume(intf);  	return ret;  } @@ -2134,8 +2142,8 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)  			else if (rx_cmd_a & (RX_CMD_A_LONG | RX_CMD_A_RUNT))  				dev->net->stats.rx_frame_errors++;  		} else { -			/* ETH_FRAME_LEN + 4(CRC) + 2(COE) + 4(Vlan) */ -			if (unlikely(size > (ETH_FRAME_LEN + 12))) { +			/* MAX_SINGLE_PACKET_SIZE + 4(CRC) + 2(COE) + 4(Vlan) */ +			if (unlikely(size > (MAX_SINGLE_PACKET_SIZE + ETH_HLEN + 12))) {  				netif_dbg(dev, rx_err, dev->net,  					  "size err rx_cmd_a=0x%08x\n",  					  rx_cmd_a); diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index e6d2dea1373..3f38ba868f6 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -1660,7 +1660,11 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)  	ret = smsc95xx_enter_suspend0(dev);  done: -	if (ret) +	/* +	 * TODO: resume() might need to handle the suspend failure +	 * in system sleep +	 */ +	if (ret && PMSG_IS_AUTO(message))  		usbnet_resume(intf);  	return ret;  } diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 4aad350e4da..eae7a03d4f9 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -2958,6 +2958,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,  	adapter->num_rx_queues = num_rx_queues;  	adapter->num_tx_queues = num_tx_queues; +	adapter->rx_buf_per_pkt = 1;  	size = sizeof(struct Vmxnet3_TxQueueDesc) * adapter->num_tx_queues;  	size += sizeof(struct Vmxnet3_RxQueueDesc) * adapter->num_rx_queues; diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index a0feb17a023..63a124340cb 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c @@ -472,6 +472,12 @@ vmxnet3_set_ringparam(struct net_device *netdev,  						VMXNET3_RX_RING_MAX_SIZE)  		return -EINVAL; +	/* if adapter not yet initialized, do nothing */ +	if (adapter->rx_buf_per_pkt == 0) { +		netdev_err(netdev, "adapter not completely initialized, " +			   "ring size cannot be changed yet\n"); +		return -EOPNOTSUPP; +	}  	/* round it up to a multiple of VMXNET3_RING_SIZE_ALIGN */  	new_tx_ring_size = (param->tx_pending + VMXNET3_RING_SIZE_MASK) & diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h index 3198384689d..35418146fa1 100644 --- a/drivers/net/vmxnet3/vmxnet3_int.h +++ b/drivers/net/vmxnet3/vmxnet3_int.h @@ -70,10 +70,10 @@  /*   * Version numbers   */ -#define VMXNET3_DRIVER_VERSION_STRING   "1.1.29.0-k" +#define VMXNET3_DRIVER_VERSION_STRING   "1.1.30.0-k"  /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */ -#define VMXNET3_DRIVER_VERSION_NUM      0x01011D00 +#define VMXNET3_DRIVER_VERSION_NUM      0x01011E00  #if defined(CONFIG_PCI_MSI)  	/* RSS only makes sense if MSI-X is supported. */ diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index f10e58ac9c1..7cee7a3068e 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -961,6 +961,8 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)  	iph->ttl	= ttl ? : ip4_dst_hoplimit(&rt->dst);  	tunnel_ip_select_ident(skb, old_iph, &rt->dst); +	nf_reset(skb); +  	vxlan_set_owner(dev, skb);  	/* See iptunnel_xmit() */ @@ -1504,6 +1506,14 @@ static __net_init int vxlan_init_net(struct net *net)  static __net_exit void vxlan_exit_net(struct net *net)  {  	struct vxlan_net *vn = net_generic(net, vxlan_net_id); +	struct vxlan_dev *vxlan; +	unsigned h; + +	rtnl_lock(); +	for (h = 0; h < VNI_HASH_SIZE; ++h) +		hlist_for_each_entry(vxlan, &vn->vni_list[h], hlist) +			dev_close(vxlan->dev); +	rtnl_unlock();  	if (vn->sock) {  		sk_release_kernel(vn->sock->sk); diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index 956024a636e..14128fd265a 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -180,16 +180,7 @@ static struct pcmcia_driver airo_driver = {  	.suspend	= airo_suspend,  	.resume		= airo_resume,  }; - -static int __init airo_cs_init(void) -{ -	return pcmcia_register_driver(&airo_driver); -} - -static void __exit airo_cs_cleanup(void) -{ -	pcmcia_unregister_driver(&airo_driver); -} +module_pcmcia_driver(airo_driver);  /*      This program is free software; you can redistribute it and/or @@ -229,6 +220,3 @@ static void __exit airo_cs_cleanup(void)      IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE      POSSIBILITY OF SUCH DAMAGE.  */ - -module_init(airo_cs_init); -module_exit(airo_cs_cleanup); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 4cc13940c89..f76c3ca07a4 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -1023,6 +1023,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,  					  AR_PHY_AGC_CONTROL_FLTR_CAL   |  					  AR_PHY_AGC_CONTROL_PKDET_CAL; +	/* Use chip chainmask only for calibration */  	ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);  	if (rtt) { @@ -1150,6 +1151,9 @@ skip_tx_iqcal:  		ar9003_hw_rtt_disable(ah);  	} +	/* Revert chainmask to runtime parameters */ +	ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); +  	/* Initialize list pointers */  	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; diff --git a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h index 28fd99203f6..bdee2ed6721 100644 --- a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h @@ -519,7 +519,7 @@ static const u32 ar9580_1p0_mac_core[][2] = {  	{0x00008258, 0x00000000},  	{0x0000825c, 0x40000000},  	{0x00008260, 0x00080922}, -	{0x00008264, 0x9bc00010}, +	{0x00008264, 0x9d400010},  	{0x00008268, 0xffffffff},  	{0x0000826c, 0x0000ffff},  	{0x00008270, 0x00000000}, diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index 5f845beeb18..050ca4a4850 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -27,7 +27,7 @@  #define WME_MAX_BA              WME_BA_BMP_SIZE  #define ATH_TID_MAX_BUFS        (2 * WME_MAX_BA) -#define ATH_RSSI_DUMMY_MARKER   0x127 +#define ATH_RSSI_DUMMY_MARKER   127  #define ATH_RSSI_LPF_LEN 		10  #define RSSI_LPF_THRESHOLD		-20  #define ATH_RSSI_EP_MULTIPLIER     (1<<7) diff --git a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c index 467b60014b7..73fe8d6db56 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c +++ b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c @@ -143,14 +143,14 @@ channel_detector_create(struct dfs_pattern_detector *dpd, u16 freq)  	u32 sz, i;  	struct channel_detector *cd; -	cd = kmalloc(sizeof(*cd), GFP_KERNEL); +	cd = kmalloc(sizeof(*cd), GFP_ATOMIC);  	if (cd == NULL)  		goto fail;  	INIT_LIST_HEAD(&cd->head);  	cd->freq = freq;  	sz = sizeof(cd->detectors) * dpd->num_radar_types; -	cd->detectors = kzalloc(sz, GFP_KERNEL); +	cd->detectors = kzalloc(sz, GFP_ATOMIC);  	if (cd->detectors == NULL)  		goto fail; diff --git a/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c b/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c index 91b8dceeadb..5e48c5515b8 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c +++ b/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c @@ -218,7 +218,7 @@ static bool pulse_queue_enqueue(struct pri_detector *pde, u64 ts)  {  	struct pulse_elem *p = pool_get_pulse_elem();  	if (p == NULL) { -		p = kmalloc(sizeof(*p), GFP_KERNEL); +		p = kmalloc(sizeof(*p), GFP_ATOMIC);  		if (p == NULL) {  			DFS_POOL_STAT_INC(pulse_alloc_error);  			return false; @@ -299,7 +299,7 @@ static bool pseq_handler_create_sequences(struct pri_detector *pde,  		ps.deadline_ts = ps.first_ts + ps.dur;  		new_ps = pool_get_pseq_elem();  		if (new_ps == NULL) { -			new_ps = kmalloc(sizeof(*new_ps), GFP_KERNEL); +			new_ps = kmalloc(sizeof(*new_ps), GFP_ATOMIC);  			if (new_ps == NULL) {  				DFS_POOL_STAT_INC(pseq_alloc_error);  				return false; diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 96bfb18078f..d3b099d7898 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -22,6 +22,7 @@  #include <linux/firmware.h>  #include <linux/skbuff.h>  #include <linux/netdevice.h> +#include <linux/etherdevice.h>  #include <linux/leds.h>  #include <linux/slab.h>  #include <net/mac80211.h> diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 716058b6755..a47f5e05fc0 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -796,7 +796,7 @@ static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv)  	 * required version.  	 */  	if (priv->fw_version_major != MAJOR_VERSION_REQ || -	    priv->fw_version_minor != MINOR_VERSION_REQ) { +	    priv->fw_version_minor < MINOR_VERSION_REQ) {  		dev_err(priv->dev, "ath9k_htc: Please upgrade to FW version %d.%d\n",  			MAJOR_VERSION_REQ, MINOR_VERSION_REQ);  		return -EINVAL; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 3ad1fd05c5e..bd8251c1c74 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -1067,15 +1067,19 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,  	last_rssi = priv->rx.last_rssi; -	if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) -		rxbuf->rxstatus.rs_rssi = ATH_EP_RND(last_rssi, -						     ATH_RSSI_EP_MULTIPLIER); +	if (ieee80211_is_beacon(hdr->frame_control) && +	    !is_zero_ether_addr(common->curbssid) && +	    ether_addr_equal(hdr->addr3, common->curbssid)) { +		s8 rssi = rxbuf->rxstatus.rs_rssi; -	if (rxbuf->rxstatus.rs_rssi < 0) -		rxbuf->rxstatus.rs_rssi = 0; +		if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) +			rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); -	if (ieee80211_is_beacon(fc)) -		priv->ah->stats.avgbrssi = rxbuf->rxstatus.rs_rssi; +		if (rssi < 0) +			rssi = 0; + +		priv->ah->stats.avgbrssi = rssi; +	}  	rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp);  	rx_status->band = hw->conf.channel->band; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 2a2ae403e0e..07e25260c31 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1463,7 +1463,9 @@ static bool ath9k_hw_chip_reset(struct ath_hw *ah,  			reset_type = ATH9K_RESET_POWER_ON;  		else  			reset_type = ATH9K_RESET_COLD; -	} +	} else if (ah->chip_fullsleep || REG_READ(ah, AR_Q_TXE) || +		   (REG_READ(ah, AR_CR) & AR_CR_RXE)) +		reset_type = ATH9K_RESET_COLD;  	if (!ath9k_hw_set_reset_reg(ah, reset_type))  		return false; diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index ade3afb21f9..7fdac6c7b3e 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -28,21 +28,21 @@ void ath_tx_complete_poll_work(struct work_struct *work)  	int i;  	bool needreset = false; -	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) -		if (ATH_TXQ_SETUP(sc, i)) { -			txq = &sc->tx.txq[i]; -			ath_txq_lock(sc, txq); -			if (txq->axq_depth) { -				if (txq->axq_tx_inprogress) { -					needreset = true; -					ath_txq_unlock(sc, txq); -					break; -				} else { -					txq->axq_tx_inprogress = true; -				} +	for (i = 0; i < IEEE80211_NUM_ACS; i++) { +		txq = sc->tx.txq_map[i]; + +		ath_txq_lock(sc, txq); +		if (txq->axq_depth) { +			if (txq->axq_tx_inprogress) { +				needreset = true; +				ath_txq_unlock(sc, txq); +				break; +			} else { +				txq->axq_tx_inprogress = true;  			} -			ath_txq_unlock_complete(sc, txq);  		} +		ath_txq_unlock_complete(sc, txq); +	}  	if (needreset) {  		ath_dbg(ath9k_hw_common(sc->sc_ah), RESET, @@ -170,7 +170,8 @@ void ath_rx_poll(unsigned long data)  {  	struct ath_softc *sc = (struct ath_softc *)data; -	ieee80211_queue_work(sc->hw, &sc->hw_check_work); +	if (!test_bit(SC_OP_INVALID, &sc->sc_flags)) +		ieee80211_queue_work(sc->hw, &sc->hw_check_work);  }  /* diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 6e66f9c6782..988372d218a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -280,6 +280,10 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)  	if (r) {  		ath_err(common,  			"Unable to reset channel, reset status %d\n", r); + +		ath9k_hw_enable_interrupts(ah); +		ath9k_queue_reset(sc, RESET_TYPE_BB_HANG); +  		goto out;  	} diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index b42930f457c..52257221921 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -245,16 +245,7 @@ static struct pcmcia_driver atmel_driver = {  	.suspend	= atmel_suspend,  	.resume		= atmel_resume,  }; - -static int __init atmel_cs_init(void) -{ -        return pcmcia_register_driver(&atmel_driver); -} - -static void __exit atmel_cs_cleanup(void) -{ -        pcmcia_unregister_driver(&atmel_driver); -} +module_pcmcia_driver(atmel_driver);  /*      This program is free software; you can redistribute it and/or @@ -294,6 +285,3 @@ static void __exit atmel_cs_cleanup(void)      IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE      POSSIBILITY OF SUCH DAMAGE.  */ - -module_init(atmel_cs_init); -module_exit(atmel_cs_cleanup); diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 38bc5a7997f..122146943bf 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1487,8 +1487,12 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,  	const struct b43_dma_ops *ops;  	struct b43_dmaring *ring;  	struct b43_dmadesc_meta *meta; +	static const struct b43_txstatus fake; /* filled with 0 */ +	const struct b43_txstatus *txstat;  	int slot, firstused;  	bool frame_succeed; +	int skip; +	static u8 err_out1, err_out2;  	ring = parse_cookie(dev, status->cookie, &slot);  	if (unlikely(!ring)) @@ -1501,13 +1505,36 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,  	firstused = ring->current_slot - ring->used_slots + 1;  	if (firstused < 0)  		firstused = ring->nr_slots + firstused; + +	skip = 0;  	if (unlikely(slot != firstused)) {  		/* This possibly is a firmware bug and will result in -		 * malfunction, memory leaks and/or stall of DMA functionality. */ -		b43dbg(dev->wl, "Out of order TX status report on DMA ring %d. " -		       "Expected %d, but got %d\n", -		       ring->index, firstused, slot); -		return; +		 * malfunction, memory leaks and/or stall of DMA functionality. +		 */ +		if (slot == next_slot(ring, next_slot(ring, firstused))) { +			/* If a single header/data pair was missed, skip over +			 * the first two slots in an attempt to recover. +			 */ +			slot = firstused; +			skip = 2; +			if (!err_out1) { +				/* Report the error once. */ +				b43dbg(dev->wl, +				       "Skip on DMA ring %d slot %d.\n", +				       ring->index, slot); +				err_out1 = 1; +			} +		} else { +			/* More than a single header/data pair were missed. +			 * Report this error once. +			 */ +			if (!err_out2) +				b43dbg(dev->wl, +				       "Out of order TX status report on DMA ring %d. Expected %d, but got %d\n", +				       ring->index, firstused, slot); +			err_out2 = 1; +			return; +		}  	}  	ops = ring->ops; @@ -1522,11 +1549,13 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,  			       slot, firstused, ring->index);  			break;  		} +  		if (meta->skb) {  			struct b43_private_tx_info *priv_info = -				b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb)); +			     b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb)); -			unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1); +			unmap_descbuffer(ring, meta->dmaaddr, +					 meta->skb->len, 1);  			kfree(priv_info->bouncebuffer);  			priv_info->bouncebuffer = NULL;  		} else { @@ -1538,8 +1567,9 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,  			struct ieee80211_tx_info *info;  			if (unlikely(!meta->skb)) { -				/* This is a scatter-gather fragment of a frame, so -				 * the skb pointer must not be NULL. */ +				/* This is a scatter-gather fragment of a frame, +				 * so the skb pointer must not be NULL. +				 */  				b43dbg(dev->wl, "TX status unexpected NULL skb "  				       "at slot %d (first=%d) on ring %d\n",  				       slot, firstused, ring->index); @@ -1550,9 +1580,18 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,  			/*  			 * Call back to inform the ieee80211 subsystem about -			 * the status of the transmission. +			 * the status of the transmission. When skipping over +			 * a missed TX status report, use a status structure +			 * filled with zeros to indicate that the frame was not +			 * sent (frame_count 0) and not acknowledged  			 */ -			frame_succeed = b43_fill_txstatus_report(dev, info, status); +			if (unlikely(skip)) +				txstat = &fake; +			else +				txstat = status; + +			frame_succeed = b43_fill_txstatus_report(dev, info, +								 txstat);  #ifdef CONFIG_B43_DEBUG  			if (frame_succeed)  				ring->nr_succeed_tx_packets++; @@ -1580,12 +1619,14 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,  		/* Everything unmapped and free'd. So it's not used anymore. */  		ring->used_slots--; -		if (meta->is_last_fragment) { +		if (meta->is_last_fragment && !skip) {  			/* This is the last scatter-gather  			 * fragment of the frame. We are done. */  			break;  		}  		slot = next_slot(ring, slot); +		if (skip > 0) +			--skip;  	}  	if (ring->stopped) {  		B43_WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME); diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c index f2ea2ceec8a..55f2bd7f8f7 100644 --- a/drivers/net/wireless/b43/pcmcia.c +++ b/drivers/net/wireless/b43/pcmcia.c @@ -130,6 +130,10 @@ static struct pcmcia_driver b43_pcmcia_driver = {  	.resume		= b43_pcmcia_resume,  }; +/* + * These are not module init/exit functions! + * The module_pcmcia_driver() helper cannot be used here. + */  int b43_pcmcia_init(void)  {  	return pcmcia_register_driver(&b43_pcmcia_driver); diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 3c35382ee6c..b70f220bc4b 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1564,7 +1564,7 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)  	u16 clip_off[2] = { 0xFFFF, 0xFFFF };  	u8 vcm_final = 0; -	s8 offset[4]; +	s32 offset[4];  	s32 results[8][4] = { };  	s32 results_min[4] = { };  	s32 poll_results[4] = { }; @@ -1615,7 +1615,7 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)  		}  		for (i = 0; i < 4; i += 2) {  			s32 curr; -			s32 mind = 40; +			s32 mind = 0x100000;  			s32 minpoll = 249;  			u8 minvcm = 0;  			if (2 * core != i) @@ -1732,7 +1732,7 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)  	u8 regs_save_radio[2];  	u16 regs_save_phy[2]; -	s8 offset[4]; +	s32 offset[4];  	u8 core;  	u8 rail; @@ -1799,7 +1799,7 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)  	}  	for (i = 0; i < 4; i++) { -		s32 mind = 40; +		s32 mind = 0x100000;  		u8 minvcm = 0;  		s32 minpoll = 249;  		s32 curr; @@ -5165,7 +5165,8 @@ static void b43_nphy_pmu_spur_avoid(struct b43_wldev *dev, bool avoid)  #endif  #ifdef CONFIG_B43_SSB  	case B43_BUS_SSB: -		/* FIXME */ +		ssb_pmu_spuravoid_pllupdate(&dev->dev->sdev->bus->chipco, +					    avoid);  		break;  #endif  	} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 4469321c0eb..35fc68be158 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -3317,15 +3317,15 @@ static int _brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)  		goto err;  	} -	/* External image takes precedence if specified */  	if (brcmf_sdbrcm_download_code_file(bus)) {  		brcmf_err("dongle image file download failed\n");  		goto err;  	} -	/* External nvram takes precedence if specified */ -	if (brcmf_sdbrcm_download_nvram(bus)) +	if (brcmf_sdbrcm_download_nvram(bus)) {  		brcmf_err("dongle nvram file download failed\n"); +		goto err; +	}  	/* Take arm out of reset */  	if (brcmf_sdbrcm_download_state(bus, false)) { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 2af9c0f0798..78da3eff75e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -1891,8 +1891,10 @@ static s32  brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,  	      u8 key_idx, const u8 *mac_addr, struct key_params *params)  { +	struct brcmf_if *ifp = netdev_priv(ndev);  	struct brcmf_wsec_key key;  	s32 err = 0; +	u8 keybuf[8];  	memset(&key, 0, sizeof(key));  	key.index = (u32) key_idx; @@ -1916,8 +1918,9 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,  		brcmf_dbg(CONN, "Setting the key index %d\n", key.index);  		memcpy(key.data, params->key, key.len); -		if (params->cipher == WLAN_CIPHER_SUITE_TKIP) { -			u8 keybuf[8]; +		if ((ifp->vif->mode != WL_MODE_AP) && +		    (params->cipher == WLAN_CIPHER_SUITE_TKIP)) { +			brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");  			memcpy(keybuf, &key.data[24], sizeof(keybuf));  			memcpy(&key.data[24], &key.data[16], sizeof(keybuf));  			memcpy(&key.data[16], keybuf, sizeof(keybuf)); @@ -2013,7 +2016,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,  		break;  	case WLAN_CIPHER_SUITE_TKIP:  		if (ifp->vif->mode != WL_MODE_AP) { -			brcmf_dbg(CONN, "Swapping key\n"); +			brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");  			memcpy(keybuf, &key.data[24], sizeof(keybuf));  			memcpy(&key.data[24], &key.data[16], sizeof(keybuf));  			memcpy(&key.data[16], keybuf, sizeof(keybuf)); @@ -2118,8 +2121,7 @@ brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,  		err = -EAGAIN;  		goto done;  	} -	switch (wsec & ~SES_OW_ENABLED) { -	case WEP_ENABLED: +	if (wsec & WEP_ENABLED) {  		sec = &profile->sec;  		if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {  			params.cipher = WLAN_CIPHER_SUITE_WEP40; @@ -2128,16 +2130,13 @@ brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,  			params.cipher = WLAN_CIPHER_SUITE_WEP104;  			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");  		} -		break; -	case TKIP_ENABLED: +	} else if (wsec & TKIP_ENABLED) {  		params.cipher = WLAN_CIPHER_SUITE_TKIP;  		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n"); -		break; -	case AES_ENABLED: +	} else if (wsec & AES_ENABLED) {  		params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;  		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n"); -		break; -	default: +	} else  {  		brcmf_err("Invalid algo (0x%x)\n", wsec);  		err = -EINVAL;  		goto done; @@ -3824,8 +3823,9 @@ exit:  static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)  {  	struct brcmf_if *ifp = netdev_priv(ndev); -	s32 err = -EPERM; +	s32 err;  	struct brcmf_fil_bss_enable_le bss_enable; +	struct brcmf_join_params join_params;  	brcmf_dbg(TRACE, "Enter\n"); @@ -3833,16 +3833,21 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)  		/* Due to most likely deauths outstanding we sleep */  		/* first to make sure they get processed by fw. */  		msleep(400); -		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0); -		if (err < 0) { -			brcmf_err("setting AP mode failed %d\n", err); -			goto exit; -		} + +		memset(&join_params, 0, sizeof(join_params)); +		err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, +					     &join_params, sizeof(join_params)); +		if (err < 0) +			brcmf_err("SET SSID error (%d)\n", err);  		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0); -		if (err < 0) { +		if (err < 0)  			brcmf_err("BRCMF_C_UP error %d\n", err); -			goto exit; -		} +		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0); +		if (err < 0) +			brcmf_err("setting AP mode failed %d\n", err); +		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0); +		if (err < 0) +			brcmf_err("setting INFRA mode failed %d\n", err);  	} else {  		bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);  		bss_enable.enable = cpu_to_le32(0); @@ -3855,7 +3860,6 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)  	set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);  	clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); -exit:  	return err;  } @@ -4124,10 +4128,6 @@ static const struct ieee80211_iface_limit brcmf_iface_limits[] = {  	},  	{  		.max = 1, -		.types = BIT(NL80211_IFTYPE_P2P_DEVICE) -	}, -	{ -		.max = 1,  		.types = BIT(NL80211_IFTYPE_P2P_CLIENT) |  			 BIT(NL80211_IFTYPE_P2P_GO)  	}, @@ -4183,8 +4183,7 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)  				 BIT(NL80211_IFTYPE_ADHOC) |  				 BIT(NL80211_IFTYPE_AP) |  				 BIT(NL80211_IFTYPE_P2P_CLIENT) | -				 BIT(NL80211_IFTYPE_P2P_GO) | -				 BIT(NL80211_IFTYPE_P2P_DEVICE); +				 BIT(NL80211_IFTYPE_P2P_GO);  	wiphy->iface_combinations = brcmf_iface_combos;  	wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);  	wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index c6451c61407..e2340b231aa 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -274,6 +274,130 @@ static void brcms_set_basic_rate(struct brcm_rateset *rs, u16 rate, bool is_br)  	}  } +/** + * This function frees the WL per-device resources. + * + * This function frees resources owned by the WL device pointed to + * by the wl parameter. + * + * precondition: can both be called locked and unlocked + * + */ +static void brcms_free(struct brcms_info *wl) +{ +	struct brcms_timer *t, *next; + +	/* free ucode data */ +	if (wl->fw.fw_cnt) +		brcms_ucode_data_free(&wl->ucode); +	if (wl->irq) +		free_irq(wl->irq, wl); + +	/* kill dpc */ +	tasklet_kill(&wl->tasklet); + +	if (wl->pub) { +		brcms_debugfs_detach(wl->pub); +		brcms_c_module_unregister(wl->pub, "linux", wl); +	} + +	/* free common resources */ +	if (wl->wlc) { +		brcms_c_detach(wl->wlc); +		wl->wlc = NULL; +		wl->pub = NULL; +	} + +	/* virtual interface deletion is deferred so we cannot spinwait */ + +	/* wait for all pending callbacks to complete */ +	while (atomic_read(&wl->callbacks) > 0) +		schedule(); + +	/* free timers */ +	for (t = wl->timers; t; t = next) { +		next = t->next; +#ifdef DEBUG +		kfree(t->name); +#endif +		kfree(t); +	} +} + +/* +* called from both kernel as from this kernel module (error flow on attach) +* precondition: perimeter lock is not acquired. +*/ +static void brcms_remove(struct bcma_device *pdev) +{ +	struct ieee80211_hw *hw = bcma_get_drvdata(pdev); +	struct brcms_info *wl = hw->priv; + +	if (wl->wlc) { +		wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false); +		wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); +		ieee80211_unregister_hw(hw); +	} + +	brcms_free(wl); + +	bcma_set_drvdata(pdev, NULL); +	ieee80211_free_hw(hw); +} + +/* + * Precondition: Since this function is called in brcms_pci_probe() context, + * no locking is required. + */ +static void brcms_release_fw(struct brcms_info *wl) +{ +	int i; +	for (i = 0; i < MAX_FW_IMAGES; i++) { +		release_firmware(wl->fw.fw_bin[i]); +		release_firmware(wl->fw.fw_hdr[i]); +	} +} + +/* + * Precondition: Since this function is called in brcms_pci_probe() context, + * no locking is required. + */ +static int brcms_request_fw(struct brcms_info *wl, struct bcma_device *pdev) +{ +	int status; +	struct device *device = &pdev->dev; +	char fw_name[100]; +	int i; + +	memset(&wl->fw, 0, sizeof(struct brcms_firmware)); +	for (i = 0; i < MAX_FW_IMAGES; i++) { +		if (brcms_firmwares[i] == NULL) +			break; +		sprintf(fw_name, "%s-%d.fw", brcms_firmwares[i], +			UCODE_LOADER_API_VER); +		status = request_firmware(&wl->fw.fw_bin[i], fw_name, device); +		if (status) { +			wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n", +				  KBUILD_MODNAME, fw_name); +			return status; +		} +		sprintf(fw_name, "%s_hdr-%d.fw", brcms_firmwares[i], +			UCODE_LOADER_API_VER); +		status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device); +		if (status) { +			wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n", +				  KBUILD_MODNAME, fw_name); +			return status; +		} +		wl->fw.hdr_num_entries[i] = +		    wl->fw.fw_hdr[i]->size / (sizeof(struct firmware_hdr)); +	} +	wl->fw.fw_cnt = i; +	status = brcms_ucode_data_init(wl, &wl->ucode); +	brcms_release_fw(wl); +	return status; +} +  static void brcms_ops_tx(struct ieee80211_hw *hw,  			 struct ieee80211_tx_control *control,  			 struct sk_buff *skb) @@ -306,6 +430,14 @@ static int brcms_ops_start(struct ieee80211_hw *hw)  	if (!blocked)  		wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); +	if (!wl->ucode.bcm43xx_bomminor) { +		err = brcms_request_fw(wl, wl->wlc->hw->d11core); +		if (err) { +			brcms_remove(wl->wlc->hw->d11core); +			return -ENOENT; +		} +	} +  	spin_lock_bh(&wl->lock);  	/* avoid acknowledging frames before a non-monitor device is added */  	wl->mute_tx = true; @@ -793,128 +925,6 @@ void brcms_dpc(unsigned long data)  	wake_up(&wl->tx_flush_wq);  } -/* - * Precondition: Since this function is called in brcms_pci_probe() context, - * no locking is required. - */ -static int brcms_request_fw(struct brcms_info *wl, struct bcma_device *pdev) -{ -	int status; -	struct device *device = &pdev->dev; -	char fw_name[100]; -	int i; - -	memset(&wl->fw, 0, sizeof(struct brcms_firmware)); -	for (i = 0; i < MAX_FW_IMAGES; i++) { -		if (brcms_firmwares[i] == NULL) -			break; -		sprintf(fw_name, "%s-%d.fw", brcms_firmwares[i], -			UCODE_LOADER_API_VER); -		status = request_firmware(&wl->fw.fw_bin[i], fw_name, device); -		if (status) { -			wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n", -				  KBUILD_MODNAME, fw_name); -			return status; -		} -		sprintf(fw_name, "%s_hdr-%d.fw", brcms_firmwares[i], -			UCODE_LOADER_API_VER); -		status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device); -		if (status) { -			wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n", -				  KBUILD_MODNAME, fw_name); -			return status; -		} -		wl->fw.hdr_num_entries[i] = -		    wl->fw.fw_hdr[i]->size / (sizeof(struct firmware_hdr)); -	} -	wl->fw.fw_cnt = i; -	return brcms_ucode_data_init(wl, &wl->ucode); -} - -/* - * Precondition: Since this function is called in brcms_pci_probe() context, - * no locking is required. - */ -static void brcms_release_fw(struct brcms_info *wl) -{ -	int i; -	for (i = 0; i < MAX_FW_IMAGES; i++) { -		release_firmware(wl->fw.fw_bin[i]); -		release_firmware(wl->fw.fw_hdr[i]); -	} -} - -/** - * This function frees the WL per-device resources. - * - * This function frees resources owned by the WL device pointed to - * by the wl parameter. - * - * precondition: can both be called locked and unlocked - * - */ -static void brcms_free(struct brcms_info *wl) -{ -	struct brcms_timer *t, *next; - -	/* free ucode data */ -	if (wl->fw.fw_cnt) -		brcms_ucode_data_free(&wl->ucode); -	if (wl->irq) -		free_irq(wl->irq, wl); - -	/* kill dpc */ -	tasklet_kill(&wl->tasklet); - -	if (wl->pub) { -		brcms_debugfs_detach(wl->pub); -		brcms_c_module_unregister(wl->pub, "linux", wl); -	} - -	/* free common resources */ -	if (wl->wlc) { -		brcms_c_detach(wl->wlc); -		wl->wlc = NULL; -		wl->pub = NULL; -	} - -	/* virtual interface deletion is deferred so we cannot spinwait */ - -	/* wait for all pending callbacks to complete */ -	while (atomic_read(&wl->callbacks) > 0) -		schedule(); - -	/* free timers */ -	for (t = wl->timers; t; t = next) { -		next = t->next; -#ifdef DEBUG -		kfree(t->name); -#endif -		kfree(t); -	} -} - -/* -* called from both kernel as from this kernel module (error flow on attach) -* precondition: perimeter lock is not acquired. -*/ -static void brcms_remove(struct bcma_device *pdev) -{ -	struct ieee80211_hw *hw = bcma_get_drvdata(pdev); -	struct brcms_info *wl = hw->priv; - -	if (wl->wlc) { -		wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false); -		wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); -		ieee80211_unregister_hw(hw); -	} - -	brcms_free(wl); - -	bcma_set_drvdata(pdev, NULL); -	ieee80211_free_hw(hw); -} -  static irqreturn_t brcms_isr(int irq, void *dev_id)  {  	struct brcms_info *wl; @@ -1047,18 +1057,8 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)  	spin_lock_init(&wl->lock);  	spin_lock_init(&wl->isr_lock); -	/* prepare ucode */ -	if (brcms_request_fw(wl, pdev) < 0) { -		wiphy_err(wl->wiphy, "%s: Failed to find firmware usually in " -			  "%s\n", KBUILD_MODNAME, "/lib/firmware/brcm"); -		brcms_release_fw(wl); -		brcms_remove(pdev); -		return NULL; -	} -  	/* common load-time initialization */  	wl->wlc = brcms_c_attach((void *)wl, pdev, unit, false, &err); -	brcms_release_fw(wl);  	if (!wl->wlc) {  		wiphy_err(wl->wiphy, "%s: attach() failed with code %d\n",  			  KBUILD_MODNAME, err); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c index 21a82423247..18d37645e2c 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c @@ -1137,9 +1137,8 @@ wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi,  	gain0_15 = ((biq1 & 0xf) << 12) |  		   ((tia & 0xf) << 8) |  		   ((lna2 & 0x3) << 6) | -		   ((lna2 & 0x3) << 4) | -		   ((lna1 & 0x3) << 2) | -		   ((lna1 & 0x3) << 0); +		   ((lna2 & +		     0x3) << 4) | ((lna1 & 0x3) << 2) | ((lna1 & 0x3) << 0);  	mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);  	mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0); @@ -1157,8 +1156,6 @@ wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi,  	}  	mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0); -	mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11); -	mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3);  } @@ -1331,43 +1328,6 @@ static u32 wlc_lcnphy_measure_digital_power(struct brcms_phy *pi, u16 nsamples)  	return (iq_est.i_pwr + iq_est.q_pwr) / nsamples;  } -static bool wlc_lcnphy_rx_iq_cal_gain(struct brcms_phy *pi, u16 biq1_gain, -				      u16 tia_gain, u16 lna2_gain) -{ -	u32 i_thresh_l, q_thresh_l; -	u32 i_thresh_h, q_thresh_h; -	struct lcnphy_iq_est iq_est_h, iq_est_l; - -	wlc_lcnphy_set_rx_gain_by_distribution(pi, 0, 0, 0, biq1_gain, tia_gain, -					       lna2_gain, 0); - -	wlc_lcnphy_rx_gain_override_enable(pi, true); -	wlc_lcnphy_start_tx_tone(pi, 2000, (40 >> 1), 0); -	udelay(500); -	write_radio_reg(pi, RADIO_2064_REG112, 0); -	if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_l)) -		return false; - -	wlc_lcnphy_start_tx_tone(pi, 2000, 40, 0); -	udelay(500); -	write_radio_reg(pi, RADIO_2064_REG112, 0); -	if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_h)) -		return false; - -	i_thresh_l = (iq_est_l.i_pwr << 1); -	i_thresh_h = (iq_est_l.i_pwr << 2) + iq_est_l.i_pwr; - -	q_thresh_l = (iq_est_l.q_pwr << 1); -	q_thresh_h = (iq_est_l.q_pwr << 2) + iq_est_l.q_pwr; -	if ((iq_est_h.i_pwr > i_thresh_l) && -	    (iq_est_h.i_pwr < i_thresh_h) && -	    (iq_est_h.q_pwr > q_thresh_l) && -	    (iq_est_h.q_pwr < q_thresh_h)) -		return true; - -	return false; -} -  static bool  wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,  		     const struct lcnphy_rx_iqcomp *iqcomp, @@ -1382,8 +1342,8 @@ wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,  	    RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old,  	    rfoverride3_old, rfoverride3val_old, rfoverride4_old,  	    rfoverride4val_old, afectrlovr_old, afectrlovrval_old; -	int tia_gain, lna2_gain, biq1_gain; -	bool set_gain; +	int tia_gain; +	u32 received_power, rx_pwr_threshold;  	u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;  	u16 values_to_save[11];  	s16 *ptr; @@ -1408,134 +1368,126 @@ wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,  		goto cal_done;  	} -	WARN_ON(module != 1); -	tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); -	wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); - -	for (i = 0; i < 11; i++) -		values_to_save[i] = -			read_radio_reg(pi, rxiq_cal_rf_reg[i]); -	Core1TxControl_old = read_phy_reg(pi, 0x631); +	if (module == 1) { -	or_phy_reg(pi, 0x631, 0x0015); - -	RFOverride0_old = read_phy_reg(pi, 0x44c); -	RFOverrideVal0_old = read_phy_reg(pi, 0x44d); -	rfoverride2_old = read_phy_reg(pi, 0x4b0); -	rfoverride2val_old = read_phy_reg(pi, 0x4b1); -	rfoverride3_old = read_phy_reg(pi, 0x4f9); -	rfoverride3val_old = read_phy_reg(pi, 0x4fa); -	rfoverride4_old = read_phy_reg(pi, 0x938); -	rfoverride4val_old = read_phy_reg(pi, 0x939); -	afectrlovr_old = read_phy_reg(pi, 0x43b); -	afectrlovrval_old = read_phy_reg(pi, 0x43c); -	old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); -	old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db); +		tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); +		wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); -	tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi); -	if (tx_gain_override_old) { -		wlc_lcnphy_get_tx_gain(pi, &old_gains); -		tx_gain_index_old = pi_lcn->lcnphy_current_index; -	} +		for (i = 0; i < 11; i++) +			values_to_save[i] = +				read_radio_reg(pi, rxiq_cal_rf_reg[i]); +		Core1TxControl_old = read_phy_reg(pi, 0x631); -	wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx); +		or_phy_reg(pi, 0x631, 0x0015); -	mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0); -	mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0); +		RFOverride0_old = read_phy_reg(pi, 0x44c); +		RFOverrideVal0_old = read_phy_reg(pi, 0x44d); +		rfoverride2_old = read_phy_reg(pi, 0x4b0); +		rfoverride2val_old = read_phy_reg(pi, 0x4b1); +		rfoverride3_old = read_phy_reg(pi, 0x4f9); +		rfoverride3val_old = read_phy_reg(pi, 0x4fa); +		rfoverride4_old = read_phy_reg(pi, 0x938); +		rfoverride4val_old = read_phy_reg(pi, 0x939); +		afectrlovr_old = read_phy_reg(pi, 0x43b); +		afectrlovrval_old = read_phy_reg(pi, 0x43c); +		old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); +		old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db); -	mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1); -	mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1); +		tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi); +		if (tx_gain_override_old) { +			wlc_lcnphy_get_tx_gain(pi, &old_gains); +			tx_gain_index_old = pi_lcn->lcnphy_current_index; +		} -	write_radio_reg(pi, RADIO_2064_REG116, 0x06); -	write_radio_reg(pi, RADIO_2064_REG12C, 0x07); -	write_radio_reg(pi, RADIO_2064_REG06A, 0xd3); -	write_radio_reg(pi, RADIO_2064_REG098, 0x03); -	write_radio_reg(pi, RADIO_2064_REG00B, 0x7); -	mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4); -	write_radio_reg(pi, RADIO_2064_REG01D, 0x01); -	write_radio_reg(pi, RADIO_2064_REG114, 0x01); -	write_radio_reg(pi, RADIO_2064_REG02E, 0x10); -	write_radio_reg(pi, RADIO_2064_REG12A, 0x08); +		wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx); -	mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0); -	mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0); -	mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1); -	mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1); -	mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2); -	mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2); -	mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3); -	mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3); -	mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5); -	mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5); +		mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0); +		mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0); -	mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0); -	mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0); +		mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1); +		mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1); -	write_phy_reg(pi, 0x6da, 0xffff); -	or_phy_reg(pi, 0x6db, 0x3); +		write_radio_reg(pi, RADIO_2064_REG116, 0x06); +		write_radio_reg(pi, RADIO_2064_REG12C, 0x07); +		write_radio_reg(pi, RADIO_2064_REG06A, 0xd3); +		write_radio_reg(pi, RADIO_2064_REG098, 0x03); +		write_radio_reg(pi, RADIO_2064_REG00B, 0x7); +		mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4); +		write_radio_reg(pi, RADIO_2064_REG01D, 0x01); +		write_radio_reg(pi, RADIO_2064_REG114, 0x01); +		write_radio_reg(pi, RADIO_2064_REG02E, 0x10); +		write_radio_reg(pi, RADIO_2064_REG12A, 0x08); -	wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch); -	set_gain = false; +		mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0); +		mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0); +		mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1); +		mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1); +		mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2); +		mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2); +		mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3); +		mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3); +		mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5); +		mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5); -	lna2_gain = 3; -	while ((lna2_gain >= 0) && !set_gain) { -		tia_gain = 4; +		mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0); +		mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0); -		while ((tia_gain >= 0) && !set_gain) { -			biq1_gain = 6; +		wlc_lcnphy_start_tx_tone(pi, 2000, 120, 0); +		write_phy_reg(pi, 0x6da, 0xffff); +		or_phy_reg(pi, 0x6db, 0x3); +		wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch); +		wlc_lcnphy_rx_gain_override_enable(pi, true); -			while ((biq1_gain >= 0) && !set_gain) { -				set_gain = wlc_lcnphy_rx_iq_cal_gain(pi, -								     (u16) -								     biq1_gain, -								     (u16) -								     tia_gain, -								     (u16) -								     lna2_gain); -				biq1_gain -= 1; -			} +		tia_gain = 8; +		rx_pwr_threshold = 950; +		while (tia_gain > 0) {  			tia_gain -= 1; -		} -		lna2_gain -= 1; -	} +			wlc_lcnphy_set_rx_gain_by_distribution(pi, +							       0, 0, 2, 2, +							       (u16) +							       tia_gain, 1, 0); +			udelay(500); -	if (set_gain) -		result = wlc_lcnphy_calc_rx_iq_comp(pi, 1024); -	else -		result = false; +			received_power = +				wlc_lcnphy_measure_digital_power(pi, 2000); +			if (received_power < rx_pwr_threshold) +				break; +		} +		result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff); -	wlc_lcnphy_stop_tx_tone(pi); +		wlc_lcnphy_stop_tx_tone(pi); -	write_phy_reg(pi, 0x631, Core1TxControl_old); +		write_phy_reg(pi, 0x631, Core1TxControl_old); -	write_phy_reg(pi, 0x44c, RFOverrideVal0_old); -	write_phy_reg(pi, 0x44d, RFOverrideVal0_old); -	write_phy_reg(pi, 0x4b0, rfoverride2_old); -	write_phy_reg(pi, 0x4b1, rfoverride2val_old); -	write_phy_reg(pi, 0x4f9, rfoverride3_old); -	write_phy_reg(pi, 0x4fa, rfoverride3val_old); -	write_phy_reg(pi, 0x938, rfoverride4_old); -	write_phy_reg(pi, 0x939, rfoverride4val_old); -	write_phy_reg(pi, 0x43b, afectrlovr_old); -	write_phy_reg(pi, 0x43c, afectrlovrval_old); -	write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl); -	write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl); +		write_phy_reg(pi, 0x44c, RFOverrideVal0_old); +		write_phy_reg(pi, 0x44d, RFOverrideVal0_old); +		write_phy_reg(pi, 0x4b0, rfoverride2_old); +		write_phy_reg(pi, 0x4b1, rfoverride2val_old); +		write_phy_reg(pi, 0x4f9, rfoverride3_old); +		write_phy_reg(pi, 0x4fa, rfoverride3val_old); +		write_phy_reg(pi, 0x938, rfoverride4_old); +		write_phy_reg(pi, 0x939, rfoverride4val_old); +		write_phy_reg(pi, 0x43b, afectrlovr_old); +		write_phy_reg(pi, 0x43c, afectrlovrval_old); +		write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl); +		write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl); -	wlc_lcnphy_clear_trsw_override(pi); +		wlc_lcnphy_clear_trsw_override(pi); -	mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2); +		mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2); -	for (i = 0; i < 11; i++) -		write_radio_reg(pi, rxiq_cal_rf_reg[i], -				values_to_save[i]); +		for (i = 0; i < 11; i++) +			write_radio_reg(pi, rxiq_cal_rf_reg[i], +					values_to_save[i]); -	if (tx_gain_override_old) -		wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old); -	else -		wlc_lcnphy_disable_tx_gain_override(pi); +		if (tx_gain_override_old) +			wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old); +		else +			wlc_lcnphy_disable_tx_gain_override(pi); -	wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl); -	wlc_lcnphy_rx_gain_override_enable(pi, false); +		wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl); +		wlc_lcnphy_rx_gain_override_enable(pi, false); +	}  cal_done:  	kfree(ptr); @@ -1829,17 +1781,6 @@ wlc_lcnphy_radio_2064_channel_tune_4313(struct brcms_phy *pi, u8 channel)  		write_radio_reg(pi, RADIO_2064_REG038, 3);  		write_radio_reg(pi, RADIO_2064_REG091, 7);  	} - -	if (!(pi->sh->boardflags & BFL_FEM)) { -		u8 reg038[14] = {0xd, 0xe, 0xd, 0xd, 0xd, 0xc, -			0xa, 0xb, 0xb, 0x3, 0x3, 0x2, 0x0, 0x0}; - -		write_radio_reg(pi, RADIO_2064_REG02A, 0xf); -		write_radio_reg(pi, RADIO_2064_REG091, 0x3); -		write_radio_reg(pi, RADIO_2064_REG038, 0x3); - -		write_radio_reg(pi, RADIO_2064_REG038, reg038[channel - 1]); -	}  }  static int @@ -2034,16 +1975,6 @@ wlc_lcnphy_set_tssi_mux(struct brcms_phy *pi, enum lcnphy_tssi_mode pos)  		} else {  			mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1);  			mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8); -			mod_radio_reg(pi, RADIO_2064_REG028, 0x1, 0x0); -			mod_radio_reg(pi, RADIO_2064_REG11A, 0x4, 1<<2); -			mod_radio_reg(pi, RADIO_2064_REG036, 0x10, 0x0); -			mod_radio_reg(pi, RADIO_2064_REG11A, 0x10, 1<<4); -			mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0); -			mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x77); -			mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0xe<<1); -			mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1<<7); -			mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 1<<1); -			mod_radio_reg(pi, RADIO_2064_REG029, 0xf0, 0<<4);  		}  	} else {  		mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2); @@ -2130,14 +2061,12 @@ static void wlc_lcnphy_pwrctrl_rssiparams(struct brcms_phy *pi)  		    (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));  	mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5)); -	mod_radio_reg(pi, RADIO_2064_REG07C, (1 << 0), (1 << 0));  }  static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)  {  	struct phytbl_info tab;  	u32 rfseq, ind; -	u8 tssi_sel;  	tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;  	tab.tbl_width = 32; @@ -2159,13 +2088,7 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)  	mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4); -	if (pi->sh->boardflags & BFL_FEM) { -		tssi_sel = 0x1; -		wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT); -	} else { -		tssi_sel = 0xe; -		wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_POST_PA); -	} +	wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT);  	mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);  	mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15); @@ -2201,10 +2124,9 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)  	mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0);  	if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { -		mod_radio_reg(pi, RADIO_2064_REG028, 0xf, tssi_sel); +		mod_radio_reg(pi, RADIO_2064_REG028, 0xf, 0xe);  		mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);  	} else { -		mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, tssi_sel << 1);  		mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);  		mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3);  	} @@ -2251,10 +2173,6 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)  	mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8); -	mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x0); -	mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0); -	mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8); -  	wlc_lcnphy_pwrctrl_rssiparams(pi);  } @@ -2873,8 +2791,6 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)  		read_radio_reg(pi, RADIO_2064_REG007) & 1;  	u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10;  	u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4; -	u8 SAVE_bbmult = wlc_lcnphy_get_bbmult(pi); -  	idleTssi = read_phy_reg(pi, 0x4ab);  	suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &  			 MCTL_EN_MAC)); @@ -2892,12 +2808,6 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)  	mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4);  	mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2);  	wlc_lcnphy_tssi_setup(pi); - -	mod_phy_reg(pi, 0x4d7, (0x1 << 0), (1 << 0)); -	mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1 << 6)); - -	wlc_lcnphy_set_bbmult(pi, 0x0); -  	wlc_phy_do_dummy_tx(pi, true, OFF);  	idleTssi = ((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))  		    >> 0); @@ -2919,7 +2829,6 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)  	mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12); -	wlc_lcnphy_set_bbmult(pi, SAVE_bbmult);  	wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old);  	wlc_lcnphy_set_tx_gain(pi, &old_gains);  	wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl); @@ -3133,11 +3042,6 @@ static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi)  			wlc_lcnphy_write_table(pi, &tab);  			tab.tbl_offset++;  		} -		mod_phy_reg(pi, 0x4d0, (0x1 << 0), (0) << 0); -		mod_phy_reg(pi, 0x4d3, (0xff << 0), (0) << 0); -		mod_phy_reg(pi, 0x4d3, (0xff << 8), (0) << 8); -		mod_phy_reg(pi, 0x4d0, (0x1 << 4), (0) << 4); -		mod_phy_reg(pi, 0x4d0, (0x1 << 2), (0) << 2);  		mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7); @@ -3939,6 +3843,7 @@ static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)  	target_gains.pad_gain = 21;  	target_gains.dac_gain = 0;  	wlc_lcnphy_set_tx_gain(pi, &target_gains); +	wlc_lcnphy_set_tx_pwr_by_index(pi, 16);  	if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) { @@ -3949,7 +3854,6 @@ static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)  					lcnphy_recal ? LCNPHY_CAL_RECAL :  					LCNPHY_CAL_FULL), false);  	} else { -		wlc_lcnphy_set_tx_pwr_by_index(pi, 16);  		wlc_lcnphy_tx_iqlo_soft_cal_full(pi);  	} @@ -4374,22 +4278,17 @@ wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi,  	if (CHSPEC_IS5G(pi->radio_chanspec))  		pa_gain = 0x70;  	else -		pa_gain = 0x60; +		pa_gain = 0x70;  	if (pi->sh->boardflags & BFL_FEM)  		pa_gain = 0x10; -  	tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;  	tab.tbl_width = 32;  	tab.tbl_len = 1;  	tab.tbl_ptr = &val;  	for (j = 0; j < 128; j++) { -		if (pi->sh->boardflags & BFL_FEM) -			gm_gain = gain_table[j].gm; -		else -			gm_gain = 15; - +		gm_gain = gain_table[j].gm;  		val = (((u32) pa_gain << 24) |  		       (gain_table[j].pad << 16) |  		       (gain_table[j].pga << 8) | gm_gain); @@ -4600,10 +4499,7 @@ static void wlc_radio_2064_init(struct brcms_phy *pi)  	write_phy_reg(pi, 0x4ea, 0x4688); -	if (pi->sh->boardflags & BFL_FEM) -		mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0); -	else -		mod_phy_reg(pi, 0x4eb, (0x7 << 0), 3 << 0); +	mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);  	mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6); @@ -4614,13 +4510,6 @@ static void wlc_radio_2064_init(struct brcms_phy *pi)  	wlc_lcnphy_rcal(pi);  	wlc_lcnphy_rc_cal(pi); - -	if (!(pi->sh->boardflags & BFL_FEM)) { -		write_radio_reg(pi, RADIO_2064_REG032, 0x6f); -		write_radio_reg(pi, RADIO_2064_REG033, 0x19); -		write_radio_reg(pi, RADIO_2064_REG039, 0xe); -	} -  }  static void wlc_lcnphy_radio_init(struct brcms_phy *pi) @@ -4650,20 +4539,22 @@ static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)  		wlc_lcnphy_write_table(pi, &tab);  	} -	if (!(pi->sh->boardflags & BFL_FEM)) { -		tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; -		tab.tbl_width = 16; -		tab.tbl_ptr = &val; -		tab.tbl_len = 1; +	tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; +	tab.tbl_width = 16; +	tab.tbl_ptr = &val; +	tab.tbl_len = 1; -		val = 150; -		tab.tbl_offset = 0; -		wlc_lcnphy_write_table(pi, &tab); +	val = 114; +	tab.tbl_offset = 0; +	wlc_lcnphy_write_table(pi, &tab); -		val = 220; -		tab.tbl_offset = 1; -		wlc_lcnphy_write_table(pi, &tab); -	} +	val = 130; +	tab.tbl_offset = 1; +	wlc_lcnphy_write_table(pi, &tab); + +	val = 6; +	tab.tbl_offset = 8; +	wlc_lcnphy_write_table(pi, &tab);  	if (CHSPEC_IS2G(pi->radio_chanspec)) {  		if (pi->sh->boardflags & BFL_FEM) @@ -5055,7 +4946,6 @@ void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec)  		wlc_lcnphy_load_tx_iir_filter(pi, true, 3);  	mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3); -	wlc_lcnphy_tssi_setup(pi);  }  void wlc_phy_detach_lcnphy(struct brcms_phy *pi) @@ -5094,7 +4984,8 @@ bool wlc_phy_attach_lcnphy(struct brcms_phy *pi)  	if (!wlc_phy_txpwr_srom_read_lcnphy(pi))  		return false; -	if (LCNREV_IS(pi->pubpi.phy_rev, 1)) { +	if ((pi->sh->boardflags & BFL_FEM) && +	    (LCNREV_IS(pi->pubpi.phy_rev, 1))) {  		if (pi_lcn->lcnphy_tempsense_option == 3) {  			pi->hwpwrctrl = true;  			pi->hwpwrctrl_capable = true; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c index b7e95acc208..622c01ca72c 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c @@ -1992,70 +1992,70 @@ static const u16 dot11lcn_sw_ctrl_tbl_4313_epa_rev0[] = {  };  static const u16 dot11lcn_sw_ctrl_tbl_4313_rev0[] = { -	0x0009,  	0x000a, -	0x0005, -	0x0006,  	0x0009, -	0x000a, -	0x0005,  	0x0006, -	0x0009, -	0x000a,  	0x0005, -	0x0006, -	0x0009,  	0x000a, -	0x0005, -	0x0006,  	0x0009, -	0x000a, -	0x0005,  	0x0006, -	0x0009, -	0x000a,  	0x0005, -	0x0006, -	0x0009,  	0x000a, -	0x0005, -	0x0006,  	0x0009, -	0x000a, -	0x0005,  	0x0006, -	0x0009, -	0x000a,  	0x0005, -	0x0006, -	0x0009,  	0x000a, -	0x0005, -	0x0006,  	0x0009, -	0x000a, -	0x0005,  	0x0006, -	0x0009, -	0x000a,  	0x0005, -	0x0006, +	0x000a,  	0x0009, +	0x0006, +	0x0005,  	0x000a, +	0x0009, +	0x0006,  	0x0005, +	0x000a, +	0x0009,  	0x0006, +	0x0005, +	0x000a,  	0x0009, +	0x0006, +	0x0005,  	0x000a, +	0x0009, +	0x0006,  	0x0005, +	0x000a, +	0x0009,  	0x0006, +	0x0005, +	0x000a,  	0x0009, +	0x0006, +	0x0005,  	0x000a, +	0x0009, +	0x0006,  	0x0005, +	0x000a, +	0x0009,  	0x0006, +	0x0005, +	0x000a,  	0x0009, +	0x0006, +	0x0005,  	0x000a, +	0x0009, +	0x0006,  	0x0005, +	0x000a, +	0x0009,  	0x0006, +	0x0005,  };  static const u16 dot11lcn_sw_ctrl_tbl_rev0[] = { diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 89e9d3a78c3..56cd01ca8ad 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -709,17 +709,4 @@ static struct pcmcia_driver hostap_driver = {  	.suspend	= hostap_cs_suspend,  	.resume		= hostap_cs_resume,  }; - -static int __init init_prism2_pccard(void) -{ -	return pcmcia_register_driver(&hostap_driver); -} - -static void __exit exit_prism2_pccard(void) -{ -	pcmcia_unregister_driver(&hostap_driver); -} - - -module_init(init_prism2_pccard); -module_exit(exit_prism2_pccard); +module_pcmcia_driver(hostap_driver); diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index 3630a41df50..c353b5f19c8 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -475,6 +475,7 @@ il3945_tx_skb(struct il_priv *il,  	dma_addr_t txcmd_phys;  	int txq_id = skb_get_queue_mapping(skb);  	u16 len, idx, hdr_len; +	u16 firstlen, secondlen;  	u8 id;  	u8 unicast;  	u8 sta_id; @@ -589,21 +590,22 @@ il3945_tx_skb(struct il_priv *il,  	len =  	    sizeof(struct il3945_tx_cmd) + sizeof(struct il_cmd_header) +  	    hdr_len; -	len = (len + 3) & ~3; +	firstlen = (len + 3) & ~3;  	/* Physical address of this Tx command's header (not MAC header!),  	 * within command buffer array. */  	txcmd_phys = -	    pci_map_single(il->pci_dev, &out_cmd->hdr, len, PCI_DMA_TODEVICE); +	    pci_map_single(il->pci_dev, &out_cmd->hdr, firstlen, +			   PCI_DMA_TODEVICE);  	if (unlikely(pci_dma_mapping_error(il->pci_dev, txcmd_phys)))  		goto drop_unlock;  	/* Set up TFD's 2nd entry to point directly to remainder of skb,  	 * if any (802.11 null frames have no payload). */ -	len = skb->len - hdr_len; -	if (len) { +	secondlen = skb->len - hdr_len; +	if (secondlen > 0) {  		phys_addr = -		    pci_map_single(il->pci_dev, skb->data + hdr_len, len, +		    pci_map_single(il->pci_dev, skb->data + hdr_len, secondlen,  				   PCI_DMA_TODEVICE);  		if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr)))  			goto drop_unlock; @@ -611,12 +613,12 @@ il3945_tx_skb(struct il_priv *il,  	/* Add buffer containing Tx command and MAC(!) header to TFD's  	 * first entry */ -	il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, len, 1, 0); +	il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, firstlen, 1, 0);  	dma_unmap_addr_set(out_meta, mapping, txcmd_phys); -	dma_unmap_len_set(out_meta, len, len); -	if (len) -		il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, len, 0, -					       U32_PAD(len)); +	dma_unmap_len_set(out_meta, len, firstlen); +	if (secondlen > 0) +		il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, secondlen, 0, +					       U32_PAD(secondlen));  	if (!ieee80211_has_morefrags(hdr->frame_control)) {  		txq->need_update = 1; diff --git a/drivers/net/wireless/iwlegacy/4965-rs.c b/drivers/net/wireless/iwlegacy/4965-rs.c index e8324b5e5bf..6c7493c2d69 100644 --- a/drivers/net/wireless/iwlegacy/4965-rs.c +++ b/drivers/net/wireless/iwlegacy/4965-rs.c @@ -2152,7 +2152,7 @@ il4965_rs_initialize_lq(struct il_priv *il, struct ieee80211_conf *conf,  	int rate_idx;  	int i;  	u32 rate; -	u8 use_green = il4965_rs_use_green(il, sta); +	u8 use_green;  	u8 active_tbl = 0;  	u8 valid_tx_ant;  	struct il_station_priv *sta_priv; @@ -2160,6 +2160,7 @@ il4965_rs_initialize_lq(struct il_priv *il, struct ieee80211_conf *conf,  	if (!sta || !lq_sta)  		return; +	use_green = il4965_rs_use_green(il, sta);  	sta_priv = (void *)sta->drv_priv;  	i = lq_sta->last_txrate_idx; diff --git a/drivers/net/wireless/iwlwifi/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c index 86ea5f4c393..44ca0e57f9f 100644 --- a/drivers/net/wireless/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/iwlwifi/dvm/lib.c @@ -1262,6 +1262,15 @@ int iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)  	}  	/* +	 * This can happen upon FW ASSERT: we clear the STATUS_FW_ERROR flag +	 * in iwl_down but cancel the workers only later. +	 */ +	if (!priv->ucode_loaded) { +		IWL_ERR(priv, "Fw not loaded - dropping CMD: %x\n", cmd->id); +		return -EIO; +	} + +	/*  	 * Synchronous commands from this op-mode must hold  	 * the mutex, this ensures we don't try to send two  	 * (or more) synchronous commands at a time. diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c index 23be948cf16..a82b6b39d4f 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c @@ -1419,6 +1419,14 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,  	mutex_lock(&priv->mutex); +	if (changes & BSS_CHANGED_IDLE && bss_conf->idle) { +		/* +		 * If we go idle, then clearly no "passive-no-rx" +		 * workaround is needed any more, this is a reset. +		 */ +		iwlagn_lift_passive_no_rx(priv); +	} +  	if (unlikely(!iwl_is_ready(priv))) {  		IWL_DEBUG_MAC80211(priv, "leave - not ready\n");  		mutex_unlock(&priv->mutex); @@ -1450,16 +1458,6 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,  			priv->timestamp = bss_conf->sync_tsf;  			ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;  		} else { -			/* -			 * If we disassociate while there are pending -			 * frames, just wake up the queues and let the -			 * frames "escape" ... This shouldn't really -			 * be happening to start with, but we should -			 * not get stuck in this case either since it -			 * can happen if userspace gets confused. -			 */ -			iwlagn_lift_passive_no_rx(priv); -  			ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;  			if (ctx->ctxid == IWL_RXON_CTX_BSS) diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index 94ef33838bc..b775769f832 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c @@ -151,7 +151,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,  		       sta_id, sta->sta.addr, flags & CMD_ASYNC ?  "a" : "");  	if (!(flags & CMD_ASYNC)) { -		cmd.flags |= CMD_WANT_SKB | CMD_WANT_HCMD; +		cmd.flags |= CMD_WANT_SKB;  		might_sleep();  	} diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index 6aec2df3bb2..d1a670d7b10 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c @@ -1192,7 +1192,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,  			memset(&info->status, 0, sizeof(info->status));  			if (status == TX_STATUS_FAIL_PASSIVE_NO_RX && -			    iwl_is_associated_ctx(ctx) && ctx->vif && +			    ctx->vif &&  			    ctx->vif->type == NL80211_IFTYPE_STATION) {  				/* block and stop all queues */  				priv->passive_no_rx = true; diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c index 736fe9bb140..1a4ac9236a4 100644 --- a/drivers/net/wireless/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c @@ -367,6 +367,8 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,  		return -EIO;  	} +	priv->ucode_loaded = true; +  	if (ucode_type != IWL_UCODE_WOWLAN) {  		/* delay a bit to give rfkill time to run */  		msleep(5); @@ -380,8 +382,6 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,  		return ret;  	} -	priv->ucode_loaded = true; -  	return 0;  } diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 9a0f45ec9e0..81aa91fab5a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -349,25 +349,23 @@ TRACE_EVENT(iwlwifi_dev_rx_data,  TRACE_EVENT(iwlwifi_dev_hcmd,  	TP_PROTO(const struct device *dev,  		 struct iwl_host_cmd *cmd, u16 total_size, -		 const void *hdr, size_t hdr_len), -	TP_ARGS(dev, cmd, total_size, hdr, hdr_len), +		 struct iwl_cmd_header *hdr), +	TP_ARGS(dev, cmd, total_size, hdr),  	TP_STRUCT__entry(  		DEV_ENTRY  		__dynamic_array(u8, hcmd, total_size)  		__field(u32, flags)  	),  	TP_fast_assign( -		int i, offset = hdr_len; +		int i, offset = sizeof(*hdr);  		DEV_ASSIGN;  		__entry->flags = cmd->flags; -		memcpy(__get_dynamic_array(hcmd), hdr, hdr_len); +		memcpy(__get_dynamic_array(hcmd), hdr, sizeof(*hdr)); -		for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { +		for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) {  			if (!cmd->len[i])  				continue; -			if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)) -				continue;  			memcpy((u8 *)__get_dynamic_array(hcmd) + offset,  			       cmd->data[i], cmd->len[i]);  			offset += cmd->len[i]; diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 6f228bb2b84..fbfd2d13711 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1102,7 +1102,6 @@ void iwl_drv_stop(struct iwl_drv *drv)  /* shared module parameters */  struct iwl_mod_params iwlwifi_mod_params = { -	.amsdu_size_8K = 1,  	.restart_fw = 1,  	.plcp_check = true,  	.bt_coex_active = true, @@ -1207,7 +1206,7 @@ MODULE_PARM_DESC(11n_disable,  	"disable 11n functionality, bitmap: 1: full, 2: agg TX, 4: agg RX");  module_param_named(amsdu_size_8K, iwlwifi_mod_params.amsdu_size_8K,  		   int, S_IRUGO); -MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); +MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0)");  module_param_named(fw_restart, iwlwifi_mod_params.restart_fw, int, S_IRUGO);  MODULE_PARM_DESC(fw_restart, "restart firmware in case of error"); diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h index e5e3a79eae2..2c2a729092f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h @@ -91,7 +91,7 @@ enum iwl_power_level {   * @sw_crypto: using hardware encryption, default = 0   * @disable_11n: disable 11n capabilities, default = 0,   *	use IWL_DISABLE_HT_* constants - * @amsdu_size_8K: enable 8K amsdu size, default = 1 + * @amsdu_size_8K: enable 8K amsdu size, default = 0   * @restart_fw: restart firmware, default = 1   * @plcp_check: enable plcp health check, default = true   * @wd_disable: enable stuck queue check, default = 0 diff --git a/drivers/net/wireless/iwlwifi/iwl-phy-db.c b/drivers/net/wireless/iwlwifi/iwl-phy-db.c index 14fc8d39fc2..3392011a876 100644 --- a/drivers/net/wireless/iwlwifi/iwl-phy-db.c +++ b/drivers/net/wireless/iwlwifi/iwl-phy-db.c @@ -136,12 +136,6 @@ struct iwl_calib_res_notif_phy_db {  	u8 data[];  } __packed; -#define IWL_PHY_DB_STATIC_PIC cpu_to_le32(0x21436587) -static inline void iwl_phy_db_test_pic(__le32 pic) -{ -	WARN_ON(IWL_PHY_DB_STATIC_PIC != pic); -} -  struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans)  {  	struct iwl_phy_db *phy_db = kzalloc(sizeof(struct iwl_phy_db), @@ -260,11 +254,6 @@ int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt,  			(size - CHANNEL_NUM_SIZE) / phy_db->channel_num;  	} -	/* Test PIC */ -	if (type != IWL_PHY_DB_CFG) -		iwl_phy_db_test_pic(*(((__le32 *)phy_db_notif->data) + -				      (size / sizeof(__le32)) - 1)); -  	IWL_DEBUG_INFO(phy_db->trans,  		       "%s(%d): [PHYDB]SET: Type %d , Size: %d\n",  		       __func__, __LINE__, type, size); @@ -372,11 +361,6 @@ int iwl_phy_db_get_section_data(struct iwl_phy_db *phy_db,  		*size = entry->size;  	} -	/* Test PIC */ -	if (type != IWL_PHY_DB_CFG) -		iwl_phy_db_test_pic(*(((__le32 *)*data) + -				      (*size / sizeof(__le32)) - 1)); -  	IWL_DEBUG_INFO(phy_db->trans,  		       "%s(%d): [PHYDB] GET: Type %d , Size: %d\n",  		       __func__, __LINE__, type, *size); diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 8c7bec6b9a0..0cac2b7af78 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -186,19 +186,13 @@ struct iwl_rx_packet {   * @CMD_ASYNC: Return right away and don't want for the response   * @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the   *	response. The caller needs to call iwl_free_resp when done. - * @CMD_WANT_HCMD: The caller needs to get the HCMD that was sent in the - *	response handler. Chunks flagged by %IWL_HCMD_DFL_NOCOPY won't be - *	copied. The pointer passed to the response handler is in the transport - *	ownership and don't need to be freed by the op_mode. This also means - *	that the pointer is invalidated after the op_mode's handler returns.   * @CMD_ON_DEMAND: This command is sent by the test mode pipe.   */  enum CMD_MODE {  	CMD_SYNC		= 0,  	CMD_ASYNC		= BIT(0),  	CMD_WANT_SKB		= BIT(1), -	CMD_WANT_HCMD		= BIT(2), -	CMD_ON_DEMAND		= BIT(3), +	CMD_ON_DEMAND		= BIT(2),  };  #define DEF_CMD_PAYLOAD_SIZE 320 @@ -217,7 +211,11 @@ struct iwl_device_cmd {  #define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd)) -#define IWL_MAX_CMD_TFDS	2 +/* + * number of transfer buffers (fragments) per transmit frame descriptor; + * this is just the driver's idea, the hardware supports 20 + */ +#define IWL_MAX_CMD_TBS_PER_TFD	2  /**   * struct iwl_hcmd_dataflag - flag for each one of the chunks of the command @@ -254,15 +252,15 @@ enum iwl_hcmd_dataflag {   * @id: id of the host command   */  struct iwl_host_cmd { -	const void *data[IWL_MAX_CMD_TFDS]; +	const void *data[IWL_MAX_CMD_TBS_PER_TFD];  	struct iwl_rx_packet *resp_pkt;  	unsigned long _rx_page_addr;  	u32 _rx_page_order;  	int handler_status;  	u32 flags; -	u16 len[IWL_MAX_CMD_TFDS]; -	u8 dataflags[IWL_MAX_CMD_TFDS]; +	u16 len[IWL_MAX_CMD_TBS_PER_TFD]; +	u8 dataflags[IWL_MAX_CMD_TBS_PER_TFD];  	u8 id;  }; diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index c64d864799c..994c8c263dc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -61,6 +61,7 @@   *   *****************************************************************************/ +#include <linux/etherdevice.h>  #include <net/cfg80211.h>  #include <net/ipv6.h>  #include "iwl-modparams.h" @@ -192,6 +193,11 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,  					   sizeof(wkc), &wkc);  		data->error = ret != 0; +		mvm->ptk_ivlen = key->iv_len; +		mvm->ptk_icvlen = key->icv_len; +		mvm->gtk_ivlen = key->iv_len; +		mvm->gtk_icvlen = key->icv_len; +  		/* don't upload key again */  		goto out_unlock;  	} @@ -304,9 +310,13 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,  	 */  	if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {  		key->hw_key_idx = 0; +		mvm->ptk_ivlen = key->iv_len; +		mvm->ptk_icvlen = key->icv_len;  	} else {  		data->gtk_key_idx++;  		key->hw_key_idx = data->gtk_key_idx; +		mvm->gtk_ivlen = key->iv_len; +		mvm->gtk_icvlen = key->icv_len;  	}  	ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true); @@ -649,6 +659,11 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)  	/* We reprogram keys and shouldn't allocate new key indices */  	memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); +	mvm->ptk_ivlen = 0; +	mvm->ptk_icvlen = 0; +	mvm->ptk_ivlen = 0; +	mvm->ptk_icvlen = 0; +  	/*  	 * The D3 firmware still hardcodes the AP station ID for the  	 * BSS we're associated with as 0. As a result, we have to move @@ -783,7 +798,6 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,  	struct iwl_wowlan_status *status;  	u32 reasons;  	int ret, len; -	bool pkt8023 = false;  	struct sk_buff *pkt = NULL;  	iwl_trans_read_mem_bytes(mvm->trans, base, @@ -824,7 +838,8 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,  	status = (void *)cmd.resp_pkt->data;  	if (len - sizeof(struct iwl_cmd_header) != -	    sizeof(*status) + le32_to_cpu(status->wake_packet_bufsize)) { +	    sizeof(*status) + +	    ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4)) {  		IWL_ERR(mvm, "Invalid WoWLAN status response!\n");  		goto out;  	} @@ -836,61 +851,96 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,  		goto report;  	} -	if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET) { +	if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET)  		wakeup.magic_pkt = true; -		pkt8023 = true; -	} -	if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) { +	if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN)  		wakeup.pattern_idx =  			le16_to_cpu(status->pattern_number); -		pkt8023 = true; -	}  	if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON |  		       IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH))  		wakeup.disconnect = true; -	if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE) { +	if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE)  		wakeup.gtk_rekey_failure = true; -		pkt8023 = true; -	} -	if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED) { +	if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED)  		wakeup.rfkill_release = true; -		pkt8023 = true; -	} -	if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST) { +	if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST)  		wakeup.eap_identity_req = true; -		pkt8023 = true; -	} -	if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE) { +	if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE)  		wakeup.four_way_handshake = true; -		pkt8023 = true; -	}  	if (status->wake_packet_bufsize) { -		u32 pktsize = le32_to_cpu(status->wake_packet_bufsize); -		u32 pktlen = le32_to_cpu(status->wake_packet_length); +		int pktsize = le32_to_cpu(status->wake_packet_bufsize); +		int pktlen = le32_to_cpu(status->wake_packet_length); +		const u8 *pktdata = status->wake_packet; +		struct ieee80211_hdr *hdr = (void *)pktdata; +		int truncated = pktlen - pktsize; + +		/* this would be a firmware bug */ +		if (WARN_ON_ONCE(truncated < 0)) +			truncated = 0; + +		if (ieee80211_is_data(hdr->frame_control)) { +			int hdrlen = ieee80211_hdrlen(hdr->frame_control); +			int ivlen = 0, icvlen = 4; /* also FCS */ -		if (pkt8023) {  			pkt = alloc_skb(pktsize, GFP_KERNEL);  			if (!pkt)  				goto report; -			memcpy(skb_put(pkt, pktsize), status->wake_packet, -			       pktsize); + +			memcpy(skb_put(pkt, hdrlen), pktdata, hdrlen); +			pktdata += hdrlen; +			pktsize -= hdrlen; + +			if (ieee80211_has_protected(hdr->frame_control)) { +				if (is_multicast_ether_addr(hdr->addr1)) { +					ivlen = mvm->gtk_ivlen; +					icvlen += mvm->gtk_icvlen; +				} else { +					ivlen = mvm->ptk_ivlen; +					icvlen += mvm->ptk_icvlen; +				} +			} + +			/* if truncated, FCS/ICV is (partially) gone */ +			if (truncated >= icvlen) { +				icvlen = 0; +				truncated -= icvlen; +			} else { +				icvlen -= truncated; +				truncated = 0; +			} + +			pktsize -= ivlen + icvlen; +			pktdata += ivlen; + +			memcpy(skb_put(pkt, pktsize), pktdata, pktsize); +  			if (ieee80211_data_to_8023(pkt, vif->addr, vif->type))  				goto report;  			wakeup.packet = pkt->data;  			wakeup.packet_present_len = pkt->len; -			wakeup.packet_len = pkt->len - (pktlen - pktsize); +			wakeup.packet_len = pkt->len - truncated;  			wakeup.packet_80211 = false;  		} else { +			int fcslen = 4; + +			if (truncated >= 4) { +				truncated -= 4; +				fcslen = 0; +			} else { +				fcslen -= truncated; +				truncated = 0; +			} +			pktsize -= fcslen;  			wakeup.packet = status->wake_packet;  			wakeup.packet_present_len = pktsize; -			wakeup.packet_len = pktlen; +			wakeup.packet_len = pktlen - truncated;  			wakeup.packet_80211 = true;  		}  	} diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 23eebda848b..2adb61f103f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -762,18 +762,20 @@ struct iwl_phy_context_cmd {  #define IWL_RX_INFO_PHY_CNT 8  #define IWL_RX_INFO_AGC_IDX 1  #define IWL_RX_INFO_RSSI_AB_IDX 2 -#define IWL_RX_INFO_RSSI_C_IDX 3 -#define IWL_OFDM_AGC_DB_MSK 0xfe00 -#define IWL_OFDM_AGC_DB_POS 9 +#define IWL_OFDM_AGC_A_MSK 0x0000007f +#define IWL_OFDM_AGC_A_POS 0 +#define IWL_OFDM_AGC_B_MSK 0x00003f80 +#define IWL_OFDM_AGC_B_POS 7 +#define IWL_OFDM_AGC_CODE_MSK 0x3fe00000 +#define IWL_OFDM_AGC_CODE_POS 20  #define IWL_OFDM_RSSI_INBAND_A_MSK 0x00ff -#define IWL_OFDM_RSSI_ALLBAND_A_MSK 0xff00  #define IWL_OFDM_RSSI_A_POS 0 +#define IWL_OFDM_RSSI_ALLBAND_A_MSK 0xff00 +#define IWL_OFDM_RSSI_ALLBAND_A_POS 8  #define IWL_OFDM_RSSI_INBAND_B_MSK 0xff0000 -#define IWL_OFDM_RSSI_ALLBAND_B_MSK 0xff000000  #define IWL_OFDM_RSSI_B_POS 16 -#define IWL_OFDM_RSSI_INBAND_C_MSK 0x00ff -#define IWL_OFDM_RSSI_ALLBAND_C_MSK 0xff00 -#define IWL_OFDM_RSSI_C_POS 0 +#define IWL_OFDM_RSSI_ALLBAND_B_MSK 0xff000000 +#define IWL_OFDM_RSSI_ALLBAND_B_POS 24  /**   * struct iwl_rx_phy_info - phy info diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index d3d959db03a..500f818dba0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -79,17 +79,8 @@  #define UCODE_VALID_OK	cpu_to_le32(0x1)  /* Default calibration values for WkP - set to INIT image w/o running */ -static const u8 wkp_calib_values_bb_filter[] = { 0xbf, 0x00, 0x5f, 0x00, 0x2f, -						 0x00, 0x18, 0x00 }; -static const u8 wkp_calib_values_rx_dc[] = { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, -					     0x7f, 0x7f, 0x7f }; -static const u8 wkp_calib_values_tx_lo[] = { 0x00, 0x00, 0x00, 0x00 }; -static const u8 wkp_calib_values_tx_iq[] = { 0xff, 0x00, 0xff, 0x00, 0x00, -					     0x00 }; -static const u8 wkp_calib_values_rx_iq[] = { 0xff, 0x00, 0x00, 0x00 };  static const u8 wkp_calib_values_rx_iq_skew[] = { 0x00, 0x00, 0x01, 0x00 };  static const u8 wkp_calib_values_tx_iq_skew[] = { 0x01, 0x00, 0x00, 0x00 }; -static const u8 wkp_calib_values_xtal[] = { 0xd2, 0xd2 };  struct iwl_calib_default_data {  	u16 size; @@ -99,12 +90,7 @@ struct iwl_calib_default_data {  #define CALIB_SIZE_N_DATA(_buf) {.size = sizeof(_buf), .data = &_buf}  static const struct iwl_calib_default_data wkp_calib_default_data[12] = { -	[5] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_dc), -	[6] = CALIB_SIZE_N_DATA(wkp_calib_values_bb_filter), -	[7] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_lo), -	[8] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq),  	[9] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq_skew), -	[10] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq),  	[11] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq_skew),  }; @@ -241,20 +227,6 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,  	return 0;  } -#define IWL_HW_REV_ID_RAINBOW	0x2 -#define IWL_PROJ_TYPE_LHP	0x5 - -static u32 iwl_mvm_build_phy_cfg(struct iwl_mvm *mvm) -{ -	struct iwl_nvm_data *data = mvm->nvm_data; -	/* Temp calls to static definitions, will be changed to CSR calls */ -	u8 hw_rev_id = IWL_HW_REV_ID_RAINBOW; -	u8 project_type = IWL_PROJ_TYPE_LHP; - -	return data->radio_cfg_dash | (data->radio_cfg_step << 2) | -		(hw_rev_id << 4) | ((project_type & 0x7f) << 6) | -		(data->valid_tx_ant << 16) | (data->valid_rx_ant << 20); -}  static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)  { @@ -262,7 +234,7 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)  	enum iwl_ucode_type ucode_type = mvm->cur_ucode;  	/* Set parameters */ -	phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_build_phy_cfg(mvm)); +	phy_cfg_cmd.phy_cfg = cpu_to_le32(mvm->fw->phy_config);  	phy_cfg_cmd.calib_control.event_trigger =  		mvm->fw->default_calib[ucode_type].event_trigger;  	phy_cfg_cmd.calib_control.flow_trigger = @@ -275,103 +247,6 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)  				    sizeof(phy_cfg_cmd), &phy_cfg_cmd);  } -/* Starting with the new PHY DB implementation - New calibs are enabled */ -/* Value - 0x405e7 */ -#define IWL_CALIB_DEFAULT_FLOW_INIT	(IWL_CALIB_CFG_XTAL_IDX		|\ -					 IWL_CALIB_CFG_TEMPERATURE_IDX	|\ -					 IWL_CALIB_CFG_VOLTAGE_READ_IDX	|\ -					 IWL_CALIB_CFG_DC_IDX		|\ -					 IWL_CALIB_CFG_BB_FILTER_IDX	|\ -					 IWL_CALIB_CFG_LO_LEAKAGE_IDX	|\ -					 IWL_CALIB_CFG_TX_IQ_IDX	|\ -					 IWL_CALIB_CFG_RX_IQ_IDX	|\ -					 IWL_CALIB_CFG_AGC_IDX) - -#define IWL_CALIB_DEFAULT_EVENT_INIT	0x0 - -/* Value 0x41567 */ -#define IWL_CALIB_DEFAULT_FLOW_RUN	(IWL_CALIB_CFG_XTAL_IDX		|\ -					 IWL_CALIB_CFG_TEMPERATURE_IDX	|\ -					 IWL_CALIB_CFG_VOLTAGE_READ_IDX	|\ -					 IWL_CALIB_CFG_BB_FILTER_IDX	|\ -					 IWL_CALIB_CFG_DC_IDX		|\ -					 IWL_CALIB_CFG_TX_IQ_IDX	|\ -					 IWL_CALIB_CFG_RX_IQ_IDX	|\ -					 IWL_CALIB_CFG_SENSITIVITY_IDX	|\ -					 IWL_CALIB_CFG_AGC_IDX) - -#define IWL_CALIB_DEFAULT_EVENT_RUN	(IWL_CALIB_CFG_XTAL_IDX		|\ -					 IWL_CALIB_CFG_TEMPERATURE_IDX	|\ -					 IWL_CALIB_CFG_VOLTAGE_READ_IDX	|\ -					 IWL_CALIB_CFG_TX_PWR_IDX	|\ -					 IWL_CALIB_CFG_DC_IDX		|\ -					 IWL_CALIB_CFG_TX_IQ_IDX	|\ -					 IWL_CALIB_CFG_SENSITIVITY_IDX) - -/* - * Sets the calibrations trigger values that will be sent to the FW for runtime - * and init calibrations. - * The ones given in the FW TLV are not correct. - */ -static void iwl_set_default_calib_trigger(struct iwl_mvm *mvm) -{ -	struct iwl_tlv_calib_ctrl default_calib; - -	/* -	 * WkP FW TLV calib bits are wrong, overwrite them. -	 * This defines the dynamic calibrations which are implemented in the -	 * uCode both for init(flow) calculation and event driven calibs. -	 */ - -	/* Init Image */ -	default_calib.event_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_EVENT_INIT); -	default_calib.flow_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_FLOW_INIT); - -	if (default_calib.event_trigger != -	    mvm->fw->default_calib[IWL_UCODE_INIT].event_trigger) -		IWL_ERR(mvm, -			"Updating the event calib for INIT image: 0x%x -> 0x%x\n", -			mvm->fw->default_calib[IWL_UCODE_INIT].event_trigger, -			default_calib.event_trigger); -	if (default_calib.flow_trigger != -	    mvm->fw->default_calib[IWL_UCODE_INIT].flow_trigger) -		IWL_ERR(mvm, -			"Updating the flow calib for INIT image: 0x%x -> 0x%x\n", -			mvm->fw->default_calib[IWL_UCODE_INIT].flow_trigger, -			default_calib.flow_trigger); - -	memcpy((void *)&mvm->fw->default_calib[IWL_UCODE_INIT], -	       &default_calib, sizeof(struct iwl_tlv_calib_ctrl)); -	IWL_ERR(mvm, -		"Setting uCode init calibrations event 0x%x, trigger 0x%x\n", -		default_calib.event_trigger, -		default_calib.flow_trigger); - -	/* Run time image */ -	default_calib.event_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_EVENT_RUN); -	default_calib.flow_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_FLOW_RUN); - -	if (default_calib.event_trigger != -	    mvm->fw->default_calib[IWL_UCODE_REGULAR].event_trigger) -		IWL_ERR(mvm, -			"Updating the event calib for RT image: 0x%x -> 0x%x\n", -			mvm->fw->default_calib[IWL_UCODE_REGULAR].event_trigger, -			default_calib.event_trigger); -	if (default_calib.flow_trigger != -	    mvm->fw->default_calib[IWL_UCODE_REGULAR].flow_trigger) -		IWL_ERR(mvm, -			"Updating the flow calib for RT image: 0x%x -> 0x%x\n", -			mvm->fw->default_calib[IWL_UCODE_REGULAR].flow_trigger, -			default_calib.flow_trigger); - -	memcpy((void *)&mvm->fw->default_calib[IWL_UCODE_REGULAR], -	       &default_calib, sizeof(struct iwl_tlv_calib_ctrl)); -	IWL_ERR(mvm, -		"Setting uCode runtime calibs event 0x%x, trigger 0x%x\n", -		default_calib.event_trigger, -		default_calib.flow_trigger); -} -  static int iwl_set_default_calibrations(struct iwl_mvm *mvm)  {  	u8 cmd_raw[16]; /* holds the variable size commands */ @@ -446,8 +321,10 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)  	ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans);  	WARN_ON(ret); -	/* Override the calibrations from TLV and the const of fw */ -	iwl_set_default_calib_trigger(mvm); +	/* Send TX valid antennas before triggering calibrations */ +	ret = iwl_send_tx_ant_cfg(mvm, mvm->nvm_data->valid_tx_ant); +	if (ret) +		goto error;  	/* WkP doesn't have all calibrations, need to set default values */  	if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index e8264e11b12..7e169b085af 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -557,11 +557,9 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,  	return ret;  } -static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, -					 struct ieee80211_vif *vif) +static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, +					struct ieee80211_vif *vif)  { -	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); -	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);  	u32 tfd_msk = 0, ac;  	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) @@ -594,12 +592,21 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,  		 */  		flush_work(&mvm->sta_drained_wk);  	} +} + +static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, +					 struct ieee80211_vif *vif) +{ +	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + +	iwl_mvm_prepare_mac_removal(mvm, vif);  	mutex_lock(&mvm->mutex);  	/*  	 * For AP/GO interface, the tear down of the resources allocated to the -	 * interface should be handled as part of the bss_info_changed flow. +	 * interface is be handled as part of the stop_ap flow.  	 */  	if (vif->type == NL80211_IFTYPE_AP) {  		iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta); @@ -763,6 +770,8 @@ static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)  	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);  	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); +	iwl_mvm_prepare_mac_removal(mvm, vif); +  	mutex_lock(&mvm->mutex);  	mvmvif->ap_active = false; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 4e339ccfa80..bdae700c769 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -80,7 +80,8 @@  #define IWL_INVALID_MAC80211_QUEUE	0xff  #define IWL_MVM_MAX_ADDRESSES		2 -#define IWL_RSSI_OFFSET 44 +/* RSSI offset for WkP */ +#define IWL_RSSI_OFFSET 50  enum iwl_mvm_tx_fifo {  	IWL_MVM_TX_FIFO_BK = 0, @@ -327,6 +328,10 @@ struct iwl_mvm {  	struct led_classdev led;  	struct ieee80211_vif *p2p_device_vif; + +#ifdef CONFIG_PM_SLEEP +	int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen; +#endif  };  /* Extract MVM priv from op_mode and _hw */ diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index aa59adf87db..d0f9c1e0475 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -624,12 +624,8 @@ static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)  	ieee80211_free_txskb(mvm->hw, skb);  } -static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) +static void iwl_mvm_nic_restart(struct iwl_mvm *mvm)  { -	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - -	iwl_mvm_dump_nic_error_log(mvm); -  	iwl_abort_notification_waits(&mvm->notif_wait);  	/* @@ -663,9 +659,21 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode)  	}  } +static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) +{ +	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + +	iwl_mvm_dump_nic_error_log(mvm); + +	iwl_mvm_nic_restart(mvm); +} +  static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode)  { +	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); +  	WARN_ON(1); +	iwl_mvm_nic_restart(mvm);  }  static const struct iwl_op_mode_ops iwl_mvm_ops = { diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 3f40ab05bbd..b0b190d0ec2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -131,33 +131,42 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,  static int iwl_mvm_calc_rssi(struct iwl_mvm *mvm,  			     struct iwl_rx_phy_info *phy_info)  { -	u32 rssi_a, rssi_b, rssi_c, max_rssi, agc_db; +	int rssi_a, rssi_b, rssi_a_dbm, rssi_b_dbm, max_rssi_dbm; +	int rssi_all_band_a, rssi_all_band_b; +	u32 agc_a, agc_b, max_agc;  	u32 val; -	/* Find max rssi among 3 possible receivers. +	/* Find max rssi among 2 possible receivers.  	 * These values are measured by the Digital Signal Processor (DSP).  	 * They should stay fairly constant even as the signal strength varies,  	 * if the radio's Automatic Gain Control (AGC) is working right.  	 * AGC value (see below) will provide the "interesting" info.  	 */ +	val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]); +	agc_a = (val & IWL_OFDM_AGC_A_MSK) >> IWL_OFDM_AGC_A_POS; +	agc_b = (val & IWL_OFDM_AGC_B_MSK) >> IWL_OFDM_AGC_B_POS; +	max_agc = max_t(u32, agc_a, agc_b); +  	val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_AB_IDX]);  	rssi_a = (val & IWL_OFDM_RSSI_INBAND_A_MSK) >> IWL_OFDM_RSSI_A_POS;  	rssi_b = (val & IWL_OFDM_RSSI_INBAND_B_MSK) >> IWL_OFDM_RSSI_B_POS; -	val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_C_IDX]); -	rssi_c = (val & IWL_OFDM_RSSI_INBAND_C_MSK) >> IWL_OFDM_RSSI_C_POS; - -	val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]); -	agc_db = (val & IWL_OFDM_AGC_DB_MSK) >> IWL_OFDM_AGC_DB_POS; +	rssi_all_band_a = (val & IWL_OFDM_RSSI_ALLBAND_A_MSK) >> +				IWL_OFDM_RSSI_ALLBAND_A_POS; +	rssi_all_band_b = (val & IWL_OFDM_RSSI_ALLBAND_B_MSK) >> +				IWL_OFDM_RSSI_ALLBAND_B_POS; -	max_rssi = max_t(u32, rssi_a, rssi_b); -	max_rssi = max_t(u32, max_rssi, rssi_c); +	/* +	 * dBm = rssi dB - agc dB - constant. +	 * Higher AGC (higher radio gain) means lower signal. +	 */ +	rssi_a_dbm = rssi_a - IWL_RSSI_OFFSET - agc_a; +	rssi_b_dbm = rssi_b - IWL_RSSI_OFFSET - agc_b; +	max_rssi_dbm = max_t(int, rssi_a_dbm, rssi_b_dbm); -	IWL_DEBUG_STATS(mvm, "Rssi In A %d B %d C %d Max %d AGC dB %d\n", -			rssi_a, rssi_b, rssi_c, max_rssi, agc_db); +	IWL_DEBUG_STATS(mvm, "Rssi In A %d B %d Max %d AGCA %d AGCB %d\n", +			rssi_a_dbm, rssi_b_dbm, max_rssi_dbm, agc_a, agc_b); -	/* dBm = max_rssi dB - agc dB - constant. -	 * Higher AGC (higher radio gain) means lower signal. */ -	return max_rssi - agc_db - IWL_RSSI_OFFSET; +	return max_rssi_dbm;  }  /* diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 861a7f9f8e7..274f44e2ef6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -770,6 +770,16 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	u16 txq_id;  	int err; + +	/* +	 * If mac80211 is cleaning its state, then say that we finished since +	 * our state has been cleared anyway. +	 */ +	if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { +		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); +		return 0; +	} +  	spin_lock_bh(&mvmsta->lock);  	txq_id = tid_data->txq_id; diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 6b67ce3f679..6645efe5c03 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -607,12 +607,8 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,  		/* Single frame failure in an AMPDU queue => send BAR */  		if (txq_id >= IWL_FIRST_AMPDU_QUEUE && -		    !(info->flags & IEEE80211_TX_STAT_ACK)) { -			/* there must be only one skb in the skb_list */ -			WARN_ON_ONCE(skb_freed > 1 || -				     !skb_queue_empty(&skbs)); +		    !(info->flags & IEEE80211_TX_STAT_ACK))  			info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; -		}  		/* W/A FW bug: seq_ctl is wrong when the queue is flushed */  		if (status == TX_STATUS_FAIL_FIFO_FLUSHED) { diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index aa2a39a637d..148843e7f34 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -137,10 +137,6 @@ static inline int iwl_queue_dec_wrap(int index, int n_bd)  struct iwl_cmd_meta {  	/* only for SYNC commands, iff the reply skb is wanted */  	struct iwl_host_cmd *source; - -	DEFINE_DMA_UNMAP_ADDR(mapping); -	DEFINE_DMA_UNMAP_LEN(len); -  	u32 flags;  }; @@ -182,19 +178,39 @@ struct iwl_queue {  #define TFD_TX_CMD_SLOTS 256  #define TFD_CMD_SLOTS 32 +/* + * The FH will write back to the first TB only, so we need + * to copy some data into the buffer regardless of whether + * it should be mapped or not. This indicates how big the + * first TB must be to include the scratch buffer. Since + * the scratch is 4 bytes at offset 12, it's 16 now. If we + * make it bigger then allocations will be bigger and copy + * slower, so that's probably not useful. + */ +#define IWL_HCMD_SCRATCHBUF_SIZE	16 +  struct iwl_pcie_txq_entry {  	struct iwl_device_cmd *cmd; -	struct iwl_device_cmd *copy_cmd;  	struct sk_buff *skb;  	/* buffer to free after command completes */  	const void *free_buf;  	struct iwl_cmd_meta meta;  }; +struct iwl_pcie_txq_scratch_buf { +	struct iwl_cmd_header hdr; +	u8 buf[8]; +	__le32 scratch; +}; +  /**   * struct iwl_txq - Tx Queue for DMA   * @q: generic Rx/Tx queue descriptor   * @tfds: transmit frame descriptors (DMA memory) + * @scratchbufs: start of command headers, including scratch buffers, for + *	the writeback -- this is DMA memory and an array holding one buffer + *	for each command on the queue + * @scratchbufs_dma: DMA address for the scratchbufs start   * @entries: transmit entries (driver state)   * @lock: queue lock   * @stuck_timer: timer that fires if queue gets stuck @@ -208,6 +224,8 @@ struct iwl_pcie_txq_entry {  struct iwl_txq {  	struct iwl_queue q;  	struct iwl_tfd *tfds; +	struct iwl_pcie_txq_scratch_buf *scratchbufs; +	dma_addr_t scratchbufs_dma;  	struct iwl_pcie_txq_entry *entries;  	spinlock_t lock;  	struct timer_list stuck_timer; @@ -216,6 +234,13 @@ struct iwl_txq {  	u8 active;  }; +static inline dma_addr_t +iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) +{ +	return txq->scratchbufs_dma + +	       sizeof(struct iwl_pcie_txq_scratch_buf) * idx; +} +  /**   * struct iwl_trans_pcie - PCIe transport specific data   * @rxq: all the RX queue data diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index b0ae06d2456..567e67ad1f6 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -637,22 +637,14 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,  		index = SEQ_TO_INDEX(sequence);  		cmd_index = get_cmd_index(&txq->q, index); -		if (reclaim) { -			struct iwl_pcie_txq_entry *ent; -			ent = &txq->entries[cmd_index]; -			cmd = ent->copy_cmd; -			WARN_ON_ONCE(!cmd && ent->meta.flags & CMD_WANT_HCMD); -		} else { +		if (reclaim) +			cmd = txq->entries[cmd_index].cmd; +		else  			cmd = NULL; -		}  		err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd);  		if (reclaim) { -			/* The original command isn't needed any more */ -			kfree(txq->entries[cmd_index].copy_cmd); -			txq->entries[cmd_index].copy_cmd = NULL; -			/* nor is the duplicated part of the command */  			kfree(txq->entries[cmd_index].free_buf);  			txq->entries[cmd_index].free_buf = NULL;  		} diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 17bedc50e75..12c4f31ca8f 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -475,6 +475,10 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,  	/* If platform's RF_KILL switch is NOT set to KILL */  	hw_rfkill = iwl_is_rfkill_set(trans); +	if (hw_rfkill) +		set_bit(STATUS_RFKILL, &trans_pcie->status); +	else +		clear_bit(STATUS_RFKILL, &trans_pcie->status);  	iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);  	if (hw_rfkill && !run_in_rfkill)  		return -ERFKILL; @@ -641,6 +645,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,  static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)  { +	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	bool hw_rfkill;  	int err; @@ -656,6 +661,10 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)  	iwl_enable_rfkill_int(trans);  	hw_rfkill = iwl_is_rfkill_set(trans); +	if (hw_rfkill) +		set_bit(STATUS_RFKILL, &trans_pcie->status); +	else +		clear_bit(STATUS_RFKILL, &trans_pcie->status);  	iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);  	return 0; @@ -694,6 +703,10 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,  		 * op_mode.  		 */  		hw_rfkill = iwl_is_rfkill_set(trans); +		if (hw_rfkill) +			set_bit(STATUS_RFKILL, &trans_pcie->status); +		else +			clear_bit(STATUS_RFKILL, &trans_pcie->status);  		iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);  	}  } diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 8e9e3212fe7..cb5c6792e3a 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -191,12 +191,9 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)  	}  	for (i = q->read_ptr; i != q->write_ptr; -	     i = iwl_queue_inc_wrap(i, q->n_bd)) { -		struct iwl_tx_cmd *tx_cmd = -			(struct iwl_tx_cmd *)txq->entries[i].cmd->payload; +	     i = iwl_queue_inc_wrap(i, q->n_bd))  		IWL_ERR(trans, "scratch %d = 0x%08x\n", i, -			get_unaligned_le32(&tx_cmd->scratch)); -	} +			le32_to_cpu(txq->scratchbufs[i].scratch));  	iwl_op_mode_nic_error(trans->op_mode);  } @@ -367,8 +364,8 @@ static inline u8 iwl_pcie_tfd_get_num_tbs(struct iwl_tfd *tfd)  }  static void iwl_pcie_tfd_unmap(struct iwl_trans *trans, -			       struct iwl_cmd_meta *meta, struct iwl_tfd *tfd, -			       enum dma_data_direction dma_dir) +			       struct iwl_cmd_meta *meta, +			       struct iwl_tfd *tfd)  {  	int i;  	int num_tbs; @@ -382,17 +379,12 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans,  		return;  	} -	/* Unmap tx_cmd */ -	if (num_tbs) -		dma_unmap_single(trans->dev, -				dma_unmap_addr(meta, mapping), -				dma_unmap_len(meta, len), -				DMA_BIDIRECTIONAL); +	/* first TB is never freed - it's the scratchbuf data */ -	/* Unmap chunks, if any. */  	for (i = 1; i < num_tbs; i++)  		dma_unmap_single(trans->dev, iwl_pcie_tfd_tb_get_addr(tfd, i), -				 iwl_pcie_tfd_tb_get_len(tfd, i), dma_dir); +				 iwl_pcie_tfd_tb_get_len(tfd, i), +				 DMA_TO_DEVICE);  	tfd->num_tbs = 0;  } @@ -406,8 +398,7 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans,   * Does NOT advance any TFD circular buffer read/write indexes   * Does NOT free the TFD itself (which is within circular buffer)   */ -static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq, -				  enum dma_data_direction dma_dir) +static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq)  {  	struct iwl_tfd *tfd_tmp = txq->tfds; @@ -418,8 +409,7 @@ static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq,  	lockdep_assert_held(&txq->lock);  	/* We have only q->n_window txq->entries, but we use q->n_bd tfds */ -	iwl_pcie_tfd_unmap(trans, &txq->entries[idx].meta, &tfd_tmp[rd_ptr], -			   dma_dir); +	iwl_pcie_tfd_unmap(trans, &txq->entries[idx].meta, &tfd_tmp[rd_ptr]);  	/* free SKB */  	if (txq->entries) { @@ -479,6 +469,7 @@ static int iwl_pcie_txq_alloc(struct iwl_trans *trans,  {  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX; +	size_t scratchbuf_sz;  	int i;  	if (WARN_ON(txq->entries || txq->tfds)) @@ -514,9 +505,25 @@ static int iwl_pcie_txq_alloc(struct iwl_trans *trans,  		IWL_ERR(trans, "dma_alloc_coherent(%zd) failed\n", tfd_sz);  		goto error;  	} + +	BUILD_BUG_ON(IWL_HCMD_SCRATCHBUF_SIZE != sizeof(*txq->scratchbufs)); +	BUILD_BUG_ON(offsetof(struct iwl_pcie_txq_scratch_buf, scratch) != +			sizeof(struct iwl_cmd_header) + +			offsetof(struct iwl_tx_cmd, scratch)); + +	scratchbuf_sz = sizeof(*txq->scratchbufs) * slots_num; + +	txq->scratchbufs = dma_alloc_coherent(trans->dev, scratchbuf_sz, +					      &txq->scratchbufs_dma, +					      GFP_KERNEL); +	if (!txq->scratchbufs) +		goto err_free_tfds; +  	txq->q.id = txq_id;  	return 0; +err_free_tfds: +	dma_free_coherent(trans->dev, tfd_sz, txq->tfds, txq->q.dma_addr);  error:  	if (txq->entries && txq_id == trans_pcie->cmd_queue)  		for (i = 0; i < slots_num; i++) @@ -565,22 +572,13 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id)  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	struct iwl_txq *txq = &trans_pcie->txq[txq_id];  	struct iwl_queue *q = &txq->q; -	enum dma_data_direction dma_dir;  	if (!q->n_bd)  		return; -	/* In the command queue, all the TBs are mapped as BIDI -	 * so unmap them as such. -	 */ -	if (txq_id == trans_pcie->cmd_queue) -		dma_dir = DMA_BIDIRECTIONAL; -	else -		dma_dir = DMA_TO_DEVICE; -  	spin_lock_bh(&txq->lock);  	while (q->write_ptr != q->read_ptr) { -		iwl_pcie_txq_free_tfd(trans, txq, dma_dir); +		iwl_pcie_txq_free_tfd(trans, txq);  		q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);  	}  	spin_unlock_bh(&txq->lock); @@ -610,7 +608,6 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id)  	if (txq_id == trans_pcie->cmd_queue)  		for (i = 0; i < txq->q.n_window; i++) {  			kfree(txq->entries[i].cmd); -			kfree(txq->entries[i].copy_cmd);  			kfree(txq->entries[i].free_buf);  		} @@ -619,6 +616,10 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id)  		dma_free_coherent(dev, sizeof(struct iwl_tfd) *  				  txq->q.n_bd, txq->tfds, txq->q.dma_addr);  		txq->q.dma_addr = 0; + +		dma_free_coherent(dev, +				  sizeof(*txq->scratchbufs) * txq->q.n_window, +				  txq->scratchbufs, txq->scratchbufs_dma);  	}  	kfree(txq->entries); @@ -962,7 +963,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,  		iwl_pcie_txq_inval_byte_cnt_tbl(trans, txq); -		iwl_pcie_txq_free_tfd(trans, txq, DMA_TO_DEVICE); +		iwl_pcie_txq_free_tfd(trans, txq);  	}  	iwl_pcie_txq_progress(trans_pcie, txq); @@ -1152,20 +1153,37 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  	void *dup_buf = NULL;  	dma_addr_t phys_addr;  	int idx; -	u16 copy_size, cmd_size; +	u16 copy_size, cmd_size, scratch_size;  	bool had_nocopy = false;  	int i;  	u32 cmd_pos; +	const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD]; +	u16 cmdlen[IWL_MAX_CMD_TBS_PER_TFD];  	copy_size = sizeof(out_cmd->hdr);  	cmd_size = sizeof(out_cmd->hdr);  	/* need one for the header if the first is NOCOPY */ -	BUILD_BUG_ON(IWL_MAX_CMD_TFDS > IWL_NUM_OF_TBS - 1); +	BUILD_BUG_ON(IWL_MAX_CMD_TBS_PER_TFD > IWL_NUM_OF_TBS - 1); + +	for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) { +		cmddata[i] = cmd->data[i]; +		cmdlen[i] = cmd->len[i]; -	for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {  		if (!cmd->len[i])  			continue; + +		/* need at least IWL_HCMD_SCRATCHBUF_SIZE copied */ +		if (copy_size < IWL_HCMD_SCRATCHBUF_SIZE) { +			int copy = IWL_HCMD_SCRATCHBUF_SIZE - copy_size; + +			if (copy > cmdlen[i]) +				copy = cmdlen[i]; +			cmdlen[i] -= copy; +			cmddata[i] += copy; +			copy_size += copy; +		} +  		if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) {  			had_nocopy = true;  			if (WARN_ON(cmd->dataflags[i] & IWL_HCMD_DFL_DUP)) { @@ -1185,7 +1203,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  				goto free_dup_buf;  			} -			dup_buf = kmemdup(cmd->data[i], cmd->len[i], +			dup_buf = kmemdup(cmddata[i], cmdlen[i],  					  GFP_ATOMIC);  			if (!dup_buf)  				return -ENOMEM; @@ -1195,7 +1213,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  				idx = -EINVAL;  				goto free_dup_buf;  			} -			copy_size += cmd->len[i]; +			copy_size += cmdlen[i];  		}  		cmd_size += cmd->len[i];  	} @@ -1242,30 +1260,30 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  	/* and copy the data that needs to be copied */  	cmd_pos = offsetof(struct iwl_device_cmd, payload); -	for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { +	copy_size = sizeof(out_cmd->hdr); +	for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) { +		int copy = 0; +  		if (!cmd->len[i])  			continue; -		if (cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY | -					 IWL_HCMD_DFL_DUP)) -			break; -		memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], cmd->len[i]); -		cmd_pos += cmd->len[i]; -	} -	WARN_ON_ONCE(txq->entries[idx].copy_cmd); +		/* need at least IWL_HCMD_SCRATCHBUF_SIZE copied */ +		if (copy_size < IWL_HCMD_SCRATCHBUF_SIZE) { +			copy = IWL_HCMD_SCRATCHBUF_SIZE - copy_size; -	/* -	 * since out_cmd will be the source address of the FH, it will write -	 * the retry count there. So when the user needs to receivce the HCMD -	 * that corresponds to the response in the response handler, it needs -	 * to set CMD_WANT_HCMD. -	 */ -	if (cmd->flags & CMD_WANT_HCMD) { -		txq->entries[idx].copy_cmd = -			kmemdup(out_cmd, cmd_pos, GFP_ATOMIC); -		if (unlikely(!txq->entries[idx].copy_cmd)) { -			idx = -ENOMEM; -			goto out; +			if (copy > cmd->len[i]) +				copy = cmd->len[i]; +		} + +		/* copy everything if not nocopy/dup */ +		if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY | +					   IWL_HCMD_DFL_DUP))) +			copy = cmd->len[i]; + +		if (copy) { +			memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], copy); +			cmd_pos += copy; +			copy_size += copy;  		}  	} @@ -1275,22 +1293,35 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  		     out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),  		     cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue); -	phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, copy_size, -				   DMA_BIDIRECTIONAL); -	if (unlikely(dma_mapping_error(trans->dev, phys_addr))) { -		idx = -ENOMEM; -		goto out; -	} +	/* start the TFD with the scratchbuf */ +	scratch_size = min_t(int, copy_size, IWL_HCMD_SCRATCHBUF_SIZE); +	memcpy(&txq->scratchbufs[q->write_ptr], &out_cmd->hdr, scratch_size); +	iwl_pcie_txq_build_tfd(trans, txq, +			       iwl_pcie_get_scratchbuf_dma(txq, q->write_ptr), +			       scratch_size, 1); -	dma_unmap_addr_set(out_meta, mapping, phys_addr); -	dma_unmap_len_set(out_meta, len, copy_size); +	/* map first command fragment, if any remains */ +	if (copy_size > scratch_size) { +		phys_addr = dma_map_single(trans->dev, +					   ((u8 *)&out_cmd->hdr) + scratch_size, +					   copy_size - scratch_size, +					   DMA_TO_DEVICE); +		if (dma_mapping_error(trans->dev, phys_addr)) { +			iwl_pcie_tfd_unmap(trans, out_meta, +					   &txq->tfds[q->write_ptr]); +			idx = -ENOMEM; +			goto out; +		} -	iwl_pcie_txq_build_tfd(trans, txq, phys_addr, copy_size, 1); +		iwl_pcie_txq_build_tfd(trans, txq, phys_addr, +				       copy_size - scratch_size, 0); +	} -	for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { -		const void *data = cmd->data[i]; +	/* map the remaining (adjusted) nocopy/dup fragments */ +	for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) { +		const void *data = cmddata[i]; -		if (!cmd->len[i]) +		if (!cmdlen[i])  			continue;  		if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY |  					   IWL_HCMD_DFL_DUP))) @@ -1298,16 +1329,15 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  		if (cmd->dataflags[i] & IWL_HCMD_DFL_DUP)  			data = dup_buf;  		phys_addr = dma_map_single(trans->dev, (void *)data, -					   cmd->len[i], DMA_BIDIRECTIONAL); +					   cmdlen[i], DMA_TO_DEVICE);  		if (dma_mapping_error(trans->dev, phys_addr)) {  			iwl_pcie_tfd_unmap(trans, out_meta, -					   &txq->tfds[q->write_ptr], -					   DMA_BIDIRECTIONAL); +					   &txq->tfds[q->write_ptr]);  			idx = -ENOMEM;  			goto out;  		} -		iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmd->len[i], 0); +		iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmdlen[i], 0);  	}  	out_meta->flags = cmd->flags; @@ -1317,8 +1347,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  	txq->need_update = 1; -	trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, -			       &out_cmd->hdr, copy_size); +	trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr);  	/* start timer if queue currently empty */  	if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout) @@ -1377,7 +1406,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,  	cmd = txq->entries[cmd_index].cmd;  	meta = &txq->entries[cmd_index].meta; -	iwl_pcie_tfd_unmap(trans, meta, &txq->tfds[index], DMA_BIDIRECTIONAL); +	iwl_pcie_tfd_unmap(trans, meta, &txq->tfds[index]);  	/* Input error checking is done when commands are added to queue. */  	if (meta->flags & CMD_WANT_SKB) { @@ -1556,10 +1585,9 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,  	struct iwl_cmd_meta *out_meta;  	struct iwl_txq *txq;  	struct iwl_queue *q; -	dma_addr_t phys_addr = 0; -	dma_addr_t txcmd_phys; -	dma_addr_t scratch_phys; -	u16 len, firstlen, secondlen; +	dma_addr_t tb0_phys, tb1_phys, scratch_phys; +	void *tb1_addr; +	u16 len, tb1_len, tb2_len;  	u8 wait_write_ptr = 0;  	__le16 fc = hdr->frame_control;  	u8 hdr_len = ieee80211_hdrlen(fc); @@ -1597,85 +1625,80 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,  		cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |  			    INDEX_TO_SEQ(q->write_ptr))); +	tb0_phys = iwl_pcie_get_scratchbuf_dma(txq, q->write_ptr); +	scratch_phys = tb0_phys + sizeof(struct iwl_cmd_header) + +		       offsetof(struct iwl_tx_cmd, scratch); + +	tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); +	tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); +  	/* Set up first empty entry in queue's array of Tx/cmd buffers */  	out_meta = &txq->entries[q->write_ptr].meta;  	/* -	 * Use the first empty entry in this queue's command buffer array -	 * to contain the Tx command and MAC header concatenated together -	 * (payload data will be in another buffer). -	 * Size of this varies, due to varying MAC header length. -	 * If end is not dword aligned, we'll have 2 extra bytes at the end -	 * of the MAC header (device reads on dword boundaries). -	 * We'll tell device about this padding later. +	 * The second TB (tb1) points to the remainder of the TX command +	 * and the 802.11 header - dword aligned size +	 * (This calculation modifies the TX command, so do it before the +	 * setup of the first TB)  	 */ -	len = sizeof(struct iwl_tx_cmd) + -		sizeof(struct iwl_cmd_header) + hdr_len; -	firstlen = (len + 3) & ~3; +	len = sizeof(struct iwl_tx_cmd) + sizeof(struct iwl_cmd_header) + +	      hdr_len - IWL_HCMD_SCRATCHBUF_SIZE; +	tb1_len = (len + 3) & ~3;  	/* Tell NIC about any 2-byte padding after MAC header */ -	if (firstlen != len) +	if (tb1_len != len)  		tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK; -	/* Physical address of this Tx command's header (not MAC header!), -	 * within command buffer array. */ -	txcmd_phys = dma_map_single(trans->dev, -				    &dev_cmd->hdr, firstlen, -				    DMA_BIDIRECTIONAL); -	if (unlikely(dma_mapping_error(trans->dev, txcmd_phys))) -		goto out_err; -	dma_unmap_addr_set(out_meta, mapping, txcmd_phys); -	dma_unmap_len_set(out_meta, len, firstlen); +	/* The first TB points to the scratchbuf data - min_copy bytes */ +	memcpy(&txq->scratchbufs[q->write_ptr], &dev_cmd->hdr, +	       IWL_HCMD_SCRATCHBUF_SIZE); +	iwl_pcie_txq_build_tfd(trans, txq, tb0_phys, +			       IWL_HCMD_SCRATCHBUF_SIZE, 1); -	if (!ieee80211_has_morefrags(fc)) { -		txq->need_update = 1; -	} else { -		wait_write_ptr = 1; -		txq->need_update = 0; -	} +	/* there must be data left over for TB1 or this code must be changed */ +	BUILD_BUG_ON(sizeof(struct iwl_tx_cmd) < IWL_HCMD_SCRATCHBUF_SIZE); + +	/* map the data for TB1 */ +	tb1_addr = ((u8 *)&dev_cmd->hdr) + IWL_HCMD_SCRATCHBUF_SIZE; +	tb1_phys = dma_map_single(trans->dev, tb1_addr, tb1_len, DMA_TO_DEVICE); +	if (unlikely(dma_mapping_error(trans->dev, tb1_phys))) +		goto out_err; +	iwl_pcie_txq_build_tfd(trans, txq, tb1_phys, tb1_len, 0); -	/* Set up TFD's 2nd entry to point directly to remainder of skb, -	 * if any (802.11 null frames have no payload). */ -	secondlen = skb->len - hdr_len; -	if (secondlen > 0) { -		phys_addr = dma_map_single(trans->dev, skb->data + hdr_len, -					   secondlen, DMA_TO_DEVICE); -		if (unlikely(dma_mapping_error(trans->dev, phys_addr))) { -			dma_unmap_single(trans->dev, -					 dma_unmap_addr(out_meta, mapping), -					 dma_unmap_len(out_meta, len), -					 DMA_BIDIRECTIONAL); +	/* +	 * Set up TFD's third entry to point directly to remainder +	 * of skb, if any (802.11 null frames have no payload). +	 */ +	tb2_len = skb->len - hdr_len; +	if (tb2_len > 0) { +		dma_addr_t tb2_phys = dma_map_single(trans->dev, +						     skb->data + hdr_len, +						     tb2_len, DMA_TO_DEVICE); +		if (unlikely(dma_mapping_error(trans->dev, tb2_phys))) { +			iwl_pcie_tfd_unmap(trans, out_meta, +					   &txq->tfds[q->write_ptr]);  			goto out_err;  		} +		iwl_pcie_txq_build_tfd(trans, txq, tb2_phys, tb2_len, 0);  	} -	/* Attach buffers to TFD */ -	iwl_pcie_txq_build_tfd(trans, txq, txcmd_phys, firstlen, 1); -	if (secondlen > 0) -		iwl_pcie_txq_build_tfd(trans, txq, phys_addr, secondlen, 0); - -	scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + -				offsetof(struct iwl_tx_cmd, scratch); - -	/* take back ownership of DMA buffer to enable update */ -	dma_sync_single_for_cpu(trans->dev, txcmd_phys, firstlen, -				DMA_BIDIRECTIONAL); -	tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); -	tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); -  	/* Set up entry for this TFD in Tx byte-count array */  	iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len)); -	dma_sync_single_for_device(trans->dev, txcmd_phys, firstlen, -				   DMA_BIDIRECTIONAL); -  	trace_iwlwifi_dev_tx(trans->dev, skb,  			     &txq->tfds[txq->q.write_ptr],  			     sizeof(struct iwl_tfd), -			     &dev_cmd->hdr, firstlen, -			     skb->data + hdr_len, secondlen); +			     &dev_cmd->hdr, IWL_HCMD_SCRATCHBUF_SIZE + tb1_len, +			     skb->data + hdr_len, tb2_len);  	trace_iwlwifi_dev_tx_data(trans->dev, skb, -				  skb->data + hdr_len, secondlen); +				  skb->data + hdr_len, tb2_len); + +	if (!ieee80211_has_morefrags(fc)) { +		txq->need_update = 1; +	} else { +		wait_write_ptr = 1; +		txq->need_update = 0; +	}  	/* start timer if queue currently empty */  	if (txq->need_update && q->read_ptr == q->write_ptr && diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 16beaf39dc5..c94dd680267 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -999,7 +999,6 @@ static const struct pcmcia_device_id if_cs_ids[] = {  };  MODULE_DEVICE_TABLE(pcmcia, if_cs_ids); -  static struct pcmcia_driver lbs_driver = {  	.owner		= THIS_MODULE,  	.name		= DRV_NAME, @@ -1007,26 +1006,4 @@ static struct pcmcia_driver lbs_driver = {  	.remove		= if_cs_detach,  	.id_table       = if_cs_ids,  }; - - -static int __init if_cs_init(void) -{ -	int ret; - -	lbs_deb_enter(LBS_DEB_CS); -	ret = pcmcia_register_driver(&lbs_driver); -	lbs_deb_leave(LBS_DEB_CS); -	return ret; -} - - -static void __exit if_cs_exit(void) -{ -	lbs_deb_enter(LBS_DEB_CS); -	pcmcia_unregister_driver(&lbs_driver); -	lbs_deb_leave(LBS_DEB_CS); -} - - -module_init(if_cs_init); -module_exit(if_cs_exit); +module_pcmcia_driver(lbs_driver); diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 739309e70d8..45578335e42 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -825,6 +825,11 @@ static void if_sdio_finish_power_on(struct if_sdio_card *card)  	sdio_release_host(func); +	/* Set fw_ready before queuing any commands so that +	 * lbs_thread won't block from sending them to firmware. +	 */ +	priv->fw_ready = 1; +  	/*  	 * FUNC_INIT is required for SD8688 WLAN/BT multiple functions  	 */ @@ -839,7 +844,6 @@ static void if_sdio_finish_power_on(struct if_sdio_card *card)  			netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n");  	} -	priv->fw_ready = 1;  	wake_up(&card->pwron_waitq);  	if (!card->started) { diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index a44023a7bd5..8aaf56ade4d 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1892,7 +1892,8 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,  		}  	} -	for (i = 0; i < request->n_channels; i++) { +	for (i = 0; i < min_t(u32, request->n_channels, +			      MWIFIEX_USER_SCAN_CHAN_MAX); i++) {  		chan = request->channels[i];  		priv->user_scan_cfg->chan_list[i].chan_number = chan->hw_value;  		priv->user_scan_cfg->chan_list[i].radio_type = chan->band; diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 20a6c555587..b5c8b962ce1 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -157,6 +157,20 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,  		return -1;  	} +	cmd_code = le16_to_cpu(host_cmd->command); +	cmd_size = le16_to_cpu(host_cmd->size); + +	if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET && +	    cmd_code != HostCmd_CMD_FUNC_SHUTDOWN && +	    cmd_code != HostCmd_CMD_FUNC_INIT) { +		dev_err(adapter->dev, +			"DNLD_CMD: FW in reset state, ignore cmd %#x\n", +			cmd_code); +		mwifiex_complete_cmd(adapter, cmd_node); +		mwifiex_insert_cmd_to_free_q(adapter, cmd_node); +		return -1; +	} +  	/* Set command sequence number */  	adapter->seq_num++;  	host_cmd->seq_num = cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO @@ -168,9 +182,6 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,  	adapter->curr_cmd = cmd_node;  	spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); -	cmd_code = le16_to_cpu(host_cmd->command); -	cmd_size = le16_to_cpu(host_cmd->size); -  	/* Adjust skb length */  	if (cmd_node->cmd_skb->len > cmd_size)  		/* @@ -484,8 +495,6 @@ int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no,  	ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid,  				     data_buf); -	if (!ret) -		ret = mwifiex_wait_queue_complete(adapter);  	return ret;  } @@ -588,9 +597,10 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,  	if (cmd_no == HostCmd_CMD_802_11_SCAN) {  		mwifiex_queue_scan_cmd(priv, cmd_node);  	} else { -		adapter->cmd_queued = cmd_node;  		mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);  		queue_work(adapter->workqueue, &adapter->main_work); +		if (cmd_node->wait_q_enabled) +			ret = mwifiex_wait_queue_complete(adapter, cmd_node);  	}  	return ret; diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index e38aa9b3663..0ff4c37ab42 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -709,6 +709,14 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)  		return ret;  	} +	/* cancel current command */ +	if (adapter->curr_cmd) { +		dev_warn(adapter->dev, "curr_cmd is still in processing\n"); +		del_timer(&adapter->cmd_timer); +		mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); +		adapter->curr_cmd = NULL; +	} +  	/* shut down mwifiex */  	dev_dbg(adapter->dev, "info: shutdown mwifiex...\n"); diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 246aa62a481..2fe0ceba440 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -1117,10 +1117,9 @@ mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,  		adhoc_join->bss_descriptor.bssid,  		adhoc_join->bss_descriptor.ssid); -	for (i = 0; bss_desc->supported_rates[i] && -			i < MWIFIEX_SUPPORTED_RATES; -			i++) -			; +	for (i = 0; i < MWIFIEX_SUPPORTED_RATES && +		    bss_desc->supported_rates[i]; i++) +		;  	rates_size = i;  	/* Copy Data Rates from the Rates recorded in scan response */ diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 553adfb0aa8..7035ade9af7 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -723,7 +723,6 @@ struct mwifiex_adapter {  	u16 cmd_wait_q_required;  	struct mwifiex_wait_queue cmd_wait_q;  	u8 scan_wait_q_woken; -	struct cmd_ctrl_node *cmd_queued;  	spinlock_t queue_lock;		/* lock for tx queues */  	struct completion fw_load;  	u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; @@ -1018,7 +1017,8 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,  			struct mwifiex_multicast_list *mcast_list);  int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,  			    struct net_device *dev); -int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter); +int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter, +				struct cmd_ctrl_node *cmd_queued);  int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,  		      struct cfg80211_ssid *req_ssid);  int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type); diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 35c79722c36..feb20461339 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -302,7 +302,7 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)  		i++;  		usleep_range(10, 20);  		/* 50ms max wait */ -		if (i == 50000) +		if (i == 5000)  			break;  	} @@ -1508,6 +1508,7 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)  		}  		memcpy(adapter->upld_buf, skb->data,  		       min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len)); +		skb_push(skb, INTF_HEADER_LEN);  		if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,  					   PCI_DMA_FROMDEVICE))  			return -1; diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index bb60c2754a9..e7f6deaf715 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -1388,10 +1388,15 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,  			list_del(&cmd_node->list);  			spin_unlock_irqrestore(&adapter->scan_pending_q_lock,  					       flags); -			adapter->cmd_queued = cmd_node;  			mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,  							true);  			queue_work(adapter->workqueue, &adapter->main_work); + +			/* Perform internal scan synchronously */ +			if (!priv->scan_request) { +				dev_dbg(adapter->dev, "wait internal scan\n"); +				mwifiex_wait_queue_complete(adapter, cmd_node); +			}  		} else {  			spin_unlock_irqrestore(&adapter->scan_pending_q_lock,  					       flags); @@ -1790,7 +1795,12 @@ check_next_scan:  		/* Need to indicate IOCTL complete */  		if (adapter->curr_cmd->wait_q_enabled) {  			adapter->cmd_wait_q.status = 0; -			mwifiex_complete_cmd(adapter, adapter->curr_cmd); +			if (!priv->scan_request) { +				dev_dbg(adapter->dev, +					"complete internal scan\n"); +				mwifiex_complete_cmd(adapter, +						     adapter->curr_cmd); +			}  		}  		if (priv->report_scan_result)  			priv->report_scan_result = false; @@ -1946,9 +1956,6 @@ int mwifiex_request_scan(struct mwifiex_private *priv,  		/* Normal scan */  		ret = mwifiex_scan_networks(priv, NULL); -	if (!ret) -		ret = mwifiex_wait_queue_complete(priv->adapter); -  	up(&priv->async_sem);  	return ret; diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 9f33c92c90f..13100f8de3d 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -54,16 +54,10 @@ int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,   * This function waits on a cmd wait queue. It also cancels the pending   * request after waking up, in case of errors.   */ -int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) +int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter, +				struct cmd_ctrl_node *cmd_queued)  {  	int status; -	struct cmd_ctrl_node *cmd_queued; - -	if (!adapter->cmd_queued) -		return 0; - -	cmd_queued = adapter->cmd_queued; -	adapter->cmd_queued = NULL;  	dev_dbg(adapter->dev, "cmd pending\n");  	atomic_inc(&adapter->cmd_pending); diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c index d7dbc00bcfb..d21d9593931 100644 --- a/drivers/net/wireless/orinoco/orinoco_cs.c +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -338,18 +338,4 @@ static struct pcmcia_driver orinoco_driver = {  	.suspend	= orinoco_cs_suspend,  	.resume		= orinoco_cs_resume,  }; - -static int __init -init_orinoco_cs(void) -{ -	return pcmcia_register_driver(&orinoco_driver); -} - -static void __exit -exit_orinoco_cs(void) -{ -	pcmcia_unregister_driver(&orinoco_driver); -} - -module_init(init_orinoco_cs); -module_exit(exit_orinoco_cs); +module_pcmcia_driver(orinoco_driver); diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c index 6e28ee4e9c5..e2264bc12eb 100644 --- a/drivers/net/wireless/orinoco/spectrum_cs.c +++ b/drivers/net/wireless/orinoco/spectrum_cs.c @@ -318,18 +318,4 @@ static struct pcmcia_driver orinoco_driver = {  	.resume		= spectrum_cs_resume,  	.id_table       = spectrum_cs_ids,  }; - -static int __init -init_spectrum_cs(void) -{ -	return pcmcia_register_driver(&orinoco_driver); -} - -static void __exit -exit_spectrum_cs(void) -{ -	pcmcia_unregister_driver(&orinoco_driver); -} - -module_init(init_spectrum_cs); -module_exit(exit_spectrum_cs); +module_pcmcia_driver(orinoco_driver); diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 44d6ead4334..76cd47eb901 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -20,6 +20,7 @@ if RT2X00  config RT2400PCI  	tristate "Ralink rt2400 (PCI/PCMCIA) support"  	depends on PCI +	select RT2X00_LIB_MMIO  	select RT2X00_LIB_PCI  	select EEPROM_93CX6  	---help--- @@ -31,6 +32,7 @@ config RT2400PCI  config RT2500PCI  	tristate "Ralink rt2500 (PCI/PCMCIA) support"  	depends on PCI +	select RT2X00_LIB_MMIO  	select RT2X00_LIB_PCI  	select EEPROM_93CX6  	---help--- @@ -43,6 +45,7 @@ config RT61PCI  	tristate "Ralink rt2501/rt61 (PCI/PCMCIA) support"  	depends on PCI  	select RT2X00_LIB_PCI +	select RT2X00_LIB_MMIO  	select RT2X00_LIB_FIRMWARE  	select RT2X00_LIB_CRYPTO  	select CRC_ITU_T @@ -55,10 +58,11 @@ config RT61PCI  config RT2800PCI  	tristate "Ralink rt27xx/rt28xx/rt30xx (PCI/PCIe/PCMCIA) support" -	depends on PCI || RALINK_RT288X || RALINK_RT305X +	depends on PCI || SOC_RT288X || SOC_RT305X  	select RT2800_LIB +	select RT2X00_LIB_MMIO  	select RT2X00_LIB_PCI if PCI -	select RT2X00_LIB_SOC if RALINK_RT288X || RALINK_RT305X +	select RT2X00_LIB_SOC if SOC_RT288X || SOC_RT305X  	select RT2X00_LIB_FIRMWARE  	select RT2X00_LIB_CRYPTO  	select CRC_CCITT @@ -185,6 +189,9 @@ endif  config RT2800_LIB  	tristate +config RT2X00_LIB_MMIO +	tristate +  config RT2X00_LIB_PCI  	tristate  	select RT2X00_LIB diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile index 349d5b8284a..f069d8bc5b6 100644 --- a/drivers/net/wireless/rt2x00/Makefile +++ b/drivers/net/wireless/rt2x00/Makefile @@ -9,6 +9,7 @@ rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE)	+= rt2x00firmware.o  rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS)	+= rt2x00leds.o  obj-$(CONFIG_RT2X00_LIB)		+= rt2x00lib.o +obj-$(CONFIG_RT2X00_LIB_MMIO)		+= rt2x00mmio.o  obj-$(CONFIG_RT2X00_LIB_PCI)		+= rt2x00pci.o  obj-$(CONFIG_RT2X00_LIB_SOC)		+= rt2x00soc.o  obj-$(CONFIG_RT2X00_LIB_USB)		+= rt2x00usb.o diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 221beaaa83f..dcfb54e0c51 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -34,6 +34,7 @@  #include <linux/slab.h>  #include "rt2x00.h" +#include "rt2x00mmio.h"  #include "rt2x00pci.h"  #include "rt2400pci.h" diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 39edc59e8d0..e1d2dc9ed28 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -34,6 +34,7 @@  #include <linux/slab.h>  #include "rt2x00.h" +#include "rt2x00mmio.h"  #include "rt2x00pci.h"  #include "rt2500pci.h" diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 48a01aa21f1..ba5a05625aa 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -41,6 +41,7 @@  #include <linux/eeprom_93cx6.h>  #include "rt2x00.h" +#include "rt2x00mmio.h"  #include "rt2x00pci.h"  #include "rt2x00soc.h"  #include "rt2800lib.h" @@ -89,7 +90,7 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token)  	rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);  } -#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) +#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X)  static int rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)  {  	void __iomem *base_addr = ioremap(0x1F040000, EEPROM_SIZE); @@ -107,7 +108,7 @@ static inline int rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)  {  	return -ENOMEM;  } -#endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */ +#endif /* CONFIG_SOC_RT288X || CONFIG_SOC_RT305X */  #ifdef CONFIG_PCI  static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom) @@ -1177,7 +1178,7 @@ MODULE_DEVICE_TABLE(pci, rt2800pci_device_table);  #endif /* CONFIG_PCI */  MODULE_LICENSE("GPL"); -#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) +#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X)  static int rt2800soc_probe(struct platform_device *pdev)  {  	return rt2x00soc_probe(pdev, &rt2800pci_ops); @@ -1194,7 +1195,7 @@ static struct platform_driver rt2800soc_driver = {  	.suspend	= rt2x00soc_suspend,  	.resume		= rt2x00soc_resume,  }; -#endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */ +#endif /* CONFIG_SOC_RT288X || CONFIG_SOC_RT305X */  #ifdef CONFIG_PCI  static int rt2800pci_probe(struct pci_dev *pci_dev, @@ -1217,7 +1218,7 @@ static int __init rt2800pci_init(void)  {  	int ret = 0; -#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) +#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X)  	ret = platform_driver_register(&rt2800soc_driver);  	if (ret)  		return ret; @@ -1225,7 +1226,7 @@ static int __init rt2800pci_init(void)  #ifdef CONFIG_PCI  	ret = pci_register_driver(&rt2800pci_driver);  	if (ret) { -#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) +#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X)  		platform_driver_unregister(&rt2800soc_driver);  #endif  		return ret; @@ -1240,7 +1241,7 @@ static void __exit rt2800pci_exit(void)  #ifdef CONFIG_PCI  	pci_unregister_driver(&rt2800pci_driver);  #endif -#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) +#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X)  	platform_driver_unregister(&rt2800soc_driver);  #endif  } diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 1031db66474..189744db65e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1236,8 +1236,10 @@ static inline void rt2x00lib_set_if_combinations(struct rt2x00_dev *rt2x00dev)  	 */  	if_limit = &rt2x00dev->if_limits_ap;  	if_limit->max = rt2x00dev->ops->max_ap_intf; -	if_limit->types = BIT(NL80211_IFTYPE_AP) | -			BIT(NL80211_IFTYPE_MESH_POINT); +	if_limit->types = BIT(NL80211_IFTYPE_AP); +#ifdef CONFIG_MAC80211_MESH +	if_limit->types |= BIT(NL80211_IFTYPE_MESH_POINT); +#endif  	/*  	 * Build up AP interface combinations structure. @@ -1309,7 +1311,9 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)  		rt2x00dev->hw->wiphy->interface_modes |=  		    BIT(NL80211_IFTYPE_ADHOC) |  		    BIT(NL80211_IFTYPE_AP) | +#ifdef CONFIG_MAC80211_MESH  		    BIT(NL80211_IFTYPE_MESH_POINT) | +#endif  		    BIT(NL80211_IFTYPE_WDS);  	rt2x00dev->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; diff --git a/drivers/net/wireless/rt2x00/rt2x00mmio.c b/drivers/net/wireless/rt2x00/rt2x00mmio.c new file mode 100644 index 00000000000..d84a680ba0c --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00mmio.c @@ -0,0 +1,216 @@ +/* +	Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> +	<http://rt2x00.serialmonkey.com> + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the +	Free Software Foundation, Inc., +	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* +	Module: rt2x00mmio +	Abstract: rt2x00 generic mmio device routines. + */ + +#include <linux/dma-mapping.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> + +#include "rt2x00.h" +#include "rt2x00mmio.h" + +/* + * Register access. + */ +int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, +			   const unsigned int offset, +			   const struct rt2x00_field32 field, +			   u32 *reg) +{ +	unsigned int i; + +	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) +		return 0; + +	for (i = 0; i < REGISTER_BUSY_COUNT; i++) { +		rt2x00pci_register_read(rt2x00dev, offset, reg); +		if (!rt2x00_get_field32(*reg, field)) +			return 1; +		udelay(REGISTER_BUSY_DELAY); +	} + +	printk_once(KERN_ERR "%s() Indirect register access failed: " +	      "offset=0x%.08x, value=0x%.08x\n", __func__, offset, *reg); +	*reg = ~0; + +	return 0; +} +EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read); + +bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) +{ +	struct data_queue *queue = rt2x00dev->rx; +	struct queue_entry *entry; +	struct queue_entry_priv_pci *entry_priv; +	struct skb_frame_desc *skbdesc; +	int max_rx = 16; + +	while (--max_rx) { +		entry = rt2x00queue_get_entry(queue, Q_INDEX); +		entry_priv = entry->priv_data; + +		if (rt2x00dev->ops->lib->get_entry_state(entry)) +			break; + +		/* +		 * Fill in desc fields of the skb descriptor +		 */ +		skbdesc = get_skb_frame_desc(entry->skb); +		skbdesc->desc = entry_priv->desc; +		skbdesc->desc_len = entry->queue->desc_size; + +		/* +		 * DMA is already done, notify rt2x00lib that +		 * it finished successfully. +		 */ +		rt2x00lib_dmastart(entry); +		rt2x00lib_dmadone(entry); + +		/* +		 * Send the frame to rt2x00lib for further processing. +		 */ +		rt2x00lib_rxdone(entry, GFP_ATOMIC); +	} + +	return !max_rx; +} +EXPORT_SYMBOL_GPL(rt2x00pci_rxdone); + +void rt2x00pci_flush_queue(struct data_queue *queue, bool drop) +{ +	unsigned int i; + +	for (i = 0; !rt2x00queue_empty(queue) && i < 10; i++) +		msleep(10); +} +EXPORT_SYMBOL_GPL(rt2x00pci_flush_queue); + +/* + * Device initialization handlers. + */ +static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev, +				     struct data_queue *queue) +{ +	struct queue_entry_priv_pci *entry_priv; +	void *addr; +	dma_addr_t dma; +	unsigned int i; + +	/* +	 * Allocate DMA memory for descriptor and buffer. +	 */ +	addr = dma_alloc_coherent(rt2x00dev->dev, +				  queue->limit * queue->desc_size, +				  &dma, GFP_KERNEL); +	if (!addr) +		return -ENOMEM; + +	memset(addr, 0, queue->limit * queue->desc_size); + +	/* +	 * Initialize all queue entries to contain valid addresses. +	 */ +	for (i = 0; i < queue->limit; i++) { +		entry_priv = queue->entries[i].priv_data; +		entry_priv->desc = addr + i * queue->desc_size; +		entry_priv->desc_dma = dma + i * queue->desc_size; +	} + +	return 0; +} + +static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev, +				     struct data_queue *queue) +{ +	struct queue_entry_priv_pci *entry_priv = +	    queue->entries[0].priv_data; + +	if (entry_priv->desc) +		dma_free_coherent(rt2x00dev->dev, +				  queue->limit * queue->desc_size, +				  entry_priv->desc, entry_priv->desc_dma); +	entry_priv->desc = NULL; +} + +int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev) +{ +	struct data_queue *queue; +	int status; + +	/* +	 * Allocate DMA +	 */ +	queue_for_each(rt2x00dev, queue) { +		status = rt2x00pci_alloc_queue_dma(rt2x00dev, queue); +		if (status) +			goto exit; +	} + +	/* +	 * Register interrupt handler. +	 */ +	status = request_irq(rt2x00dev->irq, +			     rt2x00dev->ops->lib->irq_handler, +			     IRQF_SHARED, rt2x00dev->name, rt2x00dev); +	if (status) { +		ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n", +		      rt2x00dev->irq, status); +		goto exit; +	} + +	return 0; + +exit: +	queue_for_each(rt2x00dev, queue) +		rt2x00pci_free_queue_dma(rt2x00dev, queue); + +	return status; +} +EXPORT_SYMBOL_GPL(rt2x00pci_initialize); + +void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev) +{ +	struct data_queue *queue; + +	/* +	 * Free irq line. +	 */ +	free_irq(rt2x00dev->irq, rt2x00dev); + +	/* +	 * Free DMA +	 */ +	queue_for_each(rt2x00dev, queue) +		rt2x00pci_free_queue_dma(rt2x00dev, queue); +} +EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize); + +/* + * rt2x00mmio module information. + */ +MODULE_AUTHOR(DRV_PROJECT); +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("rt2x00 mmio library"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/rt2x00/rt2x00mmio.h b/drivers/net/wireless/rt2x00/rt2x00mmio.h new file mode 100644 index 00000000000..4ecaf60175b --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00mmio.h @@ -0,0 +1,119 @@ +/* +	Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> +	<http://rt2x00.serialmonkey.com> + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the +	Free Software Foundation, Inc., +	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* +	Module: rt2x00mmio +	Abstract: Data structures for the rt2x00mmio module. + */ + +#ifndef RT2X00MMIO_H +#define RT2X00MMIO_H + +#include <linux/io.h> + +/* + * Register access. + */ +static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev, +					   const unsigned int offset, +					   u32 *value) +{ +	*value = readl(rt2x00dev->csr.base + offset); +} + +static inline void rt2x00pci_register_multiread(struct rt2x00_dev *rt2x00dev, +						const unsigned int offset, +						void *value, const u32 length) +{ +	memcpy_fromio(value, rt2x00dev->csr.base + offset, length); +} + +static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev, +					    const unsigned int offset, +					    u32 value) +{ +	writel(value, rt2x00dev->csr.base + offset); +} + +static inline void rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev, +						 const unsigned int offset, +						 const void *value, +						 const u32 length) +{ +	__iowrite32_copy(rt2x00dev->csr.base + offset, value, length >> 2); +} + +/** + * rt2x00pci_regbusy_read - Read from register with busy check + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @field: Field to check if register is busy + * @reg: Pointer to where register contents should be stored + * + * This function will read the given register, and checks if the + * register is busy. If it is, it will sleep for a couple of + * microseconds before reading the register again. If the register + * is not read after a certain timeout, this function will return + * FALSE. + */ +int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, +			   const unsigned int offset, +			   const struct rt2x00_field32 field, +			   u32 *reg); + +/** + * struct queue_entry_priv_pci: Per entry PCI specific information + * + * @desc: Pointer to device descriptor + * @desc_dma: DMA pointer to &desc. + * @data: Pointer to device's entry memory. + * @data_dma: DMA pointer to &data. + */ +struct queue_entry_priv_pci { +	__le32 *desc; +	dma_addr_t desc_dma; +}; + +/** + * rt2x00pci_rxdone - Handle RX done events + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * + * Returns true if there are still rx frames pending and false if all + * pending rx frames were processed. + */ +bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev); + +/** + * rt2x00pci_flush_queue - Flush data queue + * @queue: Data queue to stop + * @drop: True to drop all pending frames. + * + * This will wait for a maximum of 100ms, waiting for the queues + * to become empty. + */ +void rt2x00pci_flush_queue(struct data_queue *queue, bool drop); + +/* + * Device initialization handlers. + */ +int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev); +void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev); + +#endif /* RT2X00MMIO_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index a0c8caef3b0..e87865e3311 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -33,182 +33,6 @@  #include "rt2x00pci.h"  /* - * Register access. - */ -int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, -			   const unsigned int offset, -			   const struct rt2x00_field32 field, -			   u32 *reg) -{ -	unsigned int i; - -	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) -		return 0; - -	for (i = 0; i < REGISTER_BUSY_COUNT; i++) { -		rt2x00pci_register_read(rt2x00dev, offset, reg); -		if (!rt2x00_get_field32(*reg, field)) -			return 1; -		udelay(REGISTER_BUSY_DELAY); -	} - -	ERROR(rt2x00dev, "Indirect register access failed: " -	      "offset=0x%.08x, value=0x%.08x\n", offset, *reg); -	*reg = ~0; - -	return 0; -} -EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read); - -bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) -{ -	struct data_queue *queue = rt2x00dev->rx; -	struct queue_entry *entry; -	struct queue_entry_priv_pci *entry_priv; -	struct skb_frame_desc *skbdesc; -	int max_rx = 16; - -	while (--max_rx) { -		entry = rt2x00queue_get_entry(queue, Q_INDEX); -		entry_priv = entry->priv_data; - -		if (rt2x00dev->ops->lib->get_entry_state(entry)) -			break; - -		/* -		 * Fill in desc fields of the skb descriptor -		 */ -		skbdesc = get_skb_frame_desc(entry->skb); -		skbdesc->desc = entry_priv->desc; -		skbdesc->desc_len = entry->queue->desc_size; - -		/* -		 * DMA is already done, notify rt2x00lib that -		 * it finished successfully. -		 */ -		rt2x00lib_dmastart(entry); -		rt2x00lib_dmadone(entry); - -		/* -		 * Send the frame to rt2x00lib for further processing. -		 */ -		rt2x00lib_rxdone(entry, GFP_ATOMIC); -	} - -	return !max_rx; -} -EXPORT_SYMBOL_GPL(rt2x00pci_rxdone); - -void rt2x00pci_flush_queue(struct data_queue *queue, bool drop) -{ -	unsigned int i; - -	for (i = 0; !rt2x00queue_empty(queue) && i < 10; i++) -		msleep(10); -} -EXPORT_SYMBOL_GPL(rt2x00pci_flush_queue); - -/* - * Device initialization handlers. - */ -static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev, -				     struct data_queue *queue) -{ -	struct queue_entry_priv_pci *entry_priv; -	void *addr; -	dma_addr_t dma; -	unsigned int i; - -	/* -	 * Allocate DMA memory for descriptor and buffer. -	 */ -	addr = dma_alloc_coherent(rt2x00dev->dev, -				  queue->limit * queue->desc_size, -				  &dma, GFP_KERNEL); -	if (!addr) -		return -ENOMEM; - -	memset(addr, 0, queue->limit * queue->desc_size); - -	/* -	 * Initialize all queue entries to contain valid addresses. -	 */ -	for (i = 0; i < queue->limit; i++) { -		entry_priv = queue->entries[i].priv_data; -		entry_priv->desc = addr + i * queue->desc_size; -		entry_priv->desc_dma = dma + i * queue->desc_size; -	} - -	return 0; -} - -static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev, -				     struct data_queue *queue) -{ -	struct queue_entry_priv_pci *entry_priv = -	    queue->entries[0].priv_data; - -	if (entry_priv->desc) -		dma_free_coherent(rt2x00dev->dev, -				  queue->limit * queue->desc_size, -				  entry_priv->desc, entry_priv->desc_dma); -	entry_priv->desc = NULL; -} - -int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev) -{ -	struct data_queue *queue; -	int status; - -	/* -	 * Allocate DMA -	 */ -	queue_for_each(rt2x00dev, queue) { -		status = rt2x00pci_alloc_queue_dma(rt2x00dev, queue); -		if (status) -			goto exit; -	} - -	/* -	 * Register interrupt handler. -	 */ -	status = request_irq(rt2x00dev->irq, -			     rt2x00dev->ops->lib->irq_handler, -			     IRQF_SHARED, rt2x00dev->name, rt2x00dev); -	if (status) { -		ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n", -		      rt2x00dev->irq, status); -		goto exit; -	} - -	return 0; - -exit: -	queue_for_each(rt2x00dev, queue) -		rt2x00pci_free_queue_dma(rt2x00dev, queue); - -	return status; -} -EXPORT_SYMBOL_GPL(rt2x00pci_initialize); - -void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev) -{ -	struct data_queue *queue; - -	/* -	 * Free irq line. -	 */ -	free_irq(rt2x00dev->irq, rt2x00dev); - -	/* -	 * Free DMA -	 */ -	queue_for_each(rt2x00dev, queue) -		rt2x00pci_free_queue_dma(rt2x00dev, queue); -} -EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize); - -/*   * PCI driver handlers.   */  static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index e2c99f2b9a1..60d90b20f8b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -36,94 +36,6 @@  #define PCI_DEVICE_DATA(__ops)	.driver_data = (kernel_ulong_t)(__ops)  /* - * Register access. - */ -static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev, -					   const unsigned int offset, -					   u32 *value) -{ -	*value = readl(rt2x00dev->csr.base + offset); -} - -static inline void rt2x00pci_register_multiread(struct rt2x00_dev *rt2x00dev, -						const unsigned int offset, -						void *value, const u32 length) -{ -	memcpy_fromio(value, rt2x00dev->csr.base + offset, length); -} - -static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev, -					    const unsigned int offset, -					    u32 value) -{ -	writel(value, rt2x00dev->csr.base + offset); -} - -static inline void rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev, -						 const unsigned int offset, -						 const void *value, -						 const u32 length) -{ -	__iowrite32_copy(rt2x00dev->csr.base + offset, value, length >> 2); -} - -/** - * rt2x00pci_regbusy_read - Read from register with busy check - * @rt2x00dev: Device pointer, see &struct rt2x00_dev. - * @offset: Register offset - * @field: Field to check if register is busy - * @reg: Pointer to where register contents should be stored - * - * This function will read the given register, and checks if the - * register is busy. If it is, it will sleep for a couple of - * microseconds before reading the register again. If the register - * is not read after a certain timeout, this function will return - * FALSE. - */ -int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, -			   const unsigned int offset, -			   const struct rt2x00_field32 field, -			   u32 *reg); - -/** - * struct queue_entry_priv_pci: Per entry PCI specific information - * - * @desc: Pointer to device descriptor - * @desc_dma: DMA pointer to &desc. - * @data: Pointer to device's entry memory. - * @data_dma: DMA pointer to &data. - */ -struct queue_entry_priv_pci { -	__le32 *desc; -	dma_addr_t desc_dma; -}; - -/** - * rt2x00pci_rxdone - Handle RX done events - * @rt2x00dev: Device pointer, see &struct rt2x00_dev. - * - * Returns true if there are still rx frames pending and false if all - * pending rx frames were processed. - */ -bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev); - -/** - * rt2x00pci_flush_queue - Flush data queue - * @queue: Data queue to stop - * @drop: True to drop all pending frames. - * - * This will wait for a maximum of 100ms, waiting for the queues - * to become empty. - */ -void rt2x00pci_flush_queue(struct data_queue *queue, bool drop); - -/* - * Device initialization handlers. - */ -int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev); -void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev); - -/*   * PCI driver handlers.   */  int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index f95792cfcf8..9e3c8ff53e3 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -35,6 +35,7 @@  #include <linux/eeprom_93cx6.h>  #include "rt2x00.h" +#include "rt2x00mmio.h"  #include "rt2x00pci.h"  #include "rt61pci.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index b1ccff474c7..c08d0f4c5f3 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -1377,74 +1377,57 @@ void rtl92cu_card_disable(struct ieee80211_hw *hw)  void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)  { -	/* dummy routine needed for callback from rtl_op_configure_filter() */ -} - -/*========================================================================== */ - -static void _rtl92cu_set_check_bssid(struct ieee80211_hw *hw, -			      enum nl80211_iftype type) -{  	struct rtl_priv *rtlpriv = rtl_priv(hw); -	u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR);  	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); -	struct rtl_phy *rtlphy = &(rtlpriv->phy); -	u8 filterout_non_associated_bssid = false; +	u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR); -	switch (type) { -	case NL80211_IFTYPE_ADHOC: -	case NL80211_IFTYPE_STATION: -		filterout_non_associated_bssid = true; -		break; -	case NL80211_IFTYPE_UNSPECIFIED: -	case NL80211_IFTYPE_AP: -	default: -		break; -	} -	if (filterout_non_associated_bssid) { +	if (rtlpriv->psc.rfpwr_state != ERFON) +		return; + +	if (check_bssid) { +		u8 tmp;  		if (IS_NORMAL_CHIP(rtlhal->version)) { -			switch (rtlphy->current_io_type) { -			case IO_CMD_RESUME_DM_BY_SCAN: -				reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); -				rtlpriv->cfg->ops->set_hw_reg(hw, -						 HW_VAR_RCR, (u8 *)(®_rcr)); -				/* enable update TSF */ -				_rtl92cu_set_bcn_ctrl_reg(hw, 0, BIT(4)); -				break; -			case IO_CMD_PAUSE_DM_BY_SCAN: -				reg_rcr &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN); -				rtlpriv->cfg->ops->set_hw_reg(hw, -						 HW_VAR_RCR, (u8 *)(®_rcr)); -				/* disable update TSF */ -				_rtl92cu_set_bcn_ctrl_reg(hw, BIT(4), 0); -				break; -			} +			reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); +			tmp = BIT(4);  		} else { -			reg_rcr |= (RCR_CBSSID); -			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, -						      (u8 *)(®_rcr)); -			_rtl92cu_set_bcn_ctrl_reg(hw, 0, (BIT(4)|BIT(5))); +			reg_rcr |= RCR_CBSSID; +			tmp = BIT(4) | BIT(5);  		} -	} else if (filterout_non_associated_bssid == false) { +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, +					      (u8 *) (®_rcr)); +		_rtl92cu_set_bcn_ctrl_reg(hw, 0, tmp); +	} else { +		u8 tmp;  		if (IS_NORMAL_CHIP(rtlhal->version)) { -			reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN)); -			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, -						      (u8 *)(®_rcr)); -			_rtl92cu_set_bcn_ctrl_reg(hw, BIT(4), 0); +			reg_rcr &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN); +			tmp = BIT(4);  		} else { -			reg_rcr &= (~RCR_CBSSID); -			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, -						      (u8 *)(®_rcr)); -			_rtl92cu_set_bcn_ctrl_reg(hw, (BIT(4)|BIT(5)), 0); +			reg_rcr &= ~RCR_CBSSID; +			tmp = BIT(4) | BIT(5);  		} +		reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN)); +		rtlpriv->cfg->ops->set_hw_reg(hw, +					      HW_VAR_RCR, (u8 *) (®_rcr)); +		_rtl92cu_set_bcn_ctrl_reg(hw, tmp, 0);  	}  } +/*========================================================================== */ +  int rtl92cu_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type)  { +	struct rtl_priv *rtlpriv = rtl_priv(hw); +  	if (_rtl92cu_set_media_status(hw, type))  		return -EOPNOTSUPP; -	_rtl92cu_set_check_bssid(hw, type); + +	if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { +		if (type != NL80211_IFTYPE_AP) +			rtl92cu_set_check_bssid(hw, true); +	} else { +		rtl92cu_set_check_bssid(hw, false); +	} +  	return 0;  } @@ -2058,8 +2041,6 @@ void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,  			       (shortgi_rate << 4) | (shortgi_rate);  	}  	rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value); -	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, "%x\n", -		 rtl_read_dword(rtlpriv, REG_ARFR0));  }  void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 156b52732f3..5847d6d0881 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -851,6 +851,7 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb,  	if (unlikely(!_urb)) {  		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,  			 "Can't allocate urb. Drop skb!\n"); +		kfree_skb(skb);  		return;  	}  	_rtl_submit_tx_urb(hw, _urb); diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 730186d0449..38d2089f338 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -2013,19 +2013,7 @@ static struct pcmcia_driver wl3501_driver = {  	.suspend	= wl3501_suspend,  	.resume		= wl3501_resume,  }; - -static int __init wl3501_init_module(void) -{ -	return pcmcia_register_driver(&wl3501_driver); -} - -static void __exit wl3501_exit_module(void) -{ -	pcmcia_unregister_driver(&wl3501_driver); -} - -module_init(wl3501_init_module); -module_exit(wl3501_exit_module); +module_pcmcia_driver(wl3501_driver);  MODULE_AUTHOR("Fox Chen <mhchen@golf.ccl.itri.org.tw>, "  	      "Arnaldo Carvalho de Melo <acme@conectiva.com.br>,"  |