diff options
Diffstat (limited to 'drivers/net')
524 files changed, 18860 insertions, 896 deletions
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index b6de7b1e2a5..3ea42ff1765 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -117,7 +117,6 @@ static const char version[] =  #include <linux/fcntl.h>  #include <linux/ioport.h>  #include <linux/interrupt.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/spinlock.h> diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index 04b5bba1902..29b8d1d63bd 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -102,12 +102,12 @@  #include <linux/interrupt.h>  #include <linux/errno.h>  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/ioport.h>  #include <linux/spinlock.h>  #include <linux/ethtool.h>  #include <linux/delay.h>  #include <linux/bitops.h> +#include <linux/gfp.h>  #include <asm/uaccess.h>  #include <asm/io.h> diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index 77cf0901a44..b32b7a1710b 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -58,7 +58,6 @@ static const char version[] =  #include <linux/etherdevice.h>  #include <linux/if_ether.h>  #include <linux/skbuff.h> -#include <linux/slab.h>  #include <linux/init.h>  #include <linux/bitops.h> diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 902435a7646..ab9bb3c5200 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -76,7 +76,6 @@  #include <linux/interrupt.h>  #include <linux/errno.h>  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/ioport.h>  #include <linux/init.h>  #include <linux/netdevice.h> diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 1e898b1c806..2e17837be54 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -65,7 +65,6 @@ static int max_interrupt_work = 20;  #include <linux/errno.h>  #include <linux/in.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/skbuff.h>  #include <linux/etherdevice.h>  #include <linux/interrupt.h> diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index beed4fa10c6..1719079cc49 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -99,7 +99,6 @@  #include <linux/errno.h>  #include <linux/ioport.h>  #include <linux/skbuff.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/delay.h>  #include <linux/mca-legacy.h> diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index f965431f492..5f92fdbe66e 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -77,7 +77,6 @@ static int vortex_debug = 1;  #include <linux/errno.h>  #include <linux/in.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/pci.h>  #include <linux/mii.h> @@ -90,6 +89,7 @@ static int vortex_debug = 1;  #include <linux/eisa.h>  #include <linux/bitops.h>  #include <linux/jiffies.h> +#include <linux/gfp.h>  #include <asm/irq.h>			/* For nr_irqs only. */  #include <asm/io.h>  #include <asm/uaccess.h> diff --git a/drivers/net/7990.c b/drivers/net/7990.c index 4e9a5a20b6a..500e135723b 100644 --- a/drivers/net/7990.c +++ b/drivers/net/7990.c @@ -26,7 +26,6 @@  #include <linux/ioport.h>  #include <linux/in.h>  #include <linux/route.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/skbuff.h>  #include <asm/irq.h> diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 3d4406b1665..a09e6ce3eaa 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -64,6 +64,7 @@  #include <linux/dma-mapping.h>  #include <linux/delay.h>  #include <linux/ethtool.h> +#include <linux/gfp.h>  #include <linux/mii.h>  #include <linux/if_vlan.h>  #include <linux/crc32.h> diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index b4efc913978..f0d23de3296 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -110,6 +110,7 @@  #include <linux/crc32.h>  #include <linux/io.h>  #include <linux/uaccess.h> +#include <linux/gfp.h>  #include <asm/irq.h>  #define RTL8139_DRIVER_NAME   DRV_NAME " Fast Ethernet driver " DRV_VERSION @@ -1943,7 +1944,7 @@ static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp,  		netif_dbg(tp, rx_status, dev, "%s() status %04x, size %04x, cur %04x\n",  			  __func__, rx_status, rx_size, cur_rx);  #if RTL8139_DEBUG > 2 -		print_dump_hex(KERN_DEBUG, "Frame contents: ", +		print_hex_dump(KERN_DEBUG, "Frame contents: ",  			       DUMP_PREFIX_OFFSET, 16, 1,  			       &rx_ring[ring_offset], 70, true);  #endif diff --git a/drivers/net/82596.c b/drivers/net/82596.c index f94d17d78bb..56e68db4886 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -45,7 +45,6 @@  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/delay.h>  #include <linux/netdevice.h> @@ -53,6 +52,7 @@  #include <linux/skbuff.h>  #include <linux/init.h>  #include <linux/bitops.h> +#include <linux/gfp.h>  #include <asm/io.h>  #include <asm/dma.h> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 0ba5b8e50a7..7b832c727f8 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2582,6 +2582,31 @@ config CHELSIO_T3  	  To compile this driver as a module, choose M here: the module  	  will be called cxgb3. +config CHELSIO_T4_DEPENDS +	tristate +	depends on PCI && INET +	default y + +config CHELSIO_T4 +	tristate "Chelsio Communications T4 Ethernet support" +	depends on CHELSIO_T4_DEPENDS +	select FW_LOADER +	select MDIO +	help +	  This driver supports Chelsio T4-based gigabit and 10Gb Ethernet +	  adapters. + +	  For general information about Chelsio and our products, visit +	  our website at <http://www.chelsio.com>. + +	  For customer support, please visit our customer support page at +	  <http://www.chelsio.com/support.htm>. + +	  Please send feedback to <linux-bugs@chelsio.com>. + +	  To compile this driver as a module choose M here; the module +	  will be called cxgb4. +  config EHEA  	tristate "eHEA Ethernet support"  	depends on IBMEBUS && INET && SPARSEMEM diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 478886234c2..12b280afdd5 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_IXGB) += ixgb/  obj-$(CONFIG_IP1000) += ipg.o  obj-$(CONFIG_CHELSIO_T1) += chelsio/  obj-$(CONFIG_CHELSIO_T3) += cxgb3/ +obj-$(CONFIG_CHELSIO_T4) += cxgb4/  obj-$(CONFIG_EHEA) += ehea/  obj-$(CONFIG_CAN) += can/  obj-$(CONFIG_BONDING) += bonding/ @@ -272,6 +273,7 @@ obj-$(CONFIG_USB_RTL8150)       += usb/  obj-$(CONFIG_USB_HSO)		+= usb/  obj-$(CONFIG_USB_USBNET)        += usb/  obj-$(CONFIG_USB_ZD1201)        += usb/ +obj-$(CONFIG_USB_IPHETH)        += usb/  obj-y += wireless/  obj-$(CONFIG_NET_TULIP) += tulip/ diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index bd4d829eca1..ed5e9742be2 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -46,7 +46,6 @@  #include <linux/interrupt.h>  #include <linux/ioport.h>  #include <linux/skbuff.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/init.h>  #include <linux/crc32.h> diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 4ae750ef1e1..97a3dfd94df 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -67,6 +67,7 @@  #include <linux/highmem.h>  #include <linux/sockios.h>  #include <linux/firmware.h> +#include <linux/slab.h>  #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)  #include <linux/if_vlan.h> diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index b8a59d255b4..8d58f0a8f42 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -73,7 +73,6 @@ Revision History:  #include <linux/kernel.h>  #include <linux/types.h>  #include <linux/compiler.h> -#include <linux/slab.h>  #include <linux/delay.h>  #include <linux/init.h>  #include <linux/ioport.h> diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index 73b38c204eb..6f8d6206b5c 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -56,7 +56,6 @@ static const char *version =  #include <linux/ptrace.h>  #include <linux/ioport.h>  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/init.h> diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index eb0448b03f4..79636ee3582 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -31,6 +31,7 @@  #include <linux/ip.h>  #include <linux/atalk.h>  #include <linux/if_arp.h> +#include <linux/slab.h>  #include <net/route.h>  #include <asm/uaccess.h> diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c index 8ea4ec705be..6af65b656f3 100644 --- a/drivers/net/appletalk/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -215,7 +215,6 @@ static int dma;  #include <linux/ioport.h>  #include <linux/spinlock.h>  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/init.h> @@ -228,6 +227,7 @@ static int dma;  #include <linux/timer.h>  #include <linux/atalk.h>  #include <linux/bitops.h> +#include <linux/gfp.h>  #include <asm/system.h>  #include <asm/dma.h> diff --git a/drivers/net/arcnet/arc-rawmode.c b/drivers/net/arcnet/arc-rawmode.c index 8ea9c7545c1..705e6ce2eb9 100644 --- a/drivers/net/arcnet/arc-rawmode.c +++ b/drivers/net/arcnet/arc-rawmode.c @@ -25,6 +25,7 @@   */  #include <linux/module.h> +#include <linux/gfp.h>  #include <linux/init.h>  #include <linux/if_arp.h>  #include <net/arp.h> diff --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c index e6afab2455b..9efbbbae47c 100644 --- a/drivers/net/arcnet/arc-rimi.c +++ b/drivers/net/arcnet/arc-rimi.c @@ -28,7 +28,6 @@  #include <linux/module.h>  #include <linux/moduleparam.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/delay.h>  #include <linux/netdevice.h>  #include <linux/bootmem.h> diff --git a/drivers/net/arcnet/capmode.c b/drivers/net/arcnet/capmode.c index 66bcbbb6bab..355797f7004 100644 --- a/drivers/net/arcnet/capmode.c +++ b/drivers/net/arcnet/capmode.c @@ -27,6 +27,7 @@   */  #include <linux/module.h> +#include <linux/gfp.h>  #include <linux/init.h>  #include <linux/if_arp.h>  #include <net/arp.h> diff --git a/drivers/net/arcnet/com20020-isa.c b/drivers/net/arcnet/com20020-isa.c index db08fc24047..0402da30a4e 100644 --- a/drivers/net/arcnet/com20020-isa.c +++ b/drivers/net/arcnet/com20020-isa.c @@ -30,7 +30,6 @@  #include <linux/kernel.h>  #include <linux/types.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/errno.h>  #include <linux/delay.h>  #include <linux/netdevice.h> diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index b68e1eb405f..2c712af6c26 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -31,7 +31,6 @@  #include <linux/kernel.h>  #include <linux/types.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/errno.h>  #include <linux/netdevice.h>  #include <linux/init.h> diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c index 0a74f21409c..c9e459400ff 100644 --- a/drivers/net/arcnet/com20020.c +++ b/drivers/net/arcnet/com20020.c @@ -29,7 +29,6 @@  #include <linux/kernel.h>  #include <linux/types.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/errno.h>  #include <linux/delay.h>  #include <linux/netdevice.h> diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c index 28dea518d55..4cb401813b7 100644 --- a/drivers/net/arcnet/com90io.c +++ b/drivers/net/arcnet/com90io.c @@ -29,7 +29,6 @@  #include <linux/module.h>  #include <linux/moduleparam.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/delay.h>  #include <linux/netdevice.h>  #include <linux/bootmem.h> diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c index 112e230cb13..f3b46f71e29 100644 --- a/drivers/net/arcnet/com90xx.c +++ b/drivers/net/arcnet/com90xx.c @@ -30,6 +30,7 @@  #include <linux/ioport.h>  #include <linux/delay.h>  #include <linux/netdevice.h> +#include <linux/slab.h>  #include <asm/io.h>  #include <linux/arcdevice.h> diff --git a/drivers/net/arcnet/rfc1051.c b/drivers/net/arcnet/rfc1051.c index 06f8fa2f8f2..f81db4070a5 100644 --- a/drivers/net/arcnet/rfc1051.c +++ b/drivers/net/arcnet/rfc1051.c @@ -24,6 +24,7 @@   * **********************   */  #include <linux/module.h> +#include <linux/gfp.h>  #include <linux/init.h>  #include <linux/if_arp.h>  #include <net/arp.h> diff --git a/drivers/net/arcnet/rfc1201.c b/drivers/net/arcnet/rfc1201.c index 745530651c4..b71431aae08 100644 --- a/drivers/net/arcnet/rfc1201.c +++ b/drivers/net/arcnet/rfc1201.c @@ -23,6 +23,7 @@   *   * **********************   */ +#include <linux/gfp.h>  #include <linux/module.h>  #include <linux/init.h>  #include <linux/if_arp.h> diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index 08d8be47dae..fa1a2354f5f 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -40,7 +40,6 @@  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/netdevice.h>  #include <linux/etherdevice.h>  #include <linux/interrupt.h> diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index 8b23d5a175b..aed5b5479b5 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -27,6 +27,7 @@  #include <linux/ethtool.h>  #include <linux/platform_device.h>  #include <linux/clk.h> +#include <linux/gfp.h>  #include <asm/io.h>  #include <asm/uaccess.h> diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index bf72d57a0af..cd17d09f385 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -23,6 +23,7 @@  #include <linux/platform_device.h>  #include <linux/delay.h>  #include <linux/io.h> +#include <linux/slab.h>  #include <mach/hardware.h> @@ -310,11 +311,6 @@ err:  		processed++;  	} -	if (processed) { -		wrw(ep, REG_RXDENQ, processed); -		wrw(ep, REG_RXSTSENQ, processed); -	} -  	return processed;  } @@ -349,6 +345,11 @@ poll_some_more:  			goto poll_some_more;  	} +	if (rx) { +		wrw(ep, REG_RXDENQ, rx); +		wrw(ep, REG_RXSTSENQ, rx); +	} +  	return rx;  } diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index f52f668c49b..4af235d41fd 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -33,7 +33,6 @@  #include <linux/interrupt.h>  #include <linux/ioport.h>  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/netdevice.h> diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c index 6e2ae1d06df..6be8b098b8b 100644 --- a/drivers/net/arm/ixp4xx_eth.c +++ b/drivers/net/arm/ixp4xx_eth.c @@ -32,6 +32,7 @@  #include <linux/kernel.h>  #include <linux/phy.h>  #include <linux/platform_device.h> +#include <linux/slab.h>  #include <mach/npe.h>  #include <mach/qmgr.h> diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c index a1d4188c430..84f8a8f7380 100644 --- a/drivers/net/arm/ks8695net.c +++ b/drivers/net/arm/ks8695net.c @@ -30,6 +30,7 @@  #include <linux/platform_device.h>  #include <linux/irq.h>  #include <linux/io.h> +#include <linux/slab.h>  #include <asm/irq.h> @@ -449,11 +450,10 @@ ks8695_rx_irq(int irq, void *dev_id)  }  /** - *	ks8695_rx - Receive packets  called by NAPI poll method + *	ks8695_rx - Receive packets called by NAPI poll method   *	@ksp: Private data for the KS8695 Ethernet - *	@budget: The max packets would be receive + *	@budget: Number of packets allowed to process   */ -  static int ks8695_rx(struct ks8695_priv *ksp, int budget)  {  	struct net_device *ndev = ksp->ndev; @@ -461,7 +461,6 @@ static int ks8695_rx(struct ks8695_priv *ksp, int budget)  	int buff_n;  	u32 flags;  	int pktlen; -	int last_rx_processed = -1;  	int received = 0;  	buff_n = ksp->next_rx_desc_read; @@ -471,6 +470,7 @@ static int ks8695_rx(struct ks8695_priv *ksp, int budget)  					cpu_to_le32(RDES_OWN)))) {  			rmb();  			flags = le32_to_cpu(ksp->rx_ring[buff_n].status); +  			/* Found an SKB which we own, this means we  			 * received a packet  			 */ @@ -533,23 +533,18 @@ rx_failure:  			ksp->rx_ring[buff_n].status = cpu_to_le32(RDES_OWN);  rx_finished:  			received++; -			/* And note this as processed so we can start -			 * from here next time -			 */ -			last_rx_processed = buff_n;  			buff_n = (buff_n + 1) & MAX_RX_DESC_MASK; -			/*And note which RX descriptor we last did */ -			if (likely(last_rx_processed != -1)) -				ksp->next_rx_desc_read = -					(last_rx_processed + 1) & -					MAX_RX_DESC_MASK;  	} + +	/* And note which RX descriptor we last did */ +	ksp->next_rx_desc_read = buff_n; +  	/* And refill the buffers */  	ks8695_refill_rxbuffers(ksp); -	/* Kick the RX DMA engine, in case it became -	 *  suspended */ +	/* Kick the RX DMA engine, in case it became suspended */  	ks8695_writereg(ksp, KS8695_DRSC, 0); +  	return received;  } diff --git a/drivers/net/arm/w90p910_ether.c b/drivers/net/arm/w90p910_ether.c index febd813c916..f7c9ca1dfb1 100644 --- a/drivers/net/arm/w90p910_ether.c +++ b/drivers/net/arm/w90p910_ether.c @@ -18,6 +18,7 @@  #include <linux/ethtool.h>  #include <linux/platform_device.h>  #include <linux/clk.h> +#include <linux/gfp.h>  #define DRV_MODULE_NAME		"w90p910-emc"  #define DRV_MODULE_VERSION	"0.1" diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index 309843ab886..10a20fb9ae6 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -47,7 +47,6 @@  #include <linux/ioport.h>  #include <linux/in.h>  #include <linux/skbuff.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/init.h>  #include <linux/crc32.h> diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index 280cfff48b4..a8686bfec7a 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -53,7 +53,6 @@ static char version[] = "atarilance.c: v1.3 04/04/96 "  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/skbuff.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/init.h>  #include <linux/bitops.h> diff --git a/drivers/net/atl1c/atl1c_ethtool.c b/drivers/net/atl1c/atl1c_ethtool.c index 61a0f2ff11e..32339243d61 100644 --- a/drivers/net/atl1c/atl1c_ethtool.c +++ b/drivers/net/atl1c/atl1c_ethtool.c @@ -22,6 +22,7 @@  #include <linux/netdevice.h>  #include <linux/ethtool.h> +#include <linux/slab.h>  #include "atl1c.h" diff --git a/drivers/net/atl1e/atl1e_ethtool.c b/drivers/net/atl1e/atl1e_ethtool.c index a76006c1bc6..ffd696ee7c8 100644 --- a/drivers/net/atl1e/atl1e_ethtool.c +++ b/drivers/net/atl1e/atl1e_ethtool.c @@ -22,6 +22,7 @@  #include <linux/netdevice.h>  #include <linux/ethtool.h> +#include <linux/slab.h>  #include "atl1e.h" diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 9ba547069db..0ebd8208f60 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -84,7 +84,7 @@  #define ATLX_DRIVER_VERSION "2.1.3"  MODULE_AUTHOR("Xiong Huang <xiong.huang@atheros.com>, \ -	Chris Snook <csnook@redhat.com>, Jay Cliburn <jcliburn@gmail.com>"); +Chris Snook <csnook@redhat.com>, Jay Cliburn <jcliburn@gmail.com>");  MODULE_LICENSE("GPL");  MODULE_VERSION(ATLX_DRIVER_VERSION); diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c index 7061d7108f0..54662f24f9b 100644 --- a/drivers/net/atlx/atl2.c +++ b/drivers/net/atlx/atl2.c @@ -39,6 +39,7 @@  #include <linux/pci_ids.h>  #include <linux/pm.h>  #include <linux/skbuff.h> +#include <linux/slab.h>  #include <linux/spinlock.h>  #include <linux/string.h>  #include <linux/tcp.h> diff --git a/drivers/net/atp.c b/drivers/net/atp.c index 6ad16205dc1..55039d44dc4 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -129,7 +129,6 @@ static int xcvr[NUM_UNITS]; 			/* The data transfer mode. */  #include <linux/interrupt.h>  #include <linux/ioport.h>  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/init.h> diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c index 1dd4403247c..b718dc60afc 100644 --- a/drivers/net/ax88796.c +++ b/drivers/net/ax88796.c @@ -25,6 +25,7 @@  #include <linux/ethtool.h>  #include <linux/mii.h>  #include <linux/eeprom_93cx6.h> +#include <linux/slab.h>  #include <net/ax88796.h> diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 332c6035628..69d9f3d368a 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -27,6 +27,7 @@  #include <linux/init.h>  #include <linux/dma-mapping.h>  #include <linux/ssb/ssb.h> +#include <linux/slab.h>  #include <asm/uaccess.h>  #include <asm/io.h> diff --git a/drivers/net/bcm63xx_enet.c b/drivers/net/bcm63xx_enet.c index 8cdcab7655c..17460aba3ba 100644 --- a/drivers/net/bcm63xx_enet.c +++ b/drivers/net/bcm63xx_enet.c @@ -21,6 +21,7 @@  #include <linux/module.h>  #include <linux/clk.h>  #include <linux/etherdevice.h> +#include <linux/slab.h>  #include <linux/delay.h>  #include <linux/ethtool.h>  #include <linux/crc32.h> diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 8f075255368..56387b191c9 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -29,6 +29,7 @@  #include <linux/workqueue.h>  #include <linux/interrupt.h>  #include <linux/firmware.h> +#include <linux/slab.h>  #include "be_hw.h" diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index c59215361f4..d0ef4ac987c 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -673,7 +673,7 @@ int be_cmd_mccq_create(struct be_adapter *adapter,  	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,  			OPCODE_COMMON_MCC_CREATE, sizeof(*req)); -	req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size); +	req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));  	AMAP_SET_BITS(struct amap_mcc_context, valid, ctxt, 1);  	AMAP_SET_BITS(struct amap_mcc_context, ring_size, ctxt, @@ -1464,8 +1464,8 @@ int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,  	req->params.op_type = cpu_to_le32(IMG_TYPE_REDBOOT);  	req->params.op_code = cpu_to_le32(FLASHROM_OPER_REPORT); -	req->params.offset = offset; -	req->params.data_buf_size = 0x4; +	req->params.offset = cpu_to_le32(offset); +	req->params.data_buf_size = cpu_to_le32(0x4);  	status = be_mcc_notify_wait(adapter);  	if (!status) diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index 9560d48944a..51e1065e789 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -490,7 +490,7 @@ be_test_ddr_dma(struct be_adapter *adapter)  {  	int ret, i;  	struct be_dma_mem ddrdma_cmd; -	u64 pattern[2] = {0x5a5a5a5a5a5a5a5a, 0xa5a5a5a5a5a5a5a5}; +	u64 pattern[2] = {0x5a5a5a5a5a5a5a5aULL, 0xa5a5a5a5a5a5a5a5ULL};  	ddrdma_cmd.size = sizeof(struct be_cmd_req_ddrdma_test);  	ddrdma_cmd.va = pci_alloc_consistent(adapter->pdev, ddrdma_cmd.size, diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 43e8032f923..ec6ace80225 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -807,7 +807,7 @@ static void be_rx_compl_process(struct be_adapter *adapter,  			return;  		}  		vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp); -		vid = be16_to_cpu(vid); +		vid = swab16(vid);  		vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, vid);  	} else {  		netif_receive_skb(skb); @@ -884,7 +884,7 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,  		napi_gro_frags(&eq_obj->napi);  	} else {  		vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp); -		vid = be16_to_cpu(vid); +		vid = swab16(vid);  		if (!adapter->vlan_grp || adapter->vlans_added == 0)  			return; @@ -1855,7 +1855,7 @@ static bool be_flash_redboot(struct be_adapter *adapter,  	p += crc_offset;  	status = be_cmd_get_flash_crc(adapter, flashed_crc, -			(img_start + image_size - 4)); +			(image_size - 4));  	if (status) {  		dev_err(&adapter->pdev->dev,  		"could not get crc from flash, not flashing redboot\n"); @@ -1991,7 +1991,7 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)  	struct flash_file_hdr_g3 *fhdr3;  	struct image_hdr *img_hdr_ptr = NULL;  	struct be_dma_mem flash_cmd; -	int status, i = 0; +	int status, i = 0, num_imgs = 0;  	const u8 *p;  	strcpy(fw_file, func); @@ -2017,15 +2017,14 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)  	if ((adapter->generation == BE_GEN3) &&  			(get_ufigen_type(fhdr) == BE_GEN3)) {  		fhdr3 = (struct flash_file_hdr_g3 *) fw->data; -		for (i = 0; i < fhdr3->num_imgs; i++) { +		num_imgs = le32_to_cpu(fhdr3->num_imgs); +		for (i = 0; i < num_imgs; i++) {  			img_hdr_ptr = (struct image_hdr *) (fw->data +  					(sizeof(struct flash_file_hdr_g3) + -					i * sizeof(struct image_hdr))); -			if (img_hdr_ptr->imageid == 1) { -				status = be_flash_data(adapter, fw, -						&flash_cmd, fhdr3->num_imgs); -			} - +					 i * sizeof(struct image_hdr))); +			if (le32_to_cpu(img_hdr_ptr->imageid) == 1) +				status = be_flash_data(adapter, fw, &flash_cmd, +							num_imgs);  		}  	} else if ((adapter->generation == BE_GEN2) &&  			(get_ufigen_type(fhdr) == BE_GEN2)) { diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 119468e7632..598b007f199 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -20,6 +20,7 @@  #include <linux/crc32.h>  #include <linux/bitrev.h>  #include <linux/ethtool.h> +#include <linux/slab.h>  #include <asm/prom.h>  #include <asm/dbdma.h>  #include <asm/io.h> diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 381887ba677..ac90a3828f6 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -58,8 +58,8 @@  #include "bnx2_fw.h"  #define DRV_MODULE_NAME		"bnx2" -#define DRV_MODULE_VERSION	"2.0.8" -#define DRV_MODULE_RELDATE	"Feb 15, 2010" +#define DRV_MODULE_VERSION	"2.0.9" +#define DRV_MODULE_RELDATE	"April 27, 2010"  #define FW_MIPS_FILE_06		"bnx2/bnx2-mips-06-5.0.0.j6.fw"  #define FW_RV2P_FILE_06		"bnx2/bnx2-rv2p-06-5.0.0.j3.fw"  #define FW_MIPS_FILE_09		"bnx2/bnx2-mips-09-5.0.0.j9.fw" @@ -246,6 +246,8 @@ static const struct flash_spec flash_5709 = {  MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl); +static void bnx2_init_napi(struct bnx2 *bp); +  static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr)  {  	u32 diff; @@ -649,9 +651,10 @@ bnx2_napi_enable(struct bnx2 *bp)  }  static void -bnx2_netif_stop(struct bnx2 *bp) +bnx2_netif_stop(struct bnx2 *bp, bool stop_cnic)  { -	bnx2_cnic_stop(bp); +	if (stop_cnic) +		bnx2_cnic_stop(bp);  	if (netif_running(bp->dev)) {  		int i; @@ -669,14 +672,15 @@ bnx2_netif_stop(struct bnx2 *bp)  }  static void -bnx2_netif_start(struct bnx2 *bp) +bnx2_netif_start(struct bnx2 *bp, bool start_cnic)  {  	if (atomic_dec_and_test(&bp->intr_sem)) {  		if (netif_running(bp->dev)) {  			netif_tx_wake_all_queues(bp->dev);  			bnx2_napi_enable(bp);  			bnx2_enable_int(bp); -			bnx2_cnic_start(bp); +			if (start_cnic) +				bnx2_cnic_start(bp);  		}  	}  } @@ -4757,8 +4761,12 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)  		rc = bnx2_alloc_bad_rbuf(bp);  	} -	if (bp->flags & BNX2_FLAG_USING_MSIX) +	if (bp->flags & BNX2_FLAG_USING_MSIX) {  		bnx2_setup_msix_tbl(bp); +		/* Prevent MSIX table reads and write from timing out */ +		REG_WR(bp, BNX2_MISC_ECO_HW_CTL, +			BNX2_MISC_ECO_HW_CTL_LARGE_GRC_TMOUT_EN); +	}  	return rc;  } @@ -6197,6 +6205,7 @@ bnx2_open(struct net_device *dev)  	bnx2_disable_int(bp);  	bnx2_setup_int_mode(bp, disable_msi); +	bnx2_init_napi(bp);  	bnx2_napi_enable(bp);  	rc = bnx2_alloc_mem(bp);  	if (rc) @@ -6270,12 +6279,12 @@ bnx2_reset_task(struct work_struct *work)  		return;  	} -	bnx2_netif_stop(bp); +	bnx2_netif_stop(bp, true);  	bnx2_init_nic(bp, 1);  	atomic_set(&bp->intr_sem, 1); -	bnx2_netif_start(bp); +	bnx2_netif_start(bp, true);  	rtnl_unlock();  } @@ -6317,7 +6326,7 @@ bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp)  	struct bnx2 *bp = netdev_priv(dev);  	if (netif_running(dev)) -		bnx2_netif_stop(bp); +		bnx2_netif_stop(bp, false);  	bp->vlgrp = vlgrp; @@ -6328,7 +6337,7 @@ bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp)  	if (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN)  		bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1); -	bnx2_netif_start(bp); +	bnx2_netif_start(bp, false);  }  #endif @@ -7048,9 +7057,9 @@ bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)  	bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;  	if (netif_running(bp->dev)) { -		bnx2_netif_stop(bp); +		bnx2_netif_stop(bp, true);  		bnx2_init_nic(bp, 0); -		bnx2_netif_start(bp); +		bnx2_netif_start(bp, true);  	}  	return 0; @@ -7080,7 +7089,7 @@ bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx)  		/* Reset will erase chipset stats; save them */  		bnx2_save_stats(bp); -		bnx2_netif_stop(bp); +		bnx2_netif_stop(bp, true);  		bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);  		bnx2_free_skbs(bp);  		bnx2_free_mem(bp); @@ -7108,7 +7117,7 @@ bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx)  			bnx2_setup_cnic_irq_info(bp);  		mutex_unlock(&bp->cnic_lock);  #endif -		bnx2_netif_start(bp); +		bnx2_netif_start(bp, true);  	}  	return 0;  } @@ -7361,7 +7370,7 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)  	if (etest->flags & ETH_TEST_FL_OFFLINE) {  		int i; -		bnx2_netif_stop(bp); +		bnx2_netif_stop(bp, true);  		bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG);  		bnx2_free_skbs(bp); @@ -7380,7 +7389,7 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)  			bnx2_shutdown_chip(bp);  		else {  			bnx2_init_nic(bp, 1); -			bnx2_netif_start(bp); +			bnx2_netif_start(bp, true);  		}  		/* wait for link up */ @@ -7643,9 +7652,11 @@ poll_bnx2(struct net_device *dev)  	int i;  	for (i = 0; i < bp->irq_nvecs; i++) { -		disable_irq(bp->irq_tbl[i].vector); -		bnx2_interrupt(bp->irq_tbl[i].vector, &bp->bnx2_napi[i]); -		enable_irq(bp->irq_tbl[i].vector); +		struct bnx2_irq *irq = &bp->irq_tbl[i]; + +		disable_irq(irq->vector); +		irq->handler(irq->vector, &bp->bnx2_napi[i]); +		enable_irq(irq->vector);  	}  }  #endif @@ -8207,7 +8218,7 @@ bnx2_init_napi(struct bnx2 *bp)  {  	int i; -	for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) { +	for (i = 0; i < bp->irq_nvecs; i++) {  		struct bnx2_napi *bnapi = &bp->bnx2_napi[i];  		int (*poll)(struct napi_struct *, int); @@ -8276,7 +8287,6 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  	dev->ethtool_ops = &bnx2_ethtool_ops;  	bp = netdev_priv(dev); -	bnx2_init_napi(bp);  	pci_set_drvdata(pdev, dev); @@ -8373,7 +8383,7 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state)  		return 0;  	flush_scheduled_work(); -	bnx2_netif_stop(bp); +	bnx2_netif_stop(bp, true);  	netif_device_detach(dev);  	del_timer_sync(&bp->timer);  	bnx2_shutdown_chip(bp); @@ -8395,7 +8405,7 @@ bnx2_resume(struct pci_dev *pdev)  	bnx2_set_power_state(bp, PCI_D0);  	netif_device_attach(dev);  	bnx2_init_nic(bp, 1); -	bnx2_netif_start(bp); +	bnx2_netif_start(bp, true);  	return 0;  } @@ -8422,7 +8432,7 @@ static pci_ers_result_t bnx2_io_error_detected(struct pci_dev *pdev,  	}  	if (netif_running(dev)) { -		bnx2_netif_stop(bp); +		bnx2_netif_stop(bp, true);  		del_timer_sync(&bp->timer);  		bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);  	} @@ -8479,7 +8489,7 @@ static void bnx2_io_resume(struct pci_dev *pdev)  	rtnl_lock();  	if (netif_running(dev)) -		bnx2_netif_start(bp); +		bnx2_netif_start(bp, true);  	netif_device_attach(dev);  	rtnl_unlock(); diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index ed785a30e98..6c042a72d6c 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -893,7 +893,6 @@ static inline u16 bnx2x_tx_avail(struct bnx2x_fastpath *fp)  	u16 prod;  	u16 cons; -	barrier(); /* Tell compiler that prod and cons can change */  	prod = fp->tx_bd_prod;  	cons = fp->tx_bd_cons; @@ -963,7 +962,7 @@ static int bnx2x_tx_int(struct bnx2x_fastpath *fp)  	 * start_xmit() will miss it and cause the queue to be stopped  	 * forever.  	 */ -	smp_wmb(); +	smp_mb();  	/* TBD need a thresh? */  	if (unlikely(netif_tx_queue_stopped(txq))) { @@ -11429,9 +11428,12 @@ static netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)  	if (unlikely(bnx2x_tx_avail(fp) < MAX_SKB_FRAGS + 3)) {  		netif_tx_stop_queue(txq); -		/* We want bnx2x_tx_int to "see" the updated tx_bd_prod -		   if we put Tx into XOFF state. */ + +		/* paired memory barrier is in bnx2x_tx_int(), we have to keep +		 * ordering of set_bit() in netif_tx_stop_queue() and read of +		 * fp->bd_tx_cons */  		smp_mb(); +  		fp->eth_q_stats.driver_xoff++;  		if (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3)  			netif_tx_wake_queue(txq); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 430c02267d7..0075514bf32 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1235,6 +1235,11 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)  			write_lock_bh(&bond->curr_slave_lock);  		}  	} + +	/* resend IGMP joins since all were sent on curr_active_slave */ +	if (bond->params.mode == BOND_MODE_ROUNDROBIN) { +		bond_resend_igmp_join_requests(bond); +	}  }  /** @@ -4138,22 +4143,41 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev  	struct bonding *bond = netdev_priv(bond_dev);  	struct slave *slave, *start_at;  	int i, slave_no, res = 1; +	struct iphdr *iph = ip_hdr(skb);  	read_lock(&bond->lock);  	if (!BOND_IS_OK(bond))  		goto out; -  	/* -	 * Concurrent TX may collide on rr_tx_counter; we accept that -	 * as being rare enough not to justify using an atomic op here +	 * Start with the curr_active_slave that joined the bond as the +	 * default for sending IGMP traffic.  For failover purposes one +	 * needs to maintain some consistency for the interface that will +	 * send the join/membership reports.  The curr_active_slave found +	 * will send all of this type of traffic.  	 */ -	slave_no = bond->rr_tx_counter++ % bond->slave_cnt; +	if ((iph->protocol == IPPROTO_IGMP) && +	    (skb->protocol == htons(ETH_P_IP))) { -	bond_for_each_slave(bond, slave, i) { -		slave_no--; -		if (slave_no < 0) -			break; +		read_lock(&bond->curr_slave_lock); +		slave = bond->curr_active_slave; +		read_unlock(&bond->curr_slave_lock); + +		if (!slave) +			goto out; +	} else { +		/* +		 * Concurrent TX may collide on rr_tx_counter; we accept +		 * that as being rare enough not to justify using an +		 * atomic op here. +		 */ +		slave_no = bond->rr_tx_counter++ % bond->slave_cnt; + +		bond_for_each_slave(bond, slave, i) { +			slave_no--; +			if (slave_no < 0) +				break; +		}  	}  	start_at = slave; @@ -4426,6 +4450,14 @@ static const struct net_device_ops bond_netdev_ops = {  	.ndo_vlan_rx_kill_vid	= bond_vlan_rx_kill_vid,  }; +static void bond_destructor(struct net_device *bond_dev) +{ +	struct bonding *bond = netdev_priv(bond_dev); +	if (bond->wq) +		destroy_workqueue(bond->wq); +	free_netdev(bond_dev); +} +  static void bond_setup(struct net_device *bond_dev)  {  	struct bonding *bond = netdev_priv(bond_dev); @@ -4446,7 +4478,7 @@ static void bond_setup(struct net_device *bond_dev)  	bond_dev->ethtool_ops = &bond_ethtool_ops;  	bond_set_mode_ops(bond, bond->params.mode); -	bond_dev->destructor = free_netdev; +	bond_dev->destructor = bond_destructor;  	/* Initialize the device options */  	bond_dev->tx_queue_len = 0; @@ -4518,9 +4550,6 @@ static void bond_uninit(struct net_device *bond_dev)  	bond_remove_proc_entry(bond); -	if (bond->wq) -		destroy_workqueue(bond->wq); -  	netif_addr_lock_bh(bond_dev);  	bond_mc_list_destroy(bond);  	netif_addr_unlock_bh(bond_dev); @@ -4932,8 +4961,8 @@ int bond_create(struct net *net, const char *name)  				bond_setup);  	if (!bond_dev) {  		pr_err("%s: eek! can't alloc netdev!\n", name); -		res = -ENOMEM; -		goto out; +		rtnl_unlock(); +		return -ENOMEM;  	}  	dev_net_set(bond_dev, net); @@ -4942,19 +4971,16 @@ int bond_create(struct net *net, const char *name)  	if (!name) {  		res = dev_alloc_name(bond_dev, "bond%d");  		if (res < 0) -			goto out_netdev; +			goto out;  	}  	res = register_netdevice(bond_dev); -	if (res < 0) -		goto out_netdev;  out:  	rtnl_unlock(); +	if (res < 0) +		bond_destructor(bond_dev);  	return res; -out_netdev: -	free_netdev(bond_dev); -	goto out;  }  static int __net_init bond_net_init(struct net *net) diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c index 866905fa411..03489864376 100644 --- a/drivers/net/can/bfin_can.c +++ b/drivers/net/can/bfin_can.c @@ -22,6 +22,7 @@  #include <linux/can/dev.h>  #include <linux/can/error.h> +#include <asm/bfin_can.h>  #include <asm/portmux.h>  #define DRV_NAME "bfin_can" @@ -29,90 +30,6 @@  #define TX_ECHO_SKB_MAX  1  /* - * transmit and receive channels - */ -#define TRANSMIT_CHL            24 -#define RECEIVE_STD_CHL         0 -#define RECEIVE_EXT_CHL         4 -#define RECEIVE_RTR_CHL         8 -#define RECEIVE_EXT_RTR_CHL     12 -#define MAX_CHL_NUMBER          32 - -/* - * bfin can registers layout - */ -struct bfin_can_mask_regs { -	u16 aml; -	u16 dummy1; -	u16 amh; -	u16 dummy2; -}; - -struct bfin_can_channel_regs { -	u16 data[8]; -	u16 dlc; -	u16 dummy1; -	u16 tsv; -	u16 dummy2; -	u16 id0; -	u16 dummy3; -	u16 id1; -	u16 dummy4; -}; - -struct bfin_can_regs { -	/* -	 * global control and status registers -	 */ -	u16 mc1;           /* offset 0 */ -	u16 dummy1; -	u16 md1;           /* offset 4 */ -	u16 rsv1[13]; -	u16 mbtif1;        /* offset 0x20 */ -	u16 dummy2; -	u16 mbrif1;        /* offset 0x24 */ -	u16 dummy3; -	u16 mbim1;         /* offset 0x28 */ -	u16 rsv2[11]; -	u16 mc2;           /* offset 0x40 */ -	u16 dummy4; -	u16 md2;           /* offset 0x44 */ -	u16 dummy5; -	u16 trs2;          /* offset 0x48 */ -	u16 rsv3[11]; -	u16 mbtif2;        /* offset 0x60 */ -	u16 dummy6; -	u16 mbrif2;        /* offset 0x64 */ -	u16 dummy7; -	u16 mbim2;         /* offset 0x68 */ -	u16 rsv4[11]; -	u16 clk;           /* offset 0x80 */ -	u16 dummy8; -	u16 timing;        /* offset 0x84 */ -	u16 rsv5[3]; -	u16 status;        /* offset 0x8c */ -	u16 dummy9; -	u16 cec;           /* offset 0x90 */ -	u16 dummy10; -	u16 gis;           /* offset 0x94 */ -	u16 dummy11; -	u16 gim;           /* offset 0x98 */ -	u16 rsv6[3]; -	u16 ctrl;          /* offset 0xa0 */ -	u16 dummy12; -	u16 intr;          /* offset 0xa4 */ -	u16 rsv7[7]; -	u16 esr;           /* offset 0xb4 */ -	u16 rsv8[37]; - -	/* -	 * channel(mailbox) mask and message registers -	 */ -	struct bfin_can_mask_regs msk[MAX_CHL_NUMBER];    /* offset 0x100 */ -	struct bfin_can_channel_regs chl[MAX_CHL_NUMBER]; /* offset 0x200 */ -}; - -/*   * bfin can private data   */  struct bfin_can_priv { @@ -163,7 +80,7 @@ static int bfin_can_set_bittiming(struct net_device *dev)  	if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)  		timing |= SAM; -	bfin_write16(®->clk, clk); +	bfin_write16(®->clock, clk);  	bfin_write16(®->timing, timing);  	dev_info(dev->dev.parent, "setting CLOCK=0x%04x TIMING=0x%04x\n", @@ -185,11 +102,11 @@ static void bfin_can_set_reset_mode(struct net_device *dev)  	bfin_write16(®->gim, 0);  	/* reset can and enter configuration mode */ -	bfin_write16(®->ctrl, SRS | CCR); +	bfin_write16(®->control, SRS | CCR);  	SSYNC(); -	bfin_write16(®->ctrl, CCR); +	bfin_write16(®->control, CCR);  	SSYNC(); -	while (!(bfin_read16(®->ctrl) & CCA)) { +	while (!(bfin_read16(®->control) & CCA)) {  		udelay(10);  		if (--timeout == 0) {  			dev_err(dev->dev.parent, @@ -244,7 +161,7 @@ static void bfin_can_set_normal_mode(struct net_device *dev)  	/*  	 * leave configuration mode  	 */ -	bfin_write16(®->ctrl, bfin_read16(®->ctrl) & ~CCR); +	bfin_write16(®->control, bfin_read16(®->control) & ~CCR);  	while (bfin_read16(®->status) & CCA) {  		udelay(10); @@ -726,7 +643,7 @@ static int bfin_can_suspend(struct platform_device *pdev, pm_message_t mesg)  	if (netif_running(dev)) {  		/* enter sleep mode */ -		bfin_write16(®->ctrl, bfin_read16(®->ctrl) | SMR); +		bfin_write16(®->control, bfin_read16(®->control) | SMR);  		SSYNC();  		while (!(bfin_read16(®->intr) & SMACK)) {  			udelay(10); diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 904aa369f80..d0f8c7e67e7 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -19,6 +19,7 @@  #include <linux/module.h>  #include <linux/kernel.h> +#include <linux/slab.h>  #include <linux/netdevice.h>  #include <linux/if_arp.h>  #include <linux/can.h> diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index f8cc168ec76..b39b108318b 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -73,6 +73,7 @@  #include <linux/module.h>  #include <linux/netdevice.h>  #include <linux/platform_device.h> +#include <linux/slab.h>  #include <linux/spi/spi.h>  #include <linux/uaccess.h> diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c index 87300606abb..5f53da0bc40 100644 --- a/drivers/net/can/sja1000/ems_pci.c +++ b/drivers/net/can/sja1000/ems_pci.c @@ -22,6 +22,7 @@  #include <linux/interrupt.h>  #include <linux/netdevice.h>  #include <linux/delay.h> +#include <linux/slab.h>  #include <linux/pci.h>  #include <linux/can.h>  #include <linux/can/dev.h> diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c index 6b46a6395f8..4aff4070db9 100644 --- a/drivers/net/can/sja1000/plx_pci.c +++ b/drivers/net/can/sja1000/plx_pci.c @@ -25,6 +25,7 @@  #include <linux/interrupt.h>  #include <linux/netdevice.h>  #include <linux/delay.h> +#include <linux/slab.h>  #include <linux/pci.h>  #include <linux/can.h>  #include <linux/can/dev.h> diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index 33451092b8e..d800b598ae3 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -1006,7 +1006,7 @@ static int ems_usb_probe(struct usb_interface *intf,  	netdev = alloc_candev(sizeof(struct ems_usb), MAX_TX_URBS);  	if (!netdev) { -		dev_err(netdev->dev.parent, "Couldn't alloc candev\n"); +		dev_err(&intf->dev, "ems_usb: Couldn't alloc candev\n");  		return -ENOMEM;  	} @@ -1036,20 +1036,20 @@ static int ems_usb_probe(struct usb_interface *intf,  	dev->intr_urb = usb_alloc_urb(0, GFP_KERNEL);  	if (!dev->intr_urb) { -		dev_err(netdev->dev.parent, "Couldn't alloc intr URB\n"); +		dev_err(&intf->dev, "Couldn't alloc intr URB\n");  		goto cleanup_candev;  	}  	dev->intr_in_buffer = kzalloc(INTR_IN_BUFFER_SIZE, GFP_KERNEL);  	if (!dev->intr_in_buffer) { -		dev_err(netdev->dev.parent, "Couldn't alloc Intr buffer\n"); +		dev_err(&intf->dev, "Couldn't alloc Intr buffer\n");  		goto cleanup_intr_urb;  	}  	dev->tx_msg_buffer = kzalloc(CPC_HEADER_SIZE +  				     sizeof(struct ems_cpc_msg), GFP_KERNEL);  	if (!dev->tx_msg_buffer) { -		dev_err(netdev->dev.parent, "Couldn't alloc Tx buffer\n"); +		dev_err(&intf->dev, "Couldn't alloc Tx buffer\n");  		goto cleanup_intr_in_buffer;  	} diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c index d124d837ae5..a30b8f480f6 100644 --- a/drivers/net/can/vcan.c +++ b/drivers/net/can/vcan.c @@ -48,6 +48,7 @@  #include <linux/if_ether.h>  #include <linux/can.h>  #include <linux/can/dev.h> +#include <linux/slab.h>  #include <net/rtnetlink.h>  static __initdata const char banner[] = diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h index 2d11afe4531..036b2dfb1d4 100644 --- a/drivers/net/chelsio/common.h +++ b/drivers/net/chelsio/common.h @@ -51,6 +51,7 @@  #include <linux/mdio.h>  #include <linux/crc32.h>  #include <linux/init.h> +#include <linux/slab.h>  #include <asm/io.h>  #include <linux/pci_ids.h> diff --git a/drivers/net/chelsio/pm3393.c b/drivers/net/chelsio/pm3393.c index a6eb30a6e2b..9e631b9d394 100644 --- a/drivers/net/chelsio/pm3393.c +++ b/drivers/net/chelsio/pm3393.c @@ -44,6 +44,7 @@  #include "suni1x10gexp_regs.h"  #include <linux/crc32.h> +#include <linux/slab.h>  #define OFFSET(REG_ADDR)    ((REG_ADDR) << 2) diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index 55d99ca82f8..df3a1410696 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -53,6 +53,7 @@  #include <linux/ip.h>  #include <linux/in.h>  #include <linux/if_arp.h> +#include <linux/slab.h>  #include "cpl5_cmd.h"  #include "sge.h" diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c index 9781942992e..4b451a7c03e 100644 --- a/drivers/net/cnic.c +++ b/drivers/net/cnic.c @@ -2334,13 +2334,13 @@ static int cnic_service_bnx2x(void *data, void *status_blk)  	struct cnic_local *cp = dev->cnic_priv;  	u16 prod = cp->kcq_prod_idx & MAX_KCQ_IDX; -	prefetch(cp->status_blk.bnx2x); -	prefetch(&cp->kcq[KCQ_PG(prod)][KCQ_IDX(prod)]); +	if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags))) { +		prefetch(cp->status_blk.bnx2x); +		prefetch(&cp->kcq[KCQ_PG(prod)][KCQ_IDX(prod)]); -	if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags)))  		tasklet_schedule(&cp->cnic_irq_task); - -	cnic_chk_pkt_rings(cp); +		cnic_chk_pkt_rings(cp); +	}  	return 0;  } diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index dd24aadb778..61a33914e96 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -18,7 +18,6 @@  #include <linux/ptrace.h>  #include <linux/ioport.h>  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/spinlock.h>  #include <linux/errno.h> diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index b0208e474f7..4c38491b8ef 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -138,12 +138,12 @@  #include <linux/ioport.h>  #include <linux/in.h>  #include <linux/skbuff.h> -#include <linux/slab.h>  #include <linux/spinlock.h>  #include <linux/string.h>  #include <linux/init.h>  #include <linux/bitops.h>  #include <linux/delay.h> +#include <linux/gfp.h>  #include <asm/system.h>  #include <asm/io.h> diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c index 5248f9e0b2f..35cd3672915 100644 --- a/drivers/net/cxgb3/ael1002.c +++ b/drivers/net/cxgb3/ael1002.c @@ -934,7 +934,7 @@ static struct cphy_ops xaui_direct_ops = {  int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,  			    int phy_addr, const struct mdio_ops *mdio_ops)  { -	cphy_init(phy, adapter, MDIO_PRTAD_NONE, &xaui_direct_ops, mdio_ops, +	cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops,  		  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP,  		  "10GBASE-CX4");  	return 0; diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 9e3e8750b46..e3f1b856649 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -46,6 +46,7 @@  #include <linux/log2.h>  #include <linux/stringify.h>  #include <linux/sched.h> +#include <linux/slab.h>  #include <asm/uaccess.h>  #include "common.h" @@ -438,7 +439,7 @@ static void free_irq_resources(struct adapter *adapter)  static int await_mgmt_replies(struct adapter *adap, unsigned long init_cnt,  			      unsigned long n)  { -	int attempts = 5; +	int attempts = 10;  	while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) {  		if (!--attempts) diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index 9498361119d..c6485b39eb0 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -31,6 +31,7 @@   */  #include <linux/list.h> +#include <linux/slab.h>  #include <net/neighbour.h>  #include <linux/notifier.h>  #include <asm/atomic.h> diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c index ff1611f90e7..2f3ee721c3e 100644 --- a/drivers/net/cxgb3/l2t.c +++ b/drivers/net/cxgb3/l2t.c @@ -34,6 +34,7 @@  #include <linux/if.h>  #include <linux/if_vlan.h>  #include <linux/jhash.h> +#include <linux/slab.h>  #include <net/neighbour.h>  #include "common.h"  #include "t3cdev.h" diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 67e61b2a8c4..07d7e7fab3f 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -36,6 +36,7 @@  #include <linux/ip.h>  #include <linux/tcp.h>  #include <linux/dma-mapping.h> +#include <linux/slab.h>  #include <net/arp.h>  #include "common.h"  #include "regs.h" diff --git a/drivers/net/cxgb4/Makefile b/drivers/net/cxgb4/Makefile new file mode 100644 index 00000000000..498667487f5 --- /dev/null +++ b/drivers/net/cxgb4/Makefile @@ -0,0 +1,7 @@ +# +# Chelsio T4 driver +# + +obj-$(CONFIG_CHELSIO_T4) += cxgb4.o + +cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o diff --git a/drivers/net/cxgb4/cxgb4.h b/drivers/net/cxgb4/cxgb4.h new file mode 100644 index 00000000000..3d8ff4889b5 --- /dev/null +++ b/drivers/net/cxgb4/cxgb4.h @@ -0,0 +1,741 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses.  You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + *     Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *      - Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + * + *      - Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __CXGB4_H__ +#define __CXGB4_H__ + +#include <linux/bitops.h> +#include <linux/cache.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/netdevice.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/timer.h> +#include <asm/io.h> +#include "cxgb4_uld.h" +#include "t4_hw.h" + +#define FW_VERSION_MAJOR 1 +#define FW_VERSION_MINOR 1 +#define FW_VERSION_MICRO 0 + +enum { +	MAX_NPORTS = 4,     /* max # of ports */ +	SERNUM_LEN = 16,    /* Serial # length */ +	EC_LEN     = 16,    /* E/C length */ +	ID_LEN     = 16,    /* ID length */ +}; + +enum { +	MEM_EDC0, +	MEM_EDC1, +	MEM_MC +}; + +enum dev_master { +	MASTER_CANT, +	MASTER_MAY, +	MASTER_MUST +}; + +enum dev_state { +	DEV_STATE_UNINIT, +	DEV_STATE_INIT, +	DEV_STATE_ERR +}; + +enum { +	PAUSE_RX      = 1 << 0, +	PAUSE_TX      = 1 << 1, +	PAUSE_AUTONEG = 1 << 2 +}; + +struct port_stats { +	u64 tx_octets;            /* total # of octets in good frames */ +	u64 tx_frames;            /* all good frames */ +	u64 tx_bcast_frames;      /* all broadcast frames */ +	u64 tx_mcast_frames;      /* all multicast frames */ +	u64 tx_ucast_frames;      /* all unicast frames */ +	u64 tx_error_frames;      /* all error frames */ + +	u64 tx_frames_64;         /* # of Tx frames in a particular range */ +	u64 tx_frames_65_127; +	u64 tx_frames_128_255; +	u64 tx_frames_256_511; +	u64 tx_frames_512_1023; +	u64 tx_frames_1024_1518; +	u64 tx_frames_1519_max; + +	u64 tx_drop;              /* # of dropped Tx frames */ +	u64 tx_pause;             /* # of transmitted pause frames */ +	u64 tx_ppp0;              /* # of transmitted PPP prio 0 frames */ +	u64 tx_ppp1;              /* # of transmitted PPP prio 1 frames */ +	u64 tx_ppp2;              /* # of transmitted PPP prio 2 frames */ +	u64 tx_ppp3;              /* # of transmitted PPP prio 3 frames */ +	u64 tx_ppp4;              /* # of transmitted PPP prio 4 frames */ +	u64 tx_ppp5;              /* # of transmitted PPP prio 5 frames */ +	u64 tx_ppp6;              /* # of transmitted PPP prio 6 frames */ +	u64 tx_ppp7;              /* # of transmitted PPP prio 7 frames */ + +	u64 rx_octets;            /* total # of octets in good frames */ +	u64 rx_frames;            /* all good frames */ +	u64 rx_bcast_frames;      /* all broadcast frames */ +	u64 rx_mcast_frames;      /* all multicast frames */ +	u64 rx_ucast_frames;      /* all unicast frames */ +	u64 rx_too_long;          /* # of frames exceeding MTU */ +	u64 rx_jabber;            /* # of jabber frames */ +	u64 rx_fcs_err;           /* # of received frames with bad FCS */ +	u64 rx_len_err;           /* # of received frames with length error */ +	u64 rx_symbol_err;        /* symbol errors */ +	u64 rx_runt;              /* # of short frames */ + +	u64 rx_frames_64;         /* # of Rx frames in a particular range */ +	u64 rx_frames_65_127; +	u64 rx_frames_128_255; +	u64 rx_frames_256_511; +	u64 rx_frames_512_1023; +	u64 rx_frames_1024_1518; +	u64 rx_frames_1519_max; + +	u64 rx_pause;             /* # of received pause frames */ +	u64 rx_ppp0;              /* # of received PPP prio 0 frames */ +	u64 rx_ppp1;              /* # of received PPP prio 1 frames */ +	u64 rx_ppp2;              /* # of received PPP prio 2 frames */ +	u64 rx_ppp3;              /* # of received PPP prio 3 frames */ +	u64 rx_ppp4;              /* # of received PPP prio 4 frames */ +	u64 rx_ppp5;              /* # of received PPP prio 5 frames */ +	u64 rx_ppp6;              /* # of received PPP prio 6 frames */ +	u64 rx_ppp7;              /* # of received PPP prio 7 frames */ + +	u64 rx_ovflow0;           /* drops due to buffer-group 0 overflows */ +	u64 rx_ovflow1;           /* drops due to buffer-group 1 overflows */ +	u64 rx_ovflow2;           /* drops due to buffer-group 2 overflows */ +	u64 rx_ovflow3;           /* drops due to buffer-group 3 overflows */ +	u64 rx_trunc0;            /* buffer-group 0 truncated packets */ +	u64 rx_trunc1;            /* buffer-group 1 truncated packets */ +	u64 rx_trunc2;            /* buffer-group 2 truncated packets */ +	u64 rx_trunc3;            /* buffer-group 3 truncated packets */ +}; + +struct lb_port_stats { +	u64 octets; +	u64 frames; +	u64 bcast_frames; +	u64 mcast_frames; +	u64 ucast_frames; +	u64 error_frames; + +	u64 frames_64; +	u64 frames_65_127; +	u64 frames_128_255; +	u64 frames_256_511; +	u64 frames_512_1023; +	u64 frames_1024_1518; +	u64 frames_1519_max; + +	u64 drop; + +	u64 ovflow0; +	u64 ovflow1; +	u64 ovflow2; +	u64 ovflow3; +	u64 trunc0; +	u64 trunc1; +	u64 trunc2; +	u64 trunc3; +}; + +struct tp_tcp_stats { +	u32 tcpOutRsts; +	u64 tcpInSegs; +	u64 tcpOutSegs; +	u64 tcpRetransSegs; +}; + +struct tp_err_stats { +	u32 macInErrs[4]; +	u32 hdrInErrs[4]; +	u32 tcpInErrs[4]; +	u32 tnlCongDrops[4]; +	u32 ofldChanDrops[4]; +	u32 tnlTxDrops[4]; +	u32 ofldVlanDrops[4]; +	u32 tcp6InErrs[4]; +	u32 ofldNoNeigh; +	u32 ofldCongDefer; +}; + +struct tp_params { +	unsigned int ntxchan;        /* # of Tx channels */ +	unsigned int tre;            /* log2 of core clocks per TP tick */ +}; + +struct vpd_params { +	unsigned int cclk; +	u8 ec[EC_LEN + 1]; +	u8 sn[SERNUM_LEN + 1]; +	u8 id[ID_LEN + 1]; +}; + +struct pci_params { +	unsigned char speed; +	unsigned char width; +}; + +struct adapter_params { +	struct tp_params  tp; +	struct vpd_params vpd; +	struct pci_params pci; + +	unsigned int fw_vers; +	unsigned int tp_vers; +	u8 api_vers[7]; + +	unsigned short mtus[NMTUS]; +	unsigned short a_wnd[NCCTRL_WIN]; +	unsigned short b_wnd[NCCTRL_WIN]; + +	unsigned char nports;             /* # of ethernet ports */ +	unsigned char portvec; +	unsigned char rev;                /* chip revision */ +	unsigned char offload; + +	unsigned int ofldq_wr_cred; +}; + +struct trace_params { +	u32 data[TRACE_LEN / 4]; +	u32 mask[TRACE_LEN / 4]; +	unsigned short snap_len; +	unsigned short min_len; +	unsigned char skip_ofst; +	unsigned char skip_len; +	unsigned char invert; +	unsigned char port; +}; + +struct link_config { +	unsigned short supported;        /* link capabilities */ +	unsigned short advertising;      /* advertised capabilities */ +	unsigned short requested_speed;  /* speed user has requested */ +	unsigned short speed;            /* actual link speed */ +	unsigned char  requested_fc;     /* flow control user has requested */ +	unsigned char  fc;               /* actual link flow control */ +	unsigned char  autoneg;          /* autonegotiating? */ +	unsigned char  link_ok;          /* link up? */ +}; + +#define FW_LEN16(fw_struct) FW_CMD_LEN16(sizeof(fw_struct) / 16) + +enum { +	MAX_ETH_QSETS = 32,           /* # of Ethernet Tx/Rx queue sets */ +	MAX_OFLD_QSETS = 16,          /* # of offload Tx/Rx queue sets */ +	MAX_CTRL_QUEUES = NCHAN,      /* # of control Tx queues */ +	MAX_RDMA_QUEUES = NCHAN,      /* # of streaming RDMA Rx queues */ +}; + +enum { +	MAX_EGRQ = 128,         /* max # of egress queues, including FLs */ +	MAX_INGQ = 64           /* max # of interrupt-capable ingress queues */ +}; + +struct adapter; +struct vlan_group; +struct sge_rspq; + +struct port_info { +	struct adapter *adapter; +	struct vlan_group *vlan_grp; +	u16    viid; +	s16    xact_addr_filt;        /* index of exact MAC address filter */ +	u16    rss_size;              /* size of VI's RSS table slice */ +	s8     mdio_addr; +	u8     port_type; +	u8     mod_type; +	u8     port_id; +	u8     tx_chan; +	u8     lport;                 /* associated offload logical port */ +	u8     rx_offload;            /* CSO, etc */ +	u8     nqsets;                /* # of qsets */ +	u8     first_qset;            /* index of first qset */ +	struct link_config link_cfg; +}; + +/* port_info.rx_offload flags */ +enum { +	RX_CSO = 1 << 0, +}; + +struct dentry; +struct work_struct; + +enum {                                 /* adapter flags */ +	FULL_INIT_DONE     = (1 << 0), +	USING_MSI          = (1 << 1), +	USING_MSIX         = (1 << 2), +	QUEUES_BOUND       = (1 << 3), +	FW_OK              = (1 << 4), +}; + +struct rx_sw_desc; + +struct sge_fl {                     /* SGE free-buffer queue state */ +	unsigned int avail;         /* # of available Rx buffers */ +	unsigned int pend_cred;     /* new buffers since last FL DB ring */ +	unsigned int cidx;          /* consumer index */ +	unsigned int pidx;          /* producer index */ +	unsigned long alloc_failed; /* # of times buffer allocation failed */ +	unsigned long large_alloc_failed; +	unsigned long starving; +	/* RO fields */ +	unsigned int cntxt_id;      /* SGE context id for the free list */ +	unsigned int size;          /* capacity of free list */ +	struct rx_sw_desc *sdesc;   /* address of SW Rx descriptor ring */ +	__be64 *desc;               /* address of HW Rx descriptor ring */ +	dma_addr_t addr;            /* bus address of HW ring start */ +}; + +/* A packet gather list */ +struct pkt_gl { +	skb_frag_t frags[MAX_SKB_FRAGS]; +	void *va;                         /* virtual address of first byte */ +	unsigned int nfrags;              /* # of fragments */ +	unsigned int tot_len;             /* total length of fragments */ +}; + +typedef int (*rspq_handler_t)(struct sge_rspq *q, const __be64 *rsp, +			      const struct pkt_gl *gl); + +struct sge_rspq {                   /* state for an SGE response queue */ +	struct napi_struct napi; +	const __be64 *cur_desc;     /* current descriptor in queue */ +	unsigned int cidx;          /* consumer index */ +	u8 gen;                     /* current generation bit */ +	u8 intr_params;             /* interrupt holdoff parameters */ +	u8 next_intr_params;        /* holdoff params for next interrupt */ +	u8 pktcnt_idx;              /* interrupt packet threshold */ +	u8 uld;                     /* ULD handling this queue */ +	u8 idx;                     /* queue index within its group */ +	int offset;                 /* offset into current Rx buffer */ +	u16 cntxt_id;               /* SGE context id for the response q */ +	u16 abs_id;                 /* absolute SGE id for the response q */ +	__be64 *desc;               /* address of HW response ring */ +	dma_addr_t phys_addr;       /* physical address of the ring */ +	unsigned int iqe_len;       /* entry size */ +	unsigned int size;          /* capacity of response queue */ +	struct adapter *adap; +	struct net_device *netdev;  /* associated net device */ +	rspq_handler_t handler; +}; + +struct sge_eth_stats {              /* Ethernet queue statistics */ +	unsigned long pkts;         /* # of ethernet packets */ +	unsigned long lro_pkts;     /* # of LRO super packets */ +	unsigned long lro_merged;   /* # of wire packets merged by LRO */ +	unsigned long rx_cso;       /* # of Rx checksum offloads */ +	unsigned long vlan_ex;      /* # of Rx VLAN extractions */ +	unsigned long rx_drops;     /* # of packets dropped due to no mem */ +}; + +struct sge_eth_rxq {                /* SW Ethernet Rx queue */ +	struct sge_rspq rspq; +	struct sge_fl fl; +	struct sge_eth_stats stats; +} ____cacheline_aligned_in_smp; + +struct sge_ofld_stats {             /* offload queue statistics */ +	unsigned long pkts;         /* # of packets */ +	unsigned long imm;          /* # of immediate-data packets */ +	unsigned long an;           /* # of asynchronous notifications */ +	unsigned long nomem;        /* # of responses deferred due to no mem */ +}; + +struct sge_ofld_rxq {               /* SW offload Rx queue */ +	struct sge_rspq rspq; +	struct sge_fl fl; +	struct sge_ofld_stats stats; +} ____cacheline_aligned_in_smp; + +struct tx_desc { +	__be64 flit[8]; +}; + +struct tx_sw_desc; + +struct sge_txq { +	unsigned int  in_use;       /* # of in-use Tx descriptors */ +	unsigned int  size;         /* # of descriptors */ +	unsigned int  cidx;         /* SW consumer index */ +	unsigned int  pidx;         /* producer index */ +	unsigned long stops;        /* # of times q has been stopped */ +	unsigned long restarts;     /* # of queue restarts */ +	unsigned int  cntxt_id;     /* SGE context id for the Tx q */ +	struct tx_desc *desc;       /* address of HW Tx descriptor ring */ +	struct tx_sw_desc *sdesc;   /* address of SW Tx descriptor ring */ +	struct sge_qstat *stat;     /* queue status entry */ +	dma_addr_t    phys_addr;    /* physical address of the ring */ +}; + +struct sge_eth_txq {                /* state for an SGE Ethernet Tx queue */ +	struct sge_txq q; +	struct netdev_queue *txq;   /* associated netdev TX queue */ +	unsigned long tso;          /* # of TSO requests */ +	unsigned long tx_cso;       /* # of Tx checksum offloads */ +	unsigned long vlan_ins;     /* # of Tx VLAN insertions */ +	unsigned long mapping_err;  /* # of I/O MMU packet mapping errors */ +} ____cacheline_aligned_in_smp; + +struct sge_ofld_txq {               /* state for an SGE offload Tx queue */ +	struct sge_txq q; +	struct adapter *adap; +	struct sk_buff_head sendq;  /* list of backpressured packets */ +	struct tasklet_struct qresume_tsk; /* restarts the queue */ +	u8 full;                    /* the Tx ring is full */ +	unsigned long mapping_err;  /* # of I/O MMU packet mapping errors */ +} ____cacheline_aligned_in_smp; + +struct sge_ctrl_txq {               /* state for an SGE control Tx queue */ +	struct sge_txq q; +	struct adapter *adap; +	struct sk_buff_head sendq;  /* list of backpressured packets */ +	struct tasklet_struct qresume_tsk; /* restarts the queue */ +	u8 full;                    /* the Tx ring is full */ +} ____cacheline_aligned_in_smp; + +struct sge { +	struct sge_eth_txq ethtxq[MAX_ETH_QSETS]; +	struct sge_ofld_txq ofldtxq[MAX_OFLD_QSETS]; +	struct sge_ctrl_txq ctrlq[MAX_CTRL_QUEUES]; + +	struct sge_eth_rxq ethrxq[MAX_ETH_QSETS]; +	struct sge_ofld_rxq ofldrxq[MAX_OFLD_QSETS]; +	struct sge_ofld_rxq rdmarxq[MAX_RDMA_QUEUES]; +	struct sge_rspq fw_evtq ____cacheline_aligned_in_smp; + +	struct sge_rspq intrq ____cacheline_aligned_in_smp; +	spinlock_t intrq_lock; + +	u16 max_ethqsets;           /* # of available Ethernet queue sets */ +	u16 ethqsets;               /* # of active Ethernet queue sets */ +	u16 ethtxq_rover;           /* Tx queue to clean up next */ +	u16 ofldqsets;              /* # of active offload queue sets */ +	u16 rdmaqs;                 /* # of available RDMA Rx queues */ +	u16 ofld_rxq[MAX_OFLD_QSETS]; +	u16 rdma_rxq[NCHAN]; +	u16 timer_val[SGE_NTIMERS]; +	u8 counter_val[SGE_NCOUNTERS]; +	unsigned int starve_thres; +	u8 idma_state[2]; +	void *egr_map[MAX_EGRQ];    /* qid->queue egress queue map */ +	struct sge_rspq *ingr_map[MAX_INGQ]; /* qid->queue ingress queue map */ +	DECLARE_BITMAP(starving_fl, MAX_EGRQ); +	DECLARE_BITMAP(txq_maperr, MAX_EGRQ); +	struct timer_list rx_timer; /* refills starving FLs */ +	struct timer_list tx_timer; /* checks Tx queues */ +}; + +#define for_each_ethrxq(sge, i) for (i = 0; i < (sge)->ethqsets; i++) +#define for_each_ofldrxq(sge, i) for (i = 0; i < (sge)->ofldqsets; i++) +#define for_each_rdmarxq(sge, i) for (i = 0; i < (sge)->rdmaqs; i++) + +struct l2t_data; + +struct adapter { +	void __iomem *regs; +	struct pci_dev *pdev; +	struct device *pdev_dev; +	unsigned long registered_device_map; +	unsigned long open_device_map; +	unsigned long flags; + +	const char *name; +	int msg_enable; + +	struct adapter_params params; +	struct cxgb4_virt_res vres; +	unsigned int swintr; + +	unsigned int wol; + +	struct { +		unsigned short vec; +		char desc[14]; +	} msix_info[MAX_INGQ + 1]; + +	struct sge sge; + +	struct net_device *port[MAX_NPORTS]; +	u8 chan_map[NCHAN];                   /* channel -> port map */ + +	struct l2t_data *l2t; +	void *uld_handle[CXGB4_ULD_MAX]; +	struct list_head list_node; + +	struct tid_info tids; +	void **tid_release_head; +	spinlock_t tid_release_lock; +	struct work_struct tid_release_task; +	bool tid_release_task_busy; + +	struct dentry *debugfs_root; + +	spinlock_t stats_lock; +}; + +static inline u32 t4_read_reg(struct adapter *adap, u32 reg_addr) +{ +	return readl(adap->regs + reg_addr); +} + +static inline void t4_write_reg(struct adapter *adap, u32 reg_addr, u32 val) +{ +	writel(val, adap->regs + reg_addr); +} + +#ifndef readq +static inline u64 readq(const volatile void __iomem *addr) +{ +	return readl(addr) + ((u64)readl(addr + 4) << 32); +} + +static inline void writeq(u64 val, volatile void __iomem *addr) +{ +	writel(val, addr); +	writel(val >> 32, addr + 4); +} +#endif + +static inline u64 t4_read_reg64(struct adapter *adap, u32 reg_addr) +{ +	return readq(adap->regs + reg_addr); +} + +static inline void t4_write_reg64(struct adapter *adap, u32 reg_addr, u64 val) +{ +	writeq(val, adap->regs + reg_addr); +} + +/** + * netdev2pinfo - return the port_info structure associated with a net_device + * @dev: the netdev + * + * Return the struct port_info associated with a net_device + */ +static inline struct port_info *netdev2pinfo(const struct net_device *dev) +{ +	return netdev_priv(dev); +} + +/** + * adap2pinfo - return the port_info of a port + * @adap: the adapter + * @idx: the port index + * + * Return the port_info structure for the port of the given index. + */ +static inline struct port_info *adap2pinfo(struct adapter *adap, int idx) +{ +	return netdev_priv(adap->port[idx]); +} + +/** + * netdev2adap - return the adapter structure associated with a net_device + * @dev: the netdev + * + * Return the struct adapter associated with a net_device + */ +static inline struct adapter *netdev2adap(const struct net_device *dev) +{ +	return netdev2pinfo(dev)->adapter; +} + +void t4_os_portmod_changed(const struct adapter *adap, int port_id); +void t4_os_link_changed(struct adapter *adap, int port_id, int link_stat); + +void *t4_alloc_mem(size_t size); +void t4_free_mem(void *addr); + +void t4_free_sge_resources(struct adapter *adap); +irq_handler_t t4_intr_handler(struct adapter *adap); +netdev_tx_t t4_eth_xmit(struct sk_buff *skb, struct net_device *dev); +int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, +		     const struct pkt_gl *gl); +int t4_mgmt_tx(struct adapter *adap, struct sk_buff *skb); +int t4_ofld_send(struct adapter *adap, struct sk_buff *skb); +int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq, +		     struct net_device *dev, int intr_idx, +		     struct sge_fl *fl, rspq_handler_t hnd); +int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq, +			 struct net_device *dev, struct netdev_queue *netdevq, +			 unsigned int iqid); +int t4_sge_alloc_ctrl_txq(struct adapter *adap, struct sge_ctrl_txq *txq, +			  struct net_device *dev, unsigned int iqid, +			  unsigned int cmplqid); +int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_ofld_txq *txq, +			  struct net_device *dev, unsigned int iqid); +irqreturn_t t4_sge_intr_msix(int irq, void *cookie); +void t4_sge_init(struct adapter *adap); +void t4_sge_start(struct adapter *adap); +void t4_sge_stop(struct adapter *adap); + +#define for_each_port(adapter, iter) \ +	for (iter = 0; iter < (adapter)->params.nports; ++iter) + +static inline unsigned int core_ticks_per_usec(const struct adapter *adap) +{ +	return adap->params.vpd.cclk / 1000; +} + +static inline unsigned int us_to_core_ticks(const struct adapter *adap, +					    unsigned int us) +{ +	return (us * adap->params.vpd.cclk) / 1000; +} + +void t4_set_reg_field(struct adapter *adap, unsigned int addr, u32 mask, +		      u32 val); + +int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size, +		    void *rpl, bool sleep_ok); + +static inline int t4_wr_mbox(struct adapter *adap, int mbox, const void *cmd, +			     int size, void *rpl) +{ +	return t4_wr_mbox_meat(adap, mbox, cmd, size, rpl, true); +} + +static inline int t4_wr_mbox_ns(struct adapter *adap, int mbox, const void *cmd, +				int size, void *rpl) +{ +	return t4_wr_mbox_meat(adap, mbox, cmd, size, rpl, false); +} + +void t4_intr_enable(struct adapter *adapter); +void t4_intr_disable(struct adapter *adapter); +void t4_intr_clear(struct adapter *adapter); +int t4_slow_intr_handler(struct adapter *adapter); + +int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port, +		  struct link_config *lc); +int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port); +int t4_seeprom_wp(struct adapter *adapter, bool enable); +int t4_read_flash(struct adapter *adapter, unsigned int addr, +		  unsigned int nwords, u32 *data, int byte_oriented); +int t4_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size); +int t4_check_fw_version(struct adapter *adapter); +int t4_prep_adapter(struct adapter *adapter); +int t4_port_init(struct adapter *adap, int mbox, int pf, int vf); +void t4_fatal_err(struct adapter *adapter); +void t4_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on); +int t4_set_trace_filter(struct adapter *adapter, const struct trace_params *tp, +			int filter_index, int enable); +void t4_get_trace_filter(struct adapter *adapter, struct trace_params *tp, +			 int filter_index, int *enabled); +int t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid, +			int start, int n, const u16 *rspq, unsigned int nrspq); +int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode, +		       unsigned int flags); +int t4_read_rss(struct adapter *adapter, u16 *entries); +int t4_mc_read(struct adapter *adap, u32 addr, __be32 *data, u64 *parity); +int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, +		u64 *parity); + +void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p); +void t4_get_lb_stats(struct adapter *adap, int idx, struct lb_port_stats *p); + +void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log); +void t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st); +void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4, +			 struct tp_tcp_stats *v6); +void t4_load_mtus(struct adapter *adap, const unsigned short *mtus, +		  const unsigned short *alpha, const unsigned short *beta); + +void t4_wol_magic_enable(struct adapter *adap, unsigned int port, +			 const u8 *addr); +int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map, +		      u64 mask0, u64 mask1, unsigned int crc, bool enable); + +int t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox, +		enum dev_master master, enum dev_state *state); +int t4_fw_bye(struct adapter *adap, unsigned int mbox); +int t4_early_init(struct adapter *adap, unsigned int mbox); +int t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset); +int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf, +		    unsigned int vf, unsigned int nparams, const u32 *params, +		    u32 *val); +int t4_set_params(struct adapter *adap, unsigned int mbox, unsigned int pf, +		  unsigned int vf, unsigned int nparams, const u32 *params, +		  const u32 *val); +int t4_cfg_pfvf(struct adapter *adap, unsigned int mbox, unsigned int pf, +		unsigned int vf, unsigned int txq, unsigned int txq_eth_ctrl, +		unsigned int rxqi, unsigned int rxq, unsigned int tc, +		unsigned int vi, unsigned int cmask, unsigned int pmask, +		unsigned int nexact, unsigned int rcaps, unsigned int wxcaps); +int t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port, +		unsigned int pf, unsigned int vf, unsigned int nmac, u8 *mac, +		unsigned int *rss_size); +int t4_free_vi(struct adapter *adap, unsigned int mbox, unsigned int pf, +	       unsigned int vf, unsigned int viid); +int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid, +		int mtu, int promisc, int all_multi, int bcast, bool sleep_ok); +int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox, +		      unsigned int viid, bool free, unsigned int naddr, +		      const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok); +int t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid, +		  int idx, const u8 *addr, bool persist, bool add_smt); +int t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid, +		     bool ucast, u64 vec, bool sleep_ok); +int t4_enable_vi(struct adapter *adap, unsigned int mbox, unsigned int viid, +		 bool rx_en, bool tx_en); +int t4_identify_port(struct adapter *adap, unsigned int mbox, unsigned int viid, +		     unsigned int nblinks); +int t4_mdio_rd(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, +	       unsigned int mmd, unsigned int reg, u16 *valp); +int t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, +	       unsigned int mmd, unsigned int reg, u16 val); +int t4_iq_start_stop(struct adapter *adap, unsigned int mbox, bool start, +		     unsigned int pf, unsigned int vf, unsigned int iqid, +		     unsigned int fl0id, unsigned int fl1id); +int t4_iq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, +	       unsigned int vf, unsigned int iqtype, unsigned int iqid, +	       unsigned int fl0id, unsigned int fl1id); +int t4_eth_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, +		   unsigned int vf, unsigned int eqid); +int t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, +		    unsigned int vf, unsigned int eqid); +int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, +		    unsigned int vf, unsigned int eqid); +int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl); +#endif /* __CXGB4_H__ */ diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c new file mode 100644 index 00000000000..a7e30a23d32 --- /dev/null +++ b/drivers/net/cxgb4/cxgb4_main.c @@ -0,0 +1,3388 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses.  You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + *     Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *      - Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + * + *      - Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/bitmap.h> +#include <linux/crc32.h> +#include <linux/ctype.h> +#include <linux/debugfs.h> +#include <linux/err.h> +#include <linux/etherdevice.h> +#include <linux/firmware.h> +#include <linux/if_vlan.h> +#include <linux/init.h> +#include <linux/log2.h> +#include <linux/mdio.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/mutex.h> +#include <linux/netdevice.h> +#include <linux/pci.h> +#include <linux/aer.h> +#include <linux/rtnetlink.h> +#include <linux/sched.h> +#include <linux/seq_file.h> +#include <linux/sockios.h> +#include <linux/vmalloc.h> +#include <linux/workqueue.h> +#include <net/neighbour.h> +#include <net/netevent.h> +#include <asm/uaccess.h> + +#include "cxgb4.h" +#include "t4_regs.h" +#include "t4_msg.h" +#include "t4fw_api.h" +#include "l2t.h" + +#define DRV_VERSION "1.0.0-ko" +#define DRV_DESC "Chelsio T4 Network Driver" + +/* + * Max interrupt hold-off timer value in us.  Queues fall back to this value + * under extreme memory pressure so it's largish to give the system time to + * recover. + */ +#define MAX_SGE_TIMERVAL 200U + +enum { +	MEMWIN0_APERTURE = 65536, +	MEMWIN0_BASE     = 0x30000, +	MEMWIN1_APERTURE = 32768, +	MEMWIN1_BASE     = 0x28000, +	MEMWIN2_APERTURE = 2048, +	MEMWIN2_BASE     = 0x1b800, +}; + +enum { +	MAX_TXQ_ENTRIES      = 16384, +	MAX_CTRL_TXQ_ENTRIES = 1024, +	MAX_RSPQ_ENTRIES     = 16384, +	MAX_RX_BUFFERS       = 16384, +	MIN_TXQ_ENTRIES      = 32, +	MIN_CTRL_TXQ_ENTRIES = 32, +	MIN_RSPQ_ENTRIES     = 128, +	MIN_FL_ENTRIES       = 16 +}; + +#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \ +			 NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\ +			 NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) + +#define CH_DEVICE(devid) { PCI_VDEVICE(CHELSIO, devid), 0 } + +static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = { +	CH_DEVICE(0xa000),  /* PE10K */ +	{ 0, } +}; + +#define FW_FNAME "cxgb4/t4fw.bin" + +MODULE_DESCRIPTION(DRV_DESC); +MODULE_AUTHOR("Chelsio Communications"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(DRV_VERSION); +MODULE_DEVICE_TABLE(pci, cxgb4_pci_tbl); +MODULE_FIRMWARE(FW_FNAME); + +static int dflt_msg_enable = DFLT_MSG_ENABLE; + +module_param(dflt_msg_enable, int, 0644); +MODULE_PARM_DESC(dflt_msg_enable, "Chelsio T4 default message enable bitmap"); + +/* + * The driver uses the best interrupt scheme available on a platform in the + * order MSI-X, MSI, legacy INTx interrupts.  This parameter determines which + * of these schemes the driver may consider as follows: + * + * msi = 2: choose from among all three options + * msi = 1: only consider MSI and INTx interrupts + * msi = 0: force INTx interrupts + */ +static int msi = 2; + +module_param(msi, int, 0644); +MODULE_PARM_DESC(msi, "whether to use INTx (0), MSI (1) or MSI-X (2)"); + +/* + * Queue interrupt hold-off timer values.  Queues default to the first of these + * upon creation. + */ +static unsigned int intr_holdoff[SGE_NTIMERS - 1] = { 5, 10, 20, 50, 100 }; + +module_param_array(intr_holdoff, uint, NULL, 0644); +MODULE_PARM_DESC(intr_holdoff, "values for queue interrupt hold-off timers " +		 "0..4 in microseconds"); + +static unsigned int intr_cnt[SGE_NCOUNTERS - 1] = { 4, 8, 16 }; + +module_param_array(intr_cnt, uint, NULL, 0644); +MODULE_PARM_DESC(intr_cnt, +		 "thresholds 1..3 for queue interrupt packet counters"); + +static int vf_acls; + +#ifdef CONFIG_PCI_IOV +module_param(vf_acls, bool, 0644); +MODULE_PARM_DESC(vf_acls, "if set enable virtualization L2 ACL enforcement"); + +static unsigned int num_vf[4]; + +module_param_array(num_vf, uint, NULL, 0644); +MODULE_PARM_DESC(num_vf, "number of VFs for each of PFs 0-3"); +#endif + +static struct dentry *cxgb4_debugfs_root; + +static LIST_HEAD(adapter_list); +static DEFINE_MUTEX(uld_mutex); +static struct cxgb4_uld_info ulds[CXGB4_ULD_MAX]; +static const char *uld_str[] = { "RDMA", "iSCSI" }; + +static void link_report(struct net_device *dev) +{ +	if (!netif_carrier_ok(dev)) +		netdev_info(dev, "link down\n"); +	else { +		static const char *fc[] = { "no", "Rx", "Tx", "Tx/Rx" }; + +		const char *s = "10Mbps"; +		const struct port_info *p = netdev_priv(dev); + +		switch (p->link_cfg.speed) { +		case SPEED_10000: +			s = "10Gbps"; +			break; +		case SPEED_1000: +			s = "1000Mbps"; +			break; +		case SPEED_100: +			s = "100Mbps"; +			break; +		} + +		netdev_info(dev, "link up, %s, full-duplex, %s PAUSE\n", s, +			    fc[p->link_cfg.fc]); +	} +} + +void t4_os_link_changed(struct adapter *adapter, int port_id, int link_stat) +{ +	struct net_device *dev = adapter->port[port_id]; + +	/* Skip changes from disabled ports. */ +	if (netif_running(dev) && link_stat != netif_carrier_ok(dev)) { +		if (link_stat) +			netif_carrier_on(dev); +		else +			netif_carrier_off(dev); + +		link_report(dev); +	} +} + +void t4_os_portmod_changed(const struct adapter *adap, int port_id) +{ +	static const char *mod_str[] = { +		NULL, "LR", "SR", "ER", "passive DA", "active DA" +	}; + +	const struct net_device *dev = adap->port[port_id]; +	const struct port_info *pi = netdev_priv(dev); + +	if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) +		netdev_info(dev, "port module unplugged\n"); +	else +		netdev_info(dev, "%s module inserted\n", mod_str[pi->mod_type]); +} + +/* + * Configure the exact and hash address filters to handle a port's multicast + * and secondary unicast MAC addresses. + */ +static int set_addr_filters(const struct net_device *dev, bool sleep) +{ +	u64 mhash = 0; +	u64 uhash = 0; +	bool free = true; +	u16 filt_idx[7]; +	const u8 *addr[7]; +	int ret, naddr = 0; +	const struct dev_addr_list *d; +	const struct netdev_hw_addr *ha; +	int uc_cnt = netdev_uc_count(dev); +	const struct port_info *pi = netdev_priv(dev); + +	/* first do the secondary unicast addresses */ +	netdev_for_each_uc_addr(ha, dev) { +		addr[naddr++] = ha->addr; +		if (--uc_cnt == 0 || naddr >= ARRAY_SIZE(addr)) { +			ret = t4_alloc_mac_filt(pi->adapter, 0, pi->viid, free, +					naddr, addr, filt_idx, &uhash, sleep); +			if (ret < 0) +				return ret; + +			free = false; +			naddr = 0; +		} +	} + +	/* next set up the multicast addresses */ +	netdev_for_each_mc_addr(d, dev) { +		addr[naddr++] = d->dmi_addr; +		if (naddr >= ARRAY_SIZE(addr) || d->next == NULL) { +			ret = t4_alloc_mac_filt(pi->adapter, 0, pi->viid, free, +					naddr, addr, filt_idx, &mhash, sleep); +			if (ret < 0) +				return ret; + +			free = false; +			naddr = 0; +		} +	} + +	return t4_set_addr_hash(pi->adapter, 0, pi->viid, uhash != 0, +				uhash | mhash, sleep); +} + +/* + * Set Rx properties of a port, such as promiscruity, address filters, and MTU. + * If @mtu is -1 it is left unchanged. + */ +static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok) +{ +	int ret; +	struct port_info *pi = netdev_priv(dev); + +	ret = set_addr_filters(dev, sleep_ok); +	if (ret == 0) +		ret = t4_set_rxmode(pi->adapter, 0, pi->viid, mtu, +				    (dev->flags & IFF_PROMISC) ? 1 : 0, +				    (dev->flags & IFF_ALLMULTI) ? 1 : 0, 1, +				    sleep_ok); +	return ret; +} + +/** + *	link_start - enable a port + *	@dev: the port to enable + * + *	Performs the MAC and PHY actions needed to enable a port. + */ +static int link_start(struct net_device *dev) +{ +	int ret; +	struct port_info *pi = netdev_priv(dev); + +	/* +	 * We do not set address filters and promiscuity here, the stack does +	 * that step explicitly. +	 */ +	ret = t4_set_rxmode(pi->adapter, 0, pi->viid, dev->mtu, -1, -1, -1, +			    true); +	if (ret == 0) { +		ret = t4_change_mac(pi->adapter, 0, pi->viid, +				    pi->xact_addr_filt, dev->dev_addr, true, +				    false); +		if (ret >= 0) { +			pi->xact_addr_filt = ret; +			ret = 0; +		} +	} +	if (ret == 0) +		ret = t4_link_start(pi->adapter, 0, pi->tx_chan, &pi->link_cfg); +	if (ret == 0) +		ret = t4_enable_vi(pi->adapter, 0, pi->viid, true, true); +	return ret; +} + +/* + * Response queue handler for the FW event queue. + */ +static int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp, +			  const struct pkt_gl *gl) +{ +	u8 opcode = ((const struct rss_header *)rsp)->opcode; + +	rsp++;                                          /* skip RSS header */ +	if (likely(opcode == CPL_SGE_EGR_UPDATE)) { +		const struct cpl_sge_egr_update *p = (void *)rsp; +		unsigned int qid = EGR_QID(ntohl(p->opcode_qid)); +		struct sge_txq *txq = q->adap->sge.egr_map[qid]; + +		txq->restarts++; +		if ((u8 *)txq < (u8 *)q->adap->sge.ethrxq) { +			struct sge_eth_txq *eq; + +			eq = container_of(txq, struct sge_eth_txq, q); +			netif_tx_wake_queue(eq->txq); +		} else { +			struct sge_ofld_txq *oq; + +			oq = container_of(txq, struct sge_ofld_txq, q); +			tasklet_schedule(&oq->qresume_tsk); +		} +	} else if (opcode == CPL_FW6_MSG || opcode == CPL_FW4_MSG) { +		const struct cpl_fw6_msg *p = (void *)rsp; + +		if (p->type == 0) +			t4_handle_fw_rpl(q->adap, p->data); +	} else if (opcode == CPL_L2T_WRITE_RPL) { +		const struct cpl_l2t_write_rpl *p = (void *)rsp; + +		do_l2t_write_rpl(q->adap, p); +	} else +		dev_err(q->adap->pdev_dev, +			"unexpected CPL %#x on FW event queue\n", opcode); +	return 0; +} + +/** + *	uldrx_handler - response queue handler for ULD queues + *	@q: the response queue that received the packet + *	@rsp: the response queue descriptor holding the offload message + *	@gl: the gather list of packet fragments + * + *	Deliver an ingress offload packet to a ULD.  All processing is done by + *	the ULD, we just maintain statistics. + */ +static int uldrx_handler(struct sge_rspq *q, const __be64 *rsp, +			 const struct pkt_gl *gl) +{ +	struct sge_ofld_rxq *rxq = container_of(q, struct sge_ofld_rxq, rspq); + +	if (ulds[q->uld].rx_handler(q->adap->uld_handle[q->uld], rsp, gl)) { +		rxq->stats.nomem++; +		return -1; +	} +	if (gl == NULL) +		rxq->stats.imm++; +	else if (gl == CXGB4_MSG_AN) +		rxq->stats.an++; +	else +		rxq->stats.pkts++; +	return 0; +} + +static void disable_msi(struct adapter *adapter) +{ +	if (adapter->flags & USING_MSIX) { +		pci_disable_msix(adapter->pdev); +		adapter->flags &= ~USING_MSIX; +	} else if (adapter->flags & USING_MSI) { +		pci_disable_msi(adapter->pdev); +		adapter->flags &= ~USING_MSI; +	} +} + +/* + * Interrupt handler for non-data events used with MSI-X. + */ +static irqreturn_t t4_nondata_intr(int irq, void *cookie) +{ +	struct adapter *adap = cookie; + +	u32 v = t4_read_reg(adap, MYPF_REG(PL_PF_INT_CAUSE)); +	if (v & PFSW) { +		adap->swintr = 1; +		t4_write_reg(adap, MYPF_REG(PL_PF_INT_CAUSE), v); +	} +	t4_slow_intr_handler(adap); +	return IRQ_HANDLED; +} + +/* + * Name the MSI-X interrupts. + */ +static void name_msix_vecs(struct adapter *adap) +{ +	int i, j, msi_idx = 2, n = sizeof(adap->msix_info[0].desc) - 1; + +	/* non-data interrupts */ +	snprintf(adap->msix_info[0].desc, n, "%s", adap->name); +	adap->msix_info[0].desc[n] = 0; + +	/* FW events */ +	snprintf(adap->msix_info[1].desc, n, "%s-FWeventq", adap->name); +	adap->msix_info[1].desc[n] = 0; + +	/* Ethernet queues */ +	for_each_port(adap, j) { +		struct net_device *d = adap->port[j]; +		const struct port_info *pi = netdev_priv(d); + +		for (i = 0; i < pi->nqsets; i++, msi_idx++) { +			snprintf(adap->msix_info[msi_idx].desc, n, "%s-Rx%d", +				 d->name, i); +			adap->msix_info[msi_idx].desc[n] = 0; +		} +	} + +	/* offload queues */ +	for_each_ofldrxq(&adap->sge, i) { +		snprintf(adap->msix_info[msi_idx].desc, n, "%s-ofld%d", +			 adap->name, i); +		adap->msix_info[msi_idx++].desc[n] = 0; +	} +	for_each_rdmarxq(&adap->sge, i) { +		snprintf(adap->msix_info[msi_idx].desc, n, "%s-rdma%d", +			 adap->name, i); +		adap->msix_info[msi_idx++].desc[n] = 0; +	} +} + +static int request_msix_queue_irqs(struct adapter *adap) +{ +	struct sge *s = &adap->sge; +	int err, ethqidx, ofldqidx = 0, rdmaqidx = 0, msi = 2; + +	err = request_irq(adap->msix_info[1].vec, t4_sge_intr_msix, 0, +			  adap->msix_info[1].desc, &s->fw_evtq); +	if (err) +		return err; + +	for_each_ethrxq(s, ethqidx) { +		err = request_irq(adap->msix_info[msi].vec, t4_sge_intr_msix, 0, +				  adap->msix_info[msi].desc, +				  &s->ethrxq[ethqidx].rspq); +		if (err) +			goto unwind; +		msi++; +	} +	for_each_ofldrxq(s, ofldqidx) { +		err = request_irq(adap->msix_info[msi].vec, t4_sge_intr_msix, 0, +				  adap->msix_info[msi].desc, +				  &s->ofldrxq[ofldqidx].rspq); +		if (err) +			goto unwind; +		msi++; +	} +	for_each_rdmarxq(s, rdmaqidx) { +		err = request_irq(adap->msix_info[msi].vec, t4_sge_intr_msix, 0, +				  adap->msix_info[msi].desc, +				  &s->rdmarxq[rdmaqidx].rspq); +		if (err) +			goto unwind; +		msi++; +	} +	return 0; + +unwind: +	while (--rdmaqidx >= 0) +		free_irq(adap->msix_info[--msi].vec, +			 &s->rdmarxq[rdmaqidx].rspq); +	while (--ofldqidx >= 0) +		free_irq(adap->msix_info[--msi].vec, +			 &s->ofldrxq[ofldqidx].rspq); +	while (--ethqidx >= 0) +		free_irq(adap->msix_info[--msi].vec, &s->ethrxq[ethqidx].rspq); +	free_irq(adap->msix_info[1].vec, &s->fw_evtq); +	return err; +} + +static void free_msix_queue_irqs(struct adapter *adap) +{ +	int i, msi = 2; +	struct sge *s = &adap->sge; + +	free_irq(adap->msix_info[1].vec, &s->fw_evtq); +	for_each_ethrxq(s, i) +		free_irq(adap->msix_info[msi++].vec, &s->ethrxq[i].rspq); +	for_each_ofldrxq(s, i) +		free_irq(adap->msix_info[msi++].vec, &s->ofldrxq[i].rspq); +	for_each_rdmarxq(s, i) +		free_irq(adap->msix_info[msi++].vec, &s->rdmarxq[i].rspq); +} + +/** + *	setup_rss - configure RSS + *	@adap: the adapter + * + *	Sets up RSS to distribute packets to multiple receive queues.  We + *	configure the RSS CPU lookup table to distribute to the number of HW + *	receive queues, and the response queue lookup table to narrow that + *	down to the response queues actually configured for each port. + *	We always configure the RSS mapping for all ports since the mapping + *	table has plenty of entries. + */ +static int setup_rss(struct adapter *adap) +{ +	int i, j, err; +	u16 rss[MAX_ETH_QSETS]; + +	for_each_port(adap, i) { +		const struct port_info *pi = adap2pinfo(adap, i); +		const struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; + +		for (j = 0; j < pi->nqsets; j++) +			rss[j] = q[j].rspq.abs_id; + +		err = t4_config_rss_range(adap, 0, pi->viid, 0, pi->rss_size, +					  rss, pi->nqsets); +		if (err) +			return err; +	} +	return 0; +} + +/* + * Wait until all NAPI handlers are descheduled. + */ +static void quiesce_rx(struct adapter *adap) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(adap->sge.ingr_map); i++) { +		struct sge_rspq *q = adap->sge.ingr_map[i]; + +		if (q && q->handler) +			napi_disable(&q->napi); +	} +} + +/* + * Enable NAPI scheduling and interrupt generation for all Rx queues. + */ +static void enable_rx(struct adapter *adap) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(adap->sge.ingr_map); i++) { +		struct sge_rspq *q = adap->sge.ingr_map[i]; + +		if (!q) +			continue; +		if (q->handler) +			napi_enable(&q->napi); +		/* 0-increment GTS to start the timer and enable interrupts */ +		t4_write_reg(adap, MYPF_REG(SGE_PF_GTS), +			     SEINTARM(q->intr_params) | +			     INGRESSQID(q->cntxt_id)); +	} +} + +/** + *	setup_sge_queues - configure SGE Tx/Rx/response queues + *	@adap: the adapter + * + *	Determines how many sets of SGE queues to use and initializes them. + *	We support multiple queue sets per port if we have MSI-X, otherwise + *	just one queue set per port. + */ +static int setup_sge_queues(struct adapter *adap) +{ +	int err, msi_idx, i, j; +	struct sge *s = &adap->sge; + +	bitmap_zero(s->starving_fl, MAX_EGRQ); +	bitmap_zero(s->txq_maperr, MAX_EGRQ); + +	if (adap->flags & USING_MSIX) +		msi_idx = 1;         /* vector 0 is for non-queue interrupts */ +	else { +		err = t4_sge_alloc_rxq(adap, &s->intrq, false, adap->port[0], 0, +				       NULL, NULL); +		if (err) +			return err; +		msi_idx = -((int)s->intrq.abs_id + 1); +	} + +	err = t4_sge_alloc_rxq(adap, &s->fw_evtq, true, adap->port[0], +			       msi_idx, NULL, fwevtq_handler); +	if (err) { +freeout:	t4_free_sge_resources(adap); +		return err; +	} + +	for_each_port(adap, i) { +		struct net_device *dev = adap->port[i]; +		struct port_info *pi = netdev_priv(dev); +		struct sge_eth_rxq *q = &s->ethrxq[pi->first_qset]; +		struct sge_eth_txq *t = &s->ethtxq[pi->first_qset]; + +		for (j = 0; j < pi->nqsets; j++, q++) { +			if (msi_idx > 0) +				msi_idx++; +			err = t4_sge_alloc_rxq(adap, &q->rspq, false, dev, +					       msi_idx, &q->fl, +					       t4_ethrx_handler); +			if (err) +				goto freeout; +			q->rspq.idx = j; +			memset(&q->stats, 0, sizeof(q->stats)); +		} +		for (j = 0; j < pi->nqsets; j++, t++) { +			err = t4_sge_alloc_eth_txq(adap, t, dev, +					netdev_get_tx_queue(dev, j), +					s->fw_evtq.cntxt_id); +			if (err) +				goto freeout; +		} +	} + +	j = s->ofldqsets / adap->params.nports; /* ofld queues per channel */ +	for_each_ofldrxq(s, i) { +		struct sge_ofld_rxq *q = &s->ofldrxq[i]; +		struct net_device *dev = adap->port[i / j]; + +		if (msi_idx > 0) +			msi_idx++; +		err = t4_sge_alloc_rxq(adap, &q->rspq, false, dev, msi_idx, +				       &q->fl, uldrx_handler); +		if (err) +			goto freeout; +		memset(&q->stats, 0, sizeof(q->stats)); +		s->ofld_rxq[i] = q->rspq.abs_id; +		err = t4_sge_alloc_ofld_txq(adap, &s->ofldtxq[i], dev, +					    s->fw_evtq.cntxt_id); +		if (err) +			goto freeout; +	} + +	for_each_rdmarxq(s, i) { +		struct sge_ofld_rxq *q = &s->rdmarxq[i]; + +		if (msi_idx > 0) +			msi_idx++; +		err = t4_sge_alloc_rxq(adap, &q->rspq, false, adap->port[i], +				       msi_idx, &q->fl, uldrx_handler); +		if (err) +			goto freeout; +		memset(&q->stats, 0, sizeof(q->stats)); +		s->rdma_rxq[i] = q->rspq.abs_id; +	} + +	for_each_port(adap, i) { +		/* +		 * Note that ->rdmarxq[i].rspq.cntxt_id below is 0 if we don't +		 * have RDMA queues, and that's the right value. +		 */ +		err = t4_sge_alloc_ctrl_txq(adap, &s->ctrlq[i], adap->port[i], +					    s->fw_evtq.cntxt_id, +					    s->rdmarxq[i].rspq.cntxt_id); +		if (err) +			goto freeout; +	} + +	t4_write_reg(adap, MPS_TRC_RSS_CONTROL, +		     RSSCONTROL(netdev2pinfo(adap->port[0])->tx_chan) | +		     QUEUENUMBER(s->ethrxq[0].rspq.abs_id)); +	return 0; +} + +/* + * Returns 0 if new FW was successfully loaded, a positive errno if a load was + * started but failed, and a negative errno if flash load couldn't start. + */ +static int upgrade_fw(struct adapter *adap) +{ +	int ret; +	u32 vers; +	const struct fw_hdr *hdr; +	const struct firmware *fw; +	struct device *dev = adap->pdev_dev; + +	ret = request_firmware(&fw, FW_FNAME, dev); +	if (ret < 0) { +		dev_err(dev, "unable to load firmware image " FW_FNAME +			", error %d\n", ret); +		return ret; +	} + +	hdr = (const struct fw_hdr *)fw->data; +	vers = ntohl(hdr->fw_ver); +	if (FW_HDR_FW_VER_MAJOR_GET(vers) != FW_VERSION_MAJOR) { +		ret = -EINVAL;              /* wrong major version, won't do */ +		goto out; +	} + +	/* +	 * If the flash FW is unusable or we found something newer, load it. +	 */ +	if (FW_HDR_FW_VER_MAJOR_GET(adap->params.fw_vers) != FW_VERSION_MAJOR || +	    vers > adap->params.fw_vers) { +		ret = -t4_load_fw(adap, fw->data, fw->size); +		if (!ret) +			dev_info(dev, "firmware upgraded to version %pI4 from " +				 FW_FNAME "\n", &hdr->fw_ver); +	} +out:	release_firmware(fw); +	return ret; +} + +/* + * Allocate a chunk of memory using kmalloc or, if that fails, vmalloc. + * The allocated memory is cleared. + */ +void *t4_alloc_mem(size_t size) +{ +	void *p = kmalloc(size, GFP_KERNEL); + +	if (!p) +		p = vmalloc(size); +	if (p) +		memset(p, 0, size); +	return p; +} + +/* + * Free memory allocated through alloc_mem(). + */ +void t4_free_mem(void *addr) +{ +	if (is_vmalloc_addr(addr)) +		vfree(addr); +	else +		kfree(addr); +} + +static inline int is_offload(const struct adapter *adap) +{ +	return adap->params.offload; +} + +/* + * Implementation of ethtool operations. + */ + +static u32 get_msglevel(struct net_device *dev) +{ +	return netdev2adap(dev)->msg_enable; +} + +static void set_msglevel(struct net_device *dev, u32 val) +{ +	netdev2adap(dev)->msg_enable = val; +} + +static char stats_strings[][ETH_GSTRING_LEN] = { +	"TxOctetsOK         ", +	"TxFramesOK         ", +	"TxBroadcastFrames  ", +	"TxMulticastFrames  ", +	"TxUnicastFrames    ", +	"TxErrorFrames      ", + +	"TxFrames64         ", +	"TxFrames65To127    ", +	"TxFrames128To255   ", +	"TxFrames256To511   ", +	"TxFrames512To1023  ", +	"TxFrames1024To1518 ", +	"TxFrames1519ToMax  ", + +	"TxFramesDropped    ", +	"TxPauseFrames      ", +	"TxPPP0Frames       ", +	"TxPPP1Frames       ", +	"TxPPP2Frames       ", +	"TxPPP3Frames       ", +	"TxPPP4Frames       ", +	"TxPPP5Frames       ", +	"TxPPP6Frames       ", +	"TxPPP7Frames       ", + +	"RxOctetsOK         ", +	"RxFramesOK         ", +	"RxBroadcastFrames  ", +	"RxMulticastFrames  ", +	"RxUnicastFrames    ", + +	"RxFramesTooLong    ", +	"RxJabberErrors     ", +	"RxFCSErrors        ", +	"RxLengthErrors     ", +	"RxSymbolErrors     ", +	"RxRuntFrames       ", + +	"RxFrames64         ", +	"RxFrames65To127    ", +	"RxFrames128To255   ", +	"RxFrames256To511   ", +	"RxFrames512To1023  ", +	"RxFrames1024To1518 ", +	"RxFrames1519ToMax  ", + +	"RxPauseFrames      ", +	"RxPPP0Frames       ", +	"RxPPP1Frames       ", +	"RxPPP2Frames       ", +	"RxPPP3Frames       ", +	"RxPPP4Frames       ", +	"RxPPP5Frames       ", +	"RxPPP6Frames       ", +	"RxPPP7Frames       ", + +	"RxBG0FramesDropped ", +	"RxBG1FramesDropped ", +	"RxBG2FramesDropped ", +	"RxBG3FramesDropped ", +	"RxBG0FramesTrunc   ", +	"RxBG1FramesTrunc   ", +	"RxBG2FramesTrunc   ", +	"RxBG3FramesTrunc   ", + +	"TSO                ", +	"TxCsumOffload      ", +	"RxCsumGood         ", +	"VLANextractions    ", +	"VLANinsertions     ", +}; + +static int get_sset_count(struct net_device *dev, int sset) +{ +	switch (sset) { +	case ETH_SS_STATS: +		return ARRAY_SIZE(stats_strings); +	default: +		return -EOPNOTSUPP; +	} +} + +#define T4_REGMAP_SIZE (160 * 1024) + +static int get_regs_len(struct net_device *dev) +{ +	return T4_REGMAP_SIZE; +} + +static int get_eeprom_len(struct net_device *dev) +{ +	return EEPROMSIZE; +} + +static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ +	struct adapter *adapter = netdev2adap(dev); + +	strcpy(info->driver, KBUILD_MODNAME); +	strcpy(info->version, DRV_VERSION); +	strcpy(info->bus_info, pci_name(adapter->pdev)); + +	if (!adapter->params.fw_vers) +		strcpy(info->fw_version, "N/A"); +	else +		snprintf(info->fw_version, sizeof(info->fw_version), +			"%u.%u.%u.%u, TP %u.%u.%u.%u", +			FW_HDR_FW_VER_MAJOR_GET(adapter->params.fw_vers), +			FW_HDR_FW_VER_MINOR_GET(adapter->params.fw_vers), +			FW_HDR_FW_VER_MICRO_GET(adapter->params.fw_vers), +			FW_HDR_FW_VER_BUILD_GET(adapter->params.fw_vers), +			FW_HDR_FW_VER_MAJOR_GET(adapter->params.tp_vers), +			FW_HDR_FW_VER_MINOR_GET(adapter->params.tp_vers), +			FW_HDR_FW_VER_MICRO_GET(adapter->params.tp_vers), +			FW_HDR_FW_VER_BUILD_GET(adapter->params.tp_vers)); +} + +static void get_strings(struct net_device *dev, u32 stringset, u8 *data) +{ +	if (stringset == ETH_SS_STATS) +		memcpy(data, stats_strings, sizeof(stats_strings)); +} + +/* + * port stats maintained per queue of the port.  They should be in the same + * order as in stats_strings above. + */ +struct queue_port_stats { +	u64 tso; +	u64 tx_csum; +	u64 rx_csum; +	u64 vlan_ex; +	u64 vlan_ins; +}; + +static void collect_sge_port_stats(const struct adapter *adap, +		const struct port_info *p, struct queue_port_stats *s) +{ +	int i; +	const struct sge_eth_txq *tx = &adap->sge.ethtxq[p->first_qset]; +	const struct sge_eth_rxq *rx = &adap->sge.ethrxq[p->first_qset]; + +	memset(s, 0, sizeof(*s)); +	for (i = 0; i < p->nqsets; i++, rx++, tx++) { +		s->tso += tx->tso; +		s->tx_csum += tx->tx_cso; +		s->rx_csum += rx->stats.rx_cso; +		s->vlan_ex += rx->stats.vlan_ex; +		s->vlan_ins += tx->vlan_ins; +	} +} + +static void get_stats(struct net_device *dev, struct ethtool_stats *stats, +		      u64 *data) +{ +	struct port_info *pi = netdev_priv(dev); +	struct adapter *adapter = pi->adapter; + +	t4_get_port_stats(adapter, pi->tx_chan, (struct port_stats *)data); + +	data += sizeof(struct port_stats) / sizeof(u64); +	collect_sge_port_stats(adapter, pi, (struct queue_port_stats *)data); +} + +/* + * Return a version number to identify the type of adapter.  The scheme is: + * - bits 0..9: chip version + * - bits 10..15: chip revision + */ +static inline unsigned int mk_adap_vers(const struct adapter *ap) +{ +	return 4 | (ap->params.rev << 10); +} + +static void reg_block_dump(struct adapter *ap, void *buf, unsigned int start, +			   unsigned int end) +{ +	u32 *p = buf + start; + +	for ( ; start <= end; start += sizeof(u32)) +		*p++ = t4_read_reg(ap, start); +} + +static void get_regs(struct net_device *dev, struct ethtool_regs *regs, +		     void *buf) +{ +	static const unsigned int reg_ranges[] = { +		0x1008, 0x1108, +		0x1180, 0x11b4, +		0x11fc, 0x123c, +		0x1300, 0x173c, +		0x1800, 0x18fc, +		0x3000, 0x30d8, +		0x30e0, 0x5924, +		0x5960, 0x59d4, +		0x5a00, 0x5af8, +		0x6000, 0x6098, +		0x6100, 0x6150, +		0x6200, 0x6208, +		0x6240, 0x6248, +		0x6280, 0x6338, +		0x6370, 0x638c, +		0x6400, 0x643c, +		0x6500, 0x6524, +		0x6a00, 0x6a38, +		0x6a60, 0x6a78, +		0x6b00, 0x6b84, +		0x6bf0, 0x6c84, +		0x6cf0, 0x6d84, +		0x6df0, 0x6e84, +		0x6ef0, 0x6f84, +		0x6ff0, 0x7084, +		0x70f0, 0x7184, +		0x71f0, 0x7284, +		0x72f0, 0x7384, +		0x73f0, 0x7450, +		0x7500, 0x7530, +		0x7600, 0x761c, +		0x7680, 0x76cc, +		0x7700, 0x7798, +		0x77c0, 0x77fc, +		0x7900, 0x79fc, +		0x7b00, 0x7c38, +		0x7d00, 0x7efc, +		0x8dc0, 0x8e1c, +		0x8e30, 0x8e78, +		0x8ea0, 0x8f6c, +		0x8fc0, 0x9074, +		0x90fc, 0x90fc, +		0x9400, 0x9458, +		0x9600, 0x96bc, +		0x9800, 0x9808, +		0x9820, 0x983c, +		0x9850, 0x9864, +		0x9c00, 0x9c6c, +		0x9c80, 0x9cec, +		0x9d00, 0x9d6c, +		0x9d80, 0x9dec, +		0x9e00, 0x9e6c, +		0x9e80, 0x9eec, +		0x9f00, 0x9f6c, +		0x9f80, 0x9fec, +		0xd004, 0xd03c, +		0xdfc0, 0xdfe0, +		0xe000, 0xea7c, +		0xf000, 0x11190, +		0x19040, 0x19124, +		0x19150, 0x191b0, +		0x191d0, 0x191e8, +		0x19238, 0x1924c, +		0x193f8, 0x19474, +		0x19490, 0x194f8, +		0x19800, 0x19f30, +		0x1a000, 0x1a06c, +		0x1a0b0, 0x1a120, +		0x1a128, 0x1a138, +		0x1a190, 0x1a1c4, +		0x1a1fc, 0x1a1fc, +		0x1e040, 0x1e04c, +		0x1e240, 0x1e28c, +		0x1e2c0, 0x1e2c0, +		0x1e2e0, 0x1e2e0, +		0x1e300, 0x1e384, +		0x1e3c0, 0x1e3c8, +		0x1e440, 0x1e44c, +		0x1e640, 0x1e68c, +		0x1e6c0, 0x1e6c0, +		0x1e6e0, 0x1e6e0, +		0x1e700, 0x1e784, +		0x1e7c0, 0x1e7c8, +		0x1e840, 0x1e84c, +		0x1ea40, 0x1ea8c, +		0x1eac0, 0x1eac0, +		0x1eae0, 0x1eae0, +		0x1eb00, 0x1eb84, +		0x1ebc0, 0x1ebc8, +		0x1ec40, 0x1ec4c, +		0x1ee40, 0x1ee8c, +		0x1eec0, 0x1eec0, +		0x1eee0, 0x1eee0, +		0x1ef00, 0x1ef84, +		0x1efc0, 0x1efc8, +		0x1f040, 0x1f04c, +		0x1f240, 0x1f28c, +		0x1f2c0, 0x1f2c0, +		0x1f2e0, 0x1f2e0, +		0x1f300, 0x1f384, +		0x1f3c0, 0x1f3c8, +		0x1f440, 0x1f44c, +		0x1f640, 0x1f68c, +		0x1f6c0, 0x1f6c0, +		0x1f6e0, 0x1f6e0, +		0x1f700, 0x1f784, +		0x1f7c0, 0x1f7c8, +		0x1f840, 0x1f84c, +		0x1fa40, 0x1fa8c, +		0x1fac0, 0x1fac0, +		0x1fae0, 0x1fae0, +		0x1fb00, 0x1fb84, +		0x1fbc0, 0x1fbc8, +		0x1fc40, 0x1fc4c, +		0x1fe40, 0x1fe8c, +		0x1fec0, 0x1fec0, +		0x1fee0, 0x1fee0, +		0x1ff00, 0x1ff84, +		0x1ffc0, 0x1ffc8, +		0x20000, 0x2002c, +		0x20100, 0x2013c, +		0x20190, 0x201c8, +		0x20200, 0x20318, +		0x20400, 0x20528, +		0x20540, 0x20614, +		0x21000, 0x21040, +		0x2104c, 0x21060, +		0x210c0, 0x210ec, +		0x21200, 0x21268, +		0x21270, 0x21284, +		0x212fc, 0x21388, +		0x21400, 0x21404, +		0x21500, 0x21518, +		0x2152c, 0x2153c, +		0x21550, 0x21554, +		0x21600, 0x21600, +		0x21608, 0x21628, +		0x21630, 0x2163c, +		0x21700, 0x2171c, +		0x21780, 0x2178c, +		0x21800, 0x21c38, +		0x21c80, 0x21d7c, +		0x21e00, 0x21e04, +		0x22000, 0x2202c, +		0x22100, 0x2213c, +		0x22190, 0x221c8, +		0x22200, 0x22318, +		0x22400, 0x22528, +		0x22540, 0x22614, +		0x23000, 0x23040, +		0x2304c, 0x23060, +		0x230c0, 0x230ec, +		0x23200, 0x23268, +		0x23270, 0x23284, +		0x232fc, 0x23388, +		0x23400, 0x23404, +		0x23500, 0x23518, +		0x2352c, 0x2353c, +		0x23550, 0x23554, +		0x23600, 0x23600, +		0x23608, 0x23628, +		0x23630, 0x2363c, +		0x23700, 0x2371c, +		0x23780, 0x2378c, +		0x23800, 0x23c38, +		0x23c80, 0x23d7c, +		0x23e00, 0x23e04, +		0x24000, 0x2402c, +		0x24100, 0x2413c, +		0x24190, 0x241c8, +		0x24200, 0x24318, +		0x24400, 0x24528, +		0x24540, 0x24614, +		0x25000, 0x25040, +		0x2504c, 0x25060, +		0x250c0, 0x250ec, +		0x25200, 0x25268, +		0x25270, 0x25284, +		0x252fc, 0x25388, +		0x25400, 0x25404, +		0x25500, 0x25518, +		0x2552c, 0x2553c, +		0x25550, 0x25554, +		0x25600, 0x25600, +		0x25608, 0x25628, +		0x25630, 0x2563c, +		0x25700, 0x2571c, +		0x25780, 0x2578c, +		0x25800, 0x25c38, +		0x25c80, 0x25d7c, +		0x25e00, 0x25e04, +		0x26000, 0x2602c, +		0x26100, 0x2613c, +		0x26190, 0x261c8, +		0x26200, 0x26318, +		0x26400, 0x26528, +		0x26540, 0x26614, +		0x27000, 0x27040, +		0x2704c, 0x27060, +		0x270c0, 0x270ec, +		0x27200, 0x27268, +		0x27270, 0x27284, +		0x272fc, 0x27388, +		0x27400, 0x27404, +		0x27500, 0x27518, +		0x2752c, 0x2753c, +		0x27550, 0x27554, +		0x27600, 0x27600, +		0x27608, 0x27628, +		0x27630, 0x2763c, +		0x27700, 0x2771c, +		0x27780, 0x2778c, +		0x27800, 0x27c38, +		0x27c80, 0x27d7c, +		0x27e00, 0x27e04 +	}; + +	int i; +	struct adapter *ap = netdev2adap(dev); + +	regs->version = mk_adap_vers(ap); + +	memset(buf, 0, T4_REGMAP_SIZE); +	for (i = 0; i < ARRAY_SIZE(reg_ranges); i += 2) +		reg_block_dump(ap, buf, reg_ranges[i], reg_ranges[i + 1]); +} + +static int restart_autoneg(struct net_device *dev) +{ +	struct port_info *p = netdev_priv(dev); + +	if (!netif_running(dev)) +		return -EAGAIN; +	if (p->link_cfg.autoneg != AUTONEG_ENABLE) +		return -EINVAL; +	t4_restart_aneg(p->adapter, 0, p->tx_chan); +	return 0; +} + +static int identify_port(struct net_device *dev, u32 data) +{ +	if (data == 0) +		data = 2;     /* default to 2 seconds */ + +	return t4_identify_port(netdev2adap(dev), 0, netdev2pinfo(dev)->viid, +				data * 5); +} + +static unsigned int from_fw_linkcaps(unsigned int type, unsigned int caps) +{ +	unsigned int v = 0; + +	if (type == FW_PORT_TYPE_BT_SGMII || type == FW_PORT_TYPE_BT_XAUI) { +		v |= SUPPORTED_TP; +		if (caps & FW_PORT_CAP_SPEED_100M) +			v |= SUPPORTED_100baseT_Full; +		if (caps & FW_PORT_CAP_SPEED_1G) +			v |= SUPPORTED_1000baseT_Full; +		if (caps & FW_PORT_CAP_SPEED_10G) +			v |= SUPPORTED_10000baseT_Full; +	} else if (type == FW_PORT_TYPE_KX4 || type == FW_PORT_TYPE_KX) { +		v |= SUPPORTED_Backplane; +		if (caps & FW_PORT_CAP_SPEED_1G) +			v |= SUPPORTED_1000baseKX_Full; +		if (caps & FW_PORT_CAP_SPEED_10G) +			v |= SUPPORTED_10000baseKX4_Full; +	} else if (type == FW_PORT_TYPE_KR) +		v |= SUPPORTED_Backplane | SUPPORTED_10000baseKR_Full; +	else if (type == FW_PORT_TYPE_FIBER) +		v |= SUPPORTED_FIBRE; + +	if (caps & FW_PORT_CAP_ANEG) +		v |= SUPPORTED_Autoneg; +	return v; +} + +static unsigned int to_fw_linkcaps(unsigned int caps) +{ +	unsigned int v = 0; + +	if (caps & ADVERTISED_100baseT_Full) +		v |= FW_PORT_CAP_SPEED_100M; +	if (caps & ADVERTISED_1000baseT_Full) +		v |= FW_PORT_CAP_SPEED_1G; +	if (caps & ADVERTISED_10000baseT_Full) +		v |= FW_PORT_CAP_SPEED_10G; +	return v; +} + +static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ +	const struct port_info *p = netdev_priv(dev); + +	if (p->port_type == FW_PORT_TYPE_BT_SGMII || +	    p->port_type == FW_PORT_TYPE_BT_XAUI) +		cmd->port = PORT_TP; +	else if (p->port_type == FW_PORT_TYPE_FIBER) +		cmd->port = PORT_FIBRE; +	else if (p->port_type == FW_PORT_TYPE_TWINAX) +		cmd->port = PORT_DA; +	else +		cmd->port = PORT_OTHER; + +	if (p->mdio_addr >= 0) { +		cmd->phy_address = p->mdio_addr; +		cmd->transceiver = XCVR_EXTERNAL; +		cmd->mdio_support = p->port_type == FW_PORT_TYPE_BT_SGMII ? +			MDIO_SUPPORTS_C22 : MDIO_SUPPORTS_C45; +	} else { +		cmd->phy_address = 0;  /* not really, but no better option */ +		cmd->transceiver = XCVR_INTERNAL; +		cmd->mdio_support = 0; +	} + +	cmd->supported = from_fw_linkcaps(p->port_type, p->link_cfg.supported); +	cmd->advertising = from_fw_linkcaps(p->port_type, +					    p->link_cfg.advertising); +	cmd->speed = netif_carrier_ok(dev) ? p->link_cfg.speed : 0; +	cmd->duplex = DUPLEX_FULL; +	cmd->autoneg = p->link_cfg.autoneg; +	cmd->maxtxpkt = 0; +	cmd->maxrxpkt = 0; +	return 0; +} + +static unsigned int speed_to_caps(int speed) +{ +	if (speed == SPEED_100) +		return FW_PORT_CAP_SPEED_100M; +	if (speed == SPEED_1000) +		return FW_PORT_CAP_SPEED_1G; +	if (speed == SPEED_10000) +		return FW_PORT_CAP_SPEED_10G; +	return 0; +} + +static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ +	unsigned int cap; +	struct port_info *p = netdev_priv(dev); +	struct link_config *lc = &p->link_cfg; + +	if (cmd->duplex != DUPLEX_FULL)     /* only full-duplex supported */ +		return -EINVAL; + +	if (!(lc->supported & FW_PORT_CAP_ANEG)) { +		/* +		 * PHY offers a single speed.  See if that's what's +		 * being requested. +		 */ +		if (cmd->autoneg == AUTONEG_DISABLE && +		    (lc->supported & speed_to_caps(cmd->speed))) +				return 0; +		return -EINVAL; +	} + +	if (cmd->autoneg == AUTONEG_DISABLE) { +		cap = speed_to_caps(cmd->speed); + +		if (!(lc->supported & cap) || cmd->speed == SPEED_1000 || +		    cmd->speed == SPEED_10000) +			return -EINVAL; +		lc->requested_speed = cap; +		lc->advertising = 0; +	} else { +		cap = to_fw_linkcaps(cmd->advertising); +		if (!(lc->supported & cap)) +			return -EINVAL; +		lc->requested_speed = 0; +		lc->advertising = cap | FW_PORT_CAP_ANEG; +	} +	lc->autoneg = cmd->autoneg; + +	if (netif_running(dev)) +		return t4_link_start(p->adapter, 0, p->tx_chan, lc); +	return 0; +} + +static void get_pauseparam(struct net_device *dev, +			   struct ethtool_pauseparam *epause) +{ +	struct port_info *p = netdev_priv(dev); + +	epause->autoneg = (p->link_cfg.requested_fc & PAUSE_AUTONEG) != 0; +	epause->rx_pause = (p->link_cfg.fc & PAUSE_RX) != 0; +	epause->tx_pause = (p->link_cfg.fc & PAUSE_TX) != 0; +} + +static int set_pauseparam(struct net_device *dev, +			  struct ethtool_pauseparam *epause) +{ +	struct port_info *p = netdev_priv(dev); +	struct link_config *lc = &p->link_cfg; + +	if (epause->autoneg == AUTONEG_DISABLE) +		lc->requested_fc = 0; +	else if (lc->supported & FW_PORT_CAP_ANEG) +		lc->requested_fc = PAUSE_AUTONEG; +	else +		return -EINVAL; + +	if (epause->rx_pause) +		lc->requested_fc |= PAUSE_RX; +	if (epause->tx_pause) +		lc->requested_fc |= PAUSE_TX; +	if (netif_running(dev)) +		return t4_link_start(p->adapter, 0, p->tx_chan, lc); +	return 0; +} + +static u32 get_rx_csum(struct net_device *dev) +{ +	struct port_info *p = netdev_priv(dev); + +	return p->rx_offload & RX_CSO; +} + +static int set_rx_csum(struct net_device *dev, u32 data) +{ +	struct port_info *p = netdev_priv(dev); + +	if (data) +		p->rx_offload |= RX_CSO; +	else +		p->rx_offload &= ~RX_CSO; +	return 0; +} + +static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) +{ +	const struct port_info *pi = netdev_priv(dev); +	const struct sge *s = &pi->adapter->sge; + +	e->rx_max_pending = MAX_RX_BUFFERS; +	e->rx_mini_max_pending = MAX_RSPQ_ENTRIES; +	e->rx_jumbo_max_pending = 0; +	e->tx_max_pending = MAX_TXQ_ENTRIES; + +	e->rx_pending = s->ethrxq[pi->first_qset].fl.size - 8; +	e->rx_mini_pending = s->ethrxq[pi->first_qset].rspq.size; +	e->rx_jumbo_pending = 0; +	e->tx_pending = s->ethtxq[pi->first_qset].q.size; +} + +static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e) +{ +	int i; +	const struct port_info *pi = netdev_priv(dev); +	struct adapter *adapter = pi->adapter; +	struct sge *s = &adapter->sge; + +	if (e->rx_pending > MAX_RX_BUFFERS || e->rx_jumbo_pending || +	    e->tx_pending > MAX_TXQ_ENTRIES || +	    e->rx_mini_pending > MAX_RSPQ_ENTRIES || +	    e->rx_mini_pending < MIN_RSPQ_ENTRIES || +	    e->rx_pending < MIN_FL_ENTRIES || e->tx_pending < MIN_TXQ_ENTRIES) +		return -EINVAL; + +	if (adapter->flags & FULL_INIT_DONE) +		return -EBUSY; + +	for (i = 0; i < pi->nqsets; ++i) { +		s->ethtxq[pi->first_qset + i].q.size = e->tx_pending; +		s->ethrxq[pi->first_qset + i].fl.size = e->rx_pending + 8; +		s->ethrxq[pi->first_qset + i].rspq.size = e->rx_mini_pending; +	} +	return 0; +} + +static int closest_timer(const struct sge *s, int time) +{ +	int i, delta, match = 0, min_delta = INT_MAX; + +	for (i = 0; i < ARRAY_SIZE(s->timer_val); i++) { +		delta = time - s->timer_val[i]; +		if (delta < 0) +			delta = -delta; +		if (delta < min_delta) { +			min_delta = delta; +			match = i; +		} +	} +	return match; +} + +static int closest_thres(const struct sge *s, int thres) +{ +	int i, delta, match = 0, min_delta = INT_MAX; + +	for (i = 0; i < ARRAY_SIZE(s->counter_val); i++) { +		delta = thres - s->counter_val[i]; +		if (delta < 0) +			delta = -delta; +		if (delta < min_delta) { +			min_delta = delta; +			match = i; +		} +	} +	return match; +} + +/* + * Return a queue's interrupt hold-off time in us.  0 means no timer. + */ +static unsigned int qtimer_val(const struct adapter *adap, +			       const struct sge_rspq *q) +{ +	unsigned int idx = q->intr_params >> 1; + +	return idx < SGE_NTIMERS ? adap->sge.timer_val[idx] : 0; +} + +/** + *	set_rxq_intr_params - set a queue's interrupt holdoff parameters + *	@adap: the adapter + *	@q: the Rx queue + *	@us: the hold-off time in us, or 0 to disable timer + *	@cnt: the hold-off packet count, or 0 to disable counter + * + *	Sets an Rx queue's interrupt hold-off time and packet count.  At least + *	one of the two needs to be enabled for the queue to generate interrupts. + */ +static int set_rxq_intr_params(struct adapter *adap, struct sge_rspq *q, +			       unsigned int us, unsigned int cnt) +{ +	if ((us | cnt) == 0) +		cnt = 1; + +	if (cnt) { +		int err; +		u32 v, new_idx; + +		new_idx = closest_thres(&adap->sge, cnt); +		if (q->desc && q->pktcnt_idx != new_idx) { +			/* the queue has already been created, update it */ +			v = FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) | +			    FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DMAQ_IQ_INTCNTTHRESH) | +			    FW_PARAMS_PARAM_YZ(q->cntxt_id); +			err = t4_set_params(adap, 0, 0, 0, 1, &v, &new_idx); +			if (err) +				return err; +		} +		q->pktcnt_idx = new_idx; +	} + +	us = us == 0 ? 6 : closest_timer(&adap->sge, us); +	q->intr_params = QINTR_TIMER_IDX(us) | (cnt > 0 ? QINTR_CNT_EN : 0); +	return 0; +} + +static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) +{ +	const struct port_info *pi = netdev_priv(dev); +	struct adapter *adap = pi->adapter; + +	return set_rxq_intr_params(adap, &adap->sge.ethrxq[pi->first_qset].rspq, +			c->rx_coalesce_usecs, c->rx_max_coalesced_frames); +} + +static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) +{ +	const struct port_info *pi = netdev_priv(dev); +	const struct adapter *adap = pi->adapter; +	const struct sge_rspq *rq = &adap->sge.ethrxq[pi->first_qset].rspq; + +	c->rx_coalesce_usecs = qtimer_val(adap, rq); +	c->rx_max_coalesced_frames = (rq->intr_params & QINTR_CNT_EN) ? +		adap->sge.counter_val[rq->pktcnt_idx] : 0; +	return 0; +} + +/* + * Translate a physical EEPROM address to virtual.  The first 1K is accessed + * through virtual addresses starting at 31K, the rest is accessed through + * virtual addresses starting at 0.  This mapping is correct only for PF0. + */ +static int eeprom_ptov(unsigned int phys_addr) +{ +	if (phys_addr < 1024) +		return phys_addr + (31 << 10); +	if (phys_addr < EEPROMSIZE) +		return phys_addr - 1024; +	return -EINVAL; +} + +/* + * The next two routines implement eeprom read/write from physical addresses. + * The physical->virtual translation is correct only for PF0. + */ +static int eeprom_rd_phys(struct adapter *adap, unsigned int phys_addr, u32 *v) +{ +	int vaddr = eeprom_ptov(phys_addr); + +	if (vaddr >= 0) +		vaddr = pci_read_vpd(adap->pdev, vaddr, sizeof(u32), v); +	return vaddr < 0 ? vaddr : 0; +} + +static int eeprom_wr_phys(struct adapter *adap, unsigned int phys_addr, u32 v) +{ +	int vaddr = eeprom_ptov(phys_addr); + +	if (vaddr >= 0) +		vaddr = pci_write_vpd(adap->pdev, vaddr, sizeof(u32), &v); +	return vaddr < 0 ? vaddr : 0; +} + +#define EEPROM_MAGIC 0x38E2F10C + +static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e, +		      u8 *data) +{ +	int i, err = 0; +	struct adapter *adapter = netdev2adap(dev); + +	u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL); +	if (!buf) +		return -ENOMEM; + +	e->magic = EEPROM_MAGIC; +	for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4) +		err = eeprom_rd_phys(adapter, i, (u32 *)&buf[i]); + +	if (!err) +		memcpy(data, buf + e->offset, e->len); +	kfree(buf); +	return err; +} + +static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, +		      u8 *data) +{ +	u8 *buf; +	int err = 0; +	u32 aligned_offset, aligned_len, *p; +	struct adapter *adapter = netdev2adap(dev); + +	if (eeprom->magic != EEPROM_MAGIC) +		return -EINVAL; + +	aligned_offset = eeprom->offset & ~3; +	aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3; + +	if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) { +		/* +		 * RMW possibly needed for first or last words. +		 */ +		buf = kmalloc(aligned_len, GFP_KERNEL); +		if (!buf) +			return -ENOMEM; +		err = eeprom_rd_phys(adapter, aligned_offset, (u32 *)buf); +		if (!err && aligned_len > 4) +			err = eeprom_rd_phys(adapter, +					     aligned_offset + aligned_len - 4, +					     (u32 *)&buf[aligned_len - 4]); +		if (err) +			goto out; +		memcpy(buf + (eeprom->offset & 3), data, eeprom->len); +	} else +		buf = data; + +	err = t4_seeprom_wp(adapter, false); +	if (err) +		goto out; + +	for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) { +		err = eeprom_wr_phys(adapter, aligned_offset, *p); +		aligned_offset += 4; +	} + +	if (!err) +		err = t4_seeprom_wp(adapter, true); +out: +	if (buf != data) +		kfree(buf); +	return err; +} + +static int set_flash(struct net_device *netdev, struct ethtool_flash *ef) +{ +	int ret; +	const struct firmware *fw; +	struct adapter *adap = netdev2adap(netdev); + +	ef->data[sizeof(ef->data) - 1] = '\0'; +	ret = request_firmware(&fw, ef->data, adap->pdev_dev); +	if (ret < 0) +		return ret; + +	ret = t4_load_fw(adap, fw->data, fw->size); +	release_firmware(fw); +	if (!ret) +		dev_info(adap->pdev_dev, "loaded firmware %s\n", ef->data); +	return ret; +} + +#define WOL_SUPPORTED (WAKE_BCAST | WAKE_MAGIC) +#define BCAST_CRC 0xa0ccc1a6 + +static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ +	wol->supported = WAKE_BCAST | WAKE_MAGIC; +	wol->wolopts = netdev2adap(dev)->wol; +	memset(&wol->sopass, 0, sizeof(wol->sopass)); +} + +static int set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ +	int err = 0; +	struct port_info *pi = netdev_priv(dev); + +	if (wol->wolopts & ~WOL_SUPPORTED) +		return -EINVAL; +	t4_wol_magic_enable(pi->adapter, pi->tx_chan, +			    (wol->wolopts & WAKE_MAGIC) ? dev->dev_addr : NULL); +	if (wol->wolopts & WAKE_BCAST) { +		err = t4_wol_pat_enable(pi->adapter, pi->tx_chan, 0xfe, ~0ULL, +					~0ULL, 0, false); +		if (!err) +			err = t4_wol_pat_enable(pi->adapter, pi->tx_chan, 1, +						~6ULL, ~0ULL, BCAST_CRC, true); +	} else +		t4_wol_pat_enable(pi->adapter, pi->tx_chan, 0, 0, 0, 0, false); +	return err; +} + +static int set_tso(struct net_device *dev, u32 value) +{ +	if (value) +		dev->features |= NETIF_F_TSO | NETIF_F_TSO6; +	else +		dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); +	return 0; +} + +static struct ethtool_ops cxgb_ethtool_ops = { +	.get_settings      = get_settings, +	.set_settings      = set_settings, +	.get_drvinfo       = get_drvinfo, +	.get_msglevel      = get_msglevel, +	.set_msglevel      = set_msglevel, +	.get_ringparam     = get_sge_param, +	.set_ringparam     = set_sge_param, +	.get_coalesce      = get_coalesce, +	.set_coalesce      = set_coalesce, +	.get_eeprom_len    = get_eeprom_len, +	.get_eeprom        = get_eeprom, +	.set_eeprom        = set_eeprom, +	.get_pauseparam    = get_pauseparam, +	.set_pauseparam    = set_pauseparam, +	.get_rx_csum       = get_rx_csum, +	.set_rx_csum       = set_rx_csum, +	.set_tx_csum       = ethtool_op_set_tx_ipv6_csum, +	.set_sg            = ethtool_op_set_sg, +	.get_link          = ethtool_op_get_link, +	.get_strings       = get_strings, +	.phys_id           = identify_port, +	.nway_reset        = restart_autoneg, +	.get_sset_count    = get_sset_count, +	.get_ethtool_stats = get_stats, +	.get_regs_len      = get_regs_len, +	.get_regs          = get_regs, +	.get_wol           = get_wol, +	.set_wol           = set_wol, +	.set_tso           = set_tso, +	.flash_device      = set_flash, +}; + +/* + * debugfs support + */ + +static int mem_open(struct inode *inode, struct file *file) +{ +	file->private_data = inode->i_private; +	return 0; +} + +static ssize_t mem_read(struct file *file, char __user *buf, size_t count, +			loff_t *ppos) +{ +	loff_t pos = *ppos; +	loff_t avail = file->f_path.dentry->d_inode->i_size; +	unsigned int mem = (uintptr_t)file->private_data & 3; +	struct adapter *adap = file->private_data - mem; + +	if (pos < 0) +		return -EINVAL; +	if (pos >= avail) +		return 0; +	if (count > avail - pos) +		count = avail - pos; + +	while (count) { +		size_t len; +		int ret, ofst; +		__be32 data[16]; + +		if (mem == MEM_MC) +			ret = t4_mc_read(adap, pos, data, NULL); +		else +			ret = t4_edc_read(adap, mem, pos, data, NULL); +		if (ret) +			return ret; + +		ofst = pos % sizeof(data); +		len = min(count, sizeof(data) - ofst); +		if (copy_to_user(buf, (u8 *)data + ofst, len)) +			return -EFAULT; + +		buf += len; +		pos += len; +		count -= len; +	} +	count = pos - *ppos; +	*ppos = pos; +	return count; +} + +static const struct file_operations mem_debugfs_fops = { +	.owner   = THIS_MODULE, +	.open    = mem_open, +	.read    = mem_read, +}; + +static void __devinit add_debugfs_mem(struct adapter *adap, const char *name, +				      unsigned int idx, unsigned int size_mb) +{ +	struct dentry *de; + +	de = debugfs_create_file(name, S_IRUSR, adap->debugfs_root, +				 (void *)adap + idx, &mem_debugfs_fops); +	if (de && de->d_inode) +		de->d_inode->i_size = size_mb << 20; +} + +static int __devinit setup_debugfs(struct adapter *adap) +{ +	int i; + +	if (IS_ERR_OR_NULL(adap->debugfs_root)) +		return -1; + +	i = t4_read_reg(adap, MA_TARGET_MEM_ENABLE); +	if (i & EDRAM0_ENABLE) +		add_debugfs_mem(adap, "edc0", MEM_EDC0, 5); +	if (i & EDRAM1_ENABLE) +		add_debugfs_mem(adap, "edc1", MEM_EDC1, 5); +	if (i & EXT_MEM_ENABLE) +		add_debugfs_mem(adap, "mc", MEM_MC, +			EXT_MEM_SIZE_GET(t4_read_reg(adap, MA_EXT_MEMORY_BAR))); +	if (adap->l2t) +		debugfs_create_file("l2t", S_IRUSR, adap->debugfs_root, adap, +				    &t4_l2t_fops); +	return 0; +} + +/* + * upper-layer driver support + */ + +/* + * Allocate an active-open TID and set it to the supplied value. + */ +int cxgb4_alloc_atid(struct tid_info *t, void *data) +{ +	int atid = -1; + +	spin_lock_bh(&t->atid_lock); +	if (t->afree) { +		union aopen_entry *p = t->afree; + +		atid = p - t->atid_tab; +		t->afree = p->next; +		p->data = data; +		t->atids_in_use++; +	} +	spin_unlock_bh(&t->atid_lock); +	return atid; +} +EXPORT_SYMBOL(cxgb4_alloc_atid); + +/* + * Release an active-open TID. + */ +void cxgb4_free_atid(struct tid_info *t, unsigned int atid) +{ +	union aopen_entry *p = &t->atid_tab[atid]; + +	spin_lock_bh(&t->atid_lock); +	p->next = t->afree; +	t->afree = p; +	t->atids_in_use--; +	spin_unlock_bh(&t->atid_lock); +} +EXPORT_SYMBOL(cxgb4_free_atid); + +/* + * Allocate a server TID and set it to the supplied value. + */ +int cxgb4_alloc_stid(struct tid_info *t, int family, void *data) +{ +	int stid; + +	spin_lock_bh(&t->stid_lock); +	if (family == PF_INET) { +		stid = find_first_zero_bit(t->stid_bmap, t->nstids); +		if (stid < t->nstids) +			__set_bit(stid, t->stid_bmap); +		else +			stid = -1; +	} else { +		stid = bitmap_find_free_region(t->stid_bmap, t->nstids, 2); +		if (stid < 0) +			stid = -1; +	} +	if (stid >= 0) { +		t->stid_tab[stid].data = data; +		stid += t->stid_base; +		t->stids_in_use++; +	} +	spin_unlock_bh(&t->stid_lock); +	return stid; +} +EXPORT_SYMBOL(cxgb4_alloc_stid); + +/* + * Release a server TID. + */ +void cxgb4_free_stid(struct tid_info *t, unsigned int stid, int family) +{ +	stid -= t->stid_base; +	spin_lock_bh(&t->stid_lock); +	if (family == PF_INET) +		__clear_bit(stid, t->stid_bmap); +	else +		bitmap_release_region(t->stid_bmap, stid, 2); +	t->stid_tab[stid].data = NULL; +	t->stids_in_use--; +	spin_unlock_bh(&t->stid_lock); +} +EXPORT_SYMBOL(cxgb4_free_stid); + +/* + * Populate a TID_RELEASE WR.  Caller must properly size the skb. + */ +static void mk_tid_release(struct sk_buff *skb, unsigned int chan, +			   unsigned int tid) +{ +	struct cpl_tid_release *req; + +	set_wr_txq(skb, CPL_PRIORITY_SETUP, chan); +	req = (struct cpl_tid_release *)__skb_put(skb, sizeof(*req)); +	INIT_TP_WR(req, tid); +	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, tid)); +} + +/* + * Queue a TID release request and if necessary schedule a work queue to + * process it. + */ +void cxgb4_queue_tid_release(struct tid_info *t, unsigned int chan, +			     unsigned int tid) +{ +	void **p = &t->tid_tab[tid]; +	struct adapter *adap = container_of(t, struct adapter, tids); + +	spin_lock_bh(&adap->tid_release_lock); +	*p = adap->tid_release_head; +	/* Low 2 bits encode the Tx channel number */ +	adap->tid_release_head = (void **)((uintptr_t)p | chan); +	if (!adap->tid_release_task_busy) { +		adap->tid_release_task_busy = true; +		schedule_work(&adap->tid_release_task); +	} +	spin_unlock_bh(&adap->tid_release_lock); +} +EXPORT_SYMBOL(cxgb4_queue_tid_release); + +/* + * Process the list of pending TID release requests. + */ +static void process_tid_release_list(struct work_struct *work) +{ +	struct sk_buff *skb; +	struct adapter *adap; + +	adap = container_of(work, struct adapter, tid_release_task); + +	spin_lock_bh(&adap->tid_release_lock); +	while (adap->tid_release_head) { +		void **p = adap->tid_release_head; +		unsigned int chan = (uintptr_t)p & 3; +		p = (void *)p - chan; + +		adap->tid_release_head = *p; +		*p = NULL; +		spin_unlock_bh(&adap->tid_release_lock); + +		while (!(skb = alloc_skb(sizeof(struct cpl_tid_release), +					 GFP_KERNEL))) +			schedule_timeout_uninterruptible(1); + +		mk_tid_release(skb, chan, p - adap->tids.tid_tab); +		t4_ofld_send(adap, skb); +		spin_lock_bh(&adap->tid_release_lock); +	} +	adap->tid_release_task_busy = false; +	spin_unlock_bh(&adap->tid_release_lock); +} + +/* + * Release a TID and inform HW.  If we are unable to allocate the release + * message we defer to a work queue. + */ +void cxgb4_remove_tid(struct tid_info *t, unsigned int chan, unsigned int tid) +{ +	void *old; +	struct sk_buff *skb; +	struct adapter *adap = container_of(t, struct adapter, tids); + +	old = t->tid_tab[tid]; +	skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_ATOMIC); +	if (likely(skb)) { +		t->tid_tab[tid] = NULL; +		mk_tid_release(skb, chan, tid); +		t4_ofld_send(adap, skb); +	} else +		cxgb4_queue_tid_release(t, chan, tid); +	if (old) +		atomic_dec(&t->tids_in_use); +} +EXPORT_SYMBOL(cxgb4_remove_tid); + +/* + * Allocate and initialize the TID tables.  Returns 0 on success. + */ +static int tid_init(struct tid_info *t) +{ +	size_t size; +	unsigned int natids = t->natids; + +	size = t->ntids * sizeof(*t->tid_tab) + natids * sizeof(*t->atid_tab) + +	       t->nstids * sizeof(*t->stid_tab) + +	       BITS_TO_LONGS(t->nstids) * sizeof(long); +	t->tid_tab = t4_alloc_mem(size); +	if (!t->tid_tab) +		return -ENOMEM; + +	t->atid_tab = (union aopen_entry *)&t->tid_tab[t->ntids]; +	t->stid_tab = (struct serv_entry *)&t->atid_tab[natids]; +	t->stid_bmap = (unsigned long *)&t->stid_tab[t->nstids]; +	spin_lock_init(&t->stid_lock); +	spin_lock_init(&t->atid_lock); + +	t->stids_in_use = 0; +	t->afree = NULL; +	t->atids_in_use = 0; +	atomic_set(&t->tids_in_use, 0); + +	/* Setup the free list for atid_tab and clear the stid bitmap. */ +	if (natids) { +		while (--natids) +			t->atid_tab[natids - 1].next = &t->atid_tab[natids]; +		t->afree = t->atid_tab; +	} +	bitmap_zero(t->stid_bmap, t->nstids); +	return 0; +} + +/** + *	cxgb4_create_server - create an IP server + *	@dev: the device + *	@stid: the server TID + *	@sip: local IP address to bind server to + *	@sport: the server's TCP port + *	@queue: queue to direct messages from this server to + * + *	Create an IP server for the given port and address. + *	Returns <0 on error and one of the %NET_XMIT_* values on success. + */ +int cxgb4_create_server(const struct net_device *dev, unsigned int stid, +			__be32 sip, __be16 sport, unsigned int queue) +{ +	unsigned int chan; +	struct sk_buff *skb; +	struct adapter *adap; +	struct cpl_pass_open_req *req; + +	skb = alloc_skb(sizeof(*req), GFP_KERNEL); +	if (!skb) +		return -ENOMEM; + +	adap = netdev2adap(dev); +	req = (struct cpl_pass_open_req *)__skb_put(skb, sizeof(*req)); +	INIT_TP_WR(req, 0); +	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ, stid)); +	req->local_port = sport; +	req->peer_port = htons(0); +	req->local_ip = sip; +	req->peer_ip = htonl(0); +	chan = netdev2pinfo(adap->sge.ingr_map[queue]->netdev)->tx_chan; +	req->opt0 = cpu_to_be64(TX_CHAN(chan)); +	req->opt1 = cpu_to_be64(CONN_POLICY_ASK | +				SYN_RSS_ENABLE | SYN_RSS_QUEUE(queue)); +	return t4_mgmt_tx(adap, skb); +} +EXPORT_SYMBOL(cxgb4_create_server); + +/** + *	cxgb4_create_server6 - create an IPv6 server + *	@dev: the device + *	@stid: the server TID + *	@sip: local IPv6 address to bind server to + *	@sport: the server's TCP port + *	@queue: queue to direct messages from this server to + * + *	Create an IPv6 server for the given port and address. + *	Returns <0 on error and one of the %NET_XMIT_* values on success. + */ +int cxgb4_create_server6(const struct net_device *dev, unsigned int stid, +			 const struct in6_addr *sip, __be16 sport, +			 unsigned int queue) +{ +	unsigned int chan; +	struct sk_buff *skb; +	struct adapter *adap; +	struct cpl_pass_open_req6 *req; + +	skb = alloc_skb(sizeof(*req), GFP_KERNEL); +	if (!skb) +		return -ENOMEM; + +	adap = netdev2adap(dev); +	req = (struct cpl_pass_open_req6 *)__skb_put(skb, sizeof(*req)); +	INIT_TP_WR(req, 0); +	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ6, stid)); +	req->local_port = sport; +	req->peer_port = htons(0); +	req->local_ip_hi = *(__be64 *)(sip->s6_addr); +	req->local_ip_lo = *(__be64 *)(sip->s6_addr + 8); +	req->peer_ip_hi = cpu_to_be64(0); +	req->peer_ip_lo = cpu_to_be64(0); +	chan = netdev2pinfo(adap->sge.ingr_map[queue]->netdev)->tx_chan; +	req->opt0 = cpu_to_be64(TX_CHAN(chan)); +	req->opt1 = cpu_to_be64(CONN_POLICY_ASK | +				SYN_RSS_ENABLE | SYN_RSS_QUEUE(queue)); +	return t4_mgmt_tx(adap, skb); +} +EXPORT_SYMBOL(cxgb4_create_server6); + +/** + *	cxgb4_best_mtu - find the entry in the MTU table closest to an MTU + *	@mtus: the HW MTU table + *	@mtu: the target MTU + *	@idx: index of selected entry in the MTU table + * + *	Returns the index and the value in the HW MTU table that is closest to + *	but does not exceed @mtu, unless @mtu is smaller than any value in the + *	table, in which case that smallest available value is selected. + */ +unsigned int cxgb4_best_mtu(const unsigned short *mtus, unsigned short mtu, +			    unsigned int *idx) +{ +	unsigned int i = 0; + +	while (i < NMTUS - 1 && mtus[i + 1] <= mtu) +		++i; +	if (idx) +		*idx = i; +	return mtus[i]; +} +EXPORT_SYMBOL(cxgb4_best_mtu); + +/** + *	cxgb4_port_chan - get the HW channel of a port + *	@dev: the net device for the port + * + *	Return the HW Tx channel of the given port. + */ +unsigned int cxgb4_port_chan(const struct net_device *dev) +{ +	return netdev2pinfo(dev)->tx_chan; +} +EXPORT_SYMBOL(cxgb4_port_chan); + +/** + *	cxgb4_port_viid - get the VI id of a port + *	@dev: the net device for the port + * + *	Return the VI id of the given port. + */ +unsigned int cxgb4_port_viid(const struct net_device *dev) +{ +	return netdev2pinfo(dev)->viid; +} +EXPORT_SYMBOL(cxgb4_port_viid); + +/** + *	cxgb4_port_idx - get the index of a port + *	@dev: the net device for the port + * + *	Return the index of the given port. + */ +unsigned int cxgb4_port_idx(const struct net_device *dev) +{ +	return netdev2pinfo(dev)->port_id; +} +EXPORT_SYMBOL(cxgb4_port_idx); + +/** + *	cxgb4_netdev_by_hwid - return the net device of a HW port + *	@pdev: identifies the adapter + *	@id: the HW port id + * + *	Return the net device associated with the interface with the given HW + *	id. + */ +struct net_device *cxgb4_netdev_by_hwid(struct pci_dev *pdev, unsigned int id) +{ +	const struct adapter *adap = pci_get_drvdata(pdev); + +	if (!adap || id >= NCHAN) +		return NULL; +	id = adap->chan_map[id]; +	return id < MAX_NPORTS ? adap->port[id] : NULL; +} +EXPORT_SYMBOL(cxgb4_netdev_by_hwid); + +void cxgb4_get_tcp_stats(struct pci_dev *pdev, struct tp_tcp_stats *v4, +			 struct tp_tcp_stats *v6) +{ +	struct adapter *adap = pci_get_drvdata(pdev); + +	spin_lock(&adap->stats_lock); +	t4_tp_get_tcp_stats(adap, v4, v6); +	spin_unlock(&adap->stats_lock); +} +EXPORT_SYMBOL(cxgb4_get_tcp_stats); + +void cxgb4_iscsi_init(struct net_device *dev, unsigned int tag_mask, +		      const unsigned int *pgsz_order) +{ +	struct adapter *adap = netdev2adap(dev); + +	t4_write_reg(adap, ULP_RX_ISCSI_TAGMASK, tag_mask); +	t4_write_reg(adap, ULP_RX_ISCSI_PSZ, HPZ0(pgsz_order[0]) | +		     HPZ1(pgsz_order[1]) | HPZ2(pgsz_order[2]) | +		     HPZ3(pgsz_order[3])); +} +EXPORT_SYMBOL(cxgb4_iscsi_init); + +static struct pci_driver cxgb4_driver; + +static void check_neigh_update(struct neighbour *neigh) +{ +	const struct device *parent; +	const struct net_device *netdev = neigh->dev; + +	if (netdev->priv_flags & IFF_802_1Q_VLAN) +		netdev = vlan_dev_real_dev(netdev); +	parent = netdev->dev.parent; +	if (parent && parent->driver == &cxgb4_driver.driver) +		t4_l2t_update(dev_get_drvdata(parent), neigh); +} + +static int netevent_cb(struct notifier_block *nb, unsigned long event, +		       void *data) +{ +	switch (event) { +	case NETEVENT_NEIGH_UPDATE: +		check_neigh_update(data); +		break; +	case NETEVENT_PMTU_UPDATE: +	case NETEVENT_REDIRECT: +	default: +		break; +	} +	return 0; +} + +static bool netevent_registered; +static struct notifier_block cxgb4_netevent_nb = { +	.notifier_call = netevent_cb +}; + +static void uld_attach(struct adapter *adap, unsigned int uld) +{ +	void *handle; +	struct cxgb4_lld_info lli; + +	lli.pdev = adap->pdev; +	lli.l2t = adap->l2t; +	lli.tids = &adap->tids; +	lli.ports = adap->port; +	lli.vr = &adap->vres; +	lli.mtus = adap->params.mtus; +	if (uld == CXGB4_ULD_RDMA) { +		lli.rxq_ids = adap->sge.rdma_rxq; +		lli.nrxq = adap->sge.rdmaqs; +	} else if (uld == CXGB4_ULD_ISCSI) { +		lli.rxq_ids = adap->sge.ofld_rxq; +		lli.nrxq = adap->sge.ofldqsets; +	} +	lli.ntxq = adap->sge.ofldqsets; +	lli.nchan = adap->params.nports; +	lli.nports = adap->params.nports; +	lli.wr_cred = adap->params.ofldq_wr_cred; +	lli.adapter_type = adap->params.rev; +	lli.iscsi_iolen = MAXRXDATA_GET(t4_read_reg(adap, TP_PARA_REG2)); +	lli.udb_density = 1 << QUEUESPERPAGEPF0_GET( +			t4_read_reg(adap, SGE_EGRESS_QUEUES_PER_PAGE_PF)); +	lli.ucq_density = 1 << QUEUESPERPAGEPF0_GET( +			t4_read_reg(adap, SGE_INGRESS_QUEUES_PER_PAGE_PF)); +	lli.gts_reg = adap->regs + MYPF_REG(SGE_PF_GTS); +	lli.db_reg = adap->regs + MYPF_REG(SGE_PF_KDOORBELL); +	lli.fw_vers = adap->params.fw_vers; + +	handle = ulds[uld].add(&lli); +	if (IS_ERR(handle)) { +		dev_warn(adap->pdev_dev, +			 "could not attach to the %s driver, error %ld\n", +			 uld_str[uld], PTR_ERR(handle)); +		return; +	} + +	adap->uld_handle[uld] = handle; + +	if (!netevent_registered) { +		register_netevent_notifier(&cxgb4_netevent_nb); +		netevent_registered = true; +	} +} + +static void attach_ulds(struct adapter *adap) +{ +	unsigned int i; + +	mutex_lock(&uld_mutex); +	list_add_tail(&adap->list_node, &adapter_list); +	for (i = 0; i < CXGB4_ULD_MAX; i++) +		if (ulds[i].add) +			uld_attach(adap, i); +	mutex_unlock(&uld_mutex); +} + +static void detach_ulds(struct adapter *adap) +{ +	unsigned int i; + +	mutex_lock(&uld_mutex); +	list_del(&adap->list_node); +	for (i = 0; i < CXGB4_ULD_MAX; i++) +		if (adap->uld_handle[i]) { +			ulds[i].state_change(adap->uld_handle[i], +					     CXGB4_STATE_DETACH); +			adap->uld_handle[i] = NULL; +		} +	if (netevent_registered && list_empty(&adapter_list)) { +		unregister_netevent_notifier(&cxgb4_netevent_nb); +		netevent_registered = false; +	} +	mutex_unlock(&uld_mutex); +} + +static void notify_ulds(struct adapter *adap, enum cxgb4_state new_state) +{ +	unsigned int i; + +	mutex_lock(&uld_mutex); +	for (i = 0; i < CXGB4_ULD_MAX; i++) +		if (adap->uld_handle[i]) +			ulds[i].state_change(adap->uld_handle[i], new_state); +	mutex_unlock(&uld_mutex); +} + +/** + *	cxgb4_register_uld - register an upper-layer driver + *	@type: the ULD type + *	@p: the ULD methods + * + *	Registers an upper-layer driver with this driver and notifies the ULD + *	about any presently available devices that support its type.  Returns + *	%-EBUSY if a ULD of the same type is already registered. + */ +int cxgb4_register_uld(enum cxgb4_uld type, const struct cxgb4_uld_info *p) +{ +	int ret = 0; +	struct adapter *adap; + +	if (type >= CXGB4_ULD_MAX) +		return -EINVAL; +	mutex_lock(&uld_mutex); +	if (ulds[type].add) { +		ret = -EBUSY; +		goto out; +	} +	ulds[type] = *p; +	list_for_each_entry(adap, &adapter_list, list_node) +		uld_attach(adap, type); +out:	mutex_unlock(&uld_mutex); +	return ret; +} +EXPORT_SYMBOL(cxgb4_register_uld); + +/** + *	cxgb4_unregister_uld - unregister an upper-layer driver + *	@type: the ULD type + * + *	Unregisters an existing upper-layer driver. + */ +int cxgb4_unregister_uld(enum cxgb4_uld type) +{ +	struct adapter *adap; + +	if (type >= CXGB4_ULD_MAX) +		return -EINVAL; +	mutex_lock(&uld_mutex); +	list_for_each_entry(adap, &adapter_list, list_node) +		adap->uld_handle[type] = NULL; +	ulds[type].add = NULL; +	mutex_unlock(&uld_mutex); +	return 0; +} +EXPORT_SYMBOL(cxgb4_unregister_uld); + +/** + *	cxgb_up - enable the adapter + *	@adap: adapter being enabled + * + *	Called when the first port is enabled, this function performs the + *	actions necessary to make an adapter operational, such as completing + *	the initialization of HW modules, and enabling interrupts. + * + *	Must be called with the rtnl lock held. + */ +static int cxgb_up(struct adapter *adap) +{ +	int err = 0; + +	if (!(adap->flags & FULL_INIT_DONE)) { +		err = setup_sge_queues(adap); +		if (err) +			goto out; +		err = setup_rss(adap); +		if (err) { +			t4_free_sge_resources(adap); +			goto out; +		} +		if (adap->flags & USING_MSIX) +			name_msix_vecs(adap); +		adap->flags |= FULL_INIT_DONE; +	} + +	if (adap->flags & USING_MSIX) { +		err = request_irq(adap->msix_info[0].vec, t4_nondata_intr, 0, +				  adap->msix_info[0].desc, adap); +		if (err) +			goto irq_err; + +		err = request_msix_queue_irqs(adap); +		if (err) { +			free_irq(adap->msix_info[0].vec, adap); +			goto irq_err; +		} +	} else { +		err = request_irq(adap->pdev->irq, t4_intr_handler(adap), +				  (adap->flags & USING_MSI) ? 0 : IRQF_SHARED, +				  adap->name, adap); +		if (err) +			goto irq_err; +	} +	enable_rx(adap); +	t4_sge_start(adap); +	t4_intr_enable(adap); +	notify_ulds(adap, CXGB4_STATE_UP); + out: +	return err; + irq_err: +	dev_err(adap->pdev_dev, "request_irq failed, err %d\n", err); +	goto out; +} + +static void cxgb_down(struct adapter *adapter) +{ +	t4_intr_disable(adapter); +	cancel_work_sync(&adapter->tid_release_task); +	adapter->tid_release_task_busy = false; + +	if (adapter->flags & USING_MSIX) { +		free_msix_queue_irqs(adapter); +		free_irq(adapter->msix_info[0].vec, adapter); +	} else +		free_irq(adapter->pdev->irq, adapter); +	quiesce_rx(adapter); +} + +/* + * net_device operations + */ +static int cxgb_open(struct net_device *dev) +{ +	int err; +	struct port_info *pi = netdev_priv(dev); +	struct adapter *adapter = pi->adapter; + +	if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) +		return err; + +	dev->real_num_tx_queues = pi->nqsets; +	set_bit(pi->tx_chan, &adapter->open_device_map); +	link_start(dev); +	netif_tx_start_all_queues(dev); +	return 0; +} + +static int cxgb_close(struct net_device *dev) +{ +	int ret; +	struct port_info *pi = netdev_priv(dev); +	struct adapter *adapter = pi->adapter; + +	netif_tx_stop_all_queues(dev); +	netif_carrier_off(dev); +	ret = t4_enable_vi(adapter, 0, pi->viid, false, false); + +	clear_bit(pi->tx_chan, &adapter->open_device_map); + +	if (!adapter->open_device_map) +		cxgb_down(adapter); +	return 0; +} + +static struct net_device_stats *cxgb_get_stats(struct net_device *dev) +{ +	struct port_stats stats; +	struct port_info *p = netdev_priv(dev); +	struct adapter *adapter = p->adapter; +	struct net_device_stats *ns = &dev->stats; + +	spin_lock(&adapter->stats_lock); +	t4_get_port_stats(adapter, p->tx_chan, &stats); +	spin_unlock(&adapter->stats_lock); + +	ns->tx_bytes   = stats.tx_octets; +	ns->tx_packets = stats.tx_frames; +	ns->rx_bytes   = stats.rx_octets; +	ns->rx_packets = stats.rx_frames; +	ns->multicast  = stats.rx_mcast_frames; + +	/* detailed rx_errors */ +	ns->rx_length_errors = stats.rx_jabber + stats.rx_too_long + +			       stats.rx_runt; +	ns->rx_over_errors   = 0; +	ns->rx_crc_errors    = stats.rx_fcs_err; +	ns->rx_frame_errors  = stats.rx_symbol_err; +	ns->rx_fifo_errors   = stats.rx_ovflow0 + stats.rx_ovflow1 + +			       stats.rx_ovflow2 + stats.rx_ovflow3 + +			       stats.rx_trunc0 + stats.rx_trunc1 + +			       stats.rx_trunc2 + stats.rx_trunc3; +	ns->rx_missed_errors = 0; + +	/* detailed tx_errors */ +	ns->tx_aborted_errors   = 0; +	ns->tx_carrier_errors   = 0; +	ns->tx_fifo_errors      = 0; +	ns->tx_heartbeat_errors = 0; +	ns->tx_window_errors    = 0; + +	ns->tx_errors = stats.tx_error_frames; +	ns->rx_errors = stats.rx_symbol_err + stats.rx_fcs_err + +		ns->rx_length_errors + stats.rx_len_err + ns->rx_fifo_errors; +	return ns; +} + +static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd) +{ +	int ret = 0, prtad, devad; +	struct port_info *pi = netdev_priv(dev); +	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&req->ifr_data; + +	switch (cmd) { +	case SIOCGMIIPHY: +		if (pi->mdio_addr < 0) +			return -EOPNOTSUPP; +		data->phy_id = pi->mdio_addr; +		break; +	case SIOCGMIIREG: +	case SIOCSMIIREG: +		if (mdio_phy_id_is_c45(data->phy_id)) { +			prtad = mdio_phy_id_prtad(data->phy_id); +			devad = mdio_phy_id_devad(data->phy_id); +		} else if (data->phy_id < 32) { +			prtad = data->phy_id; +			devad = 0; +			data->reg_num &= 0x1f; +		} else +			return -EINVAL; + +		if (cmd == SIOCGMIIREG) +			ret = t4_mdio_rd(pi->adapter, 0, prtad, devad, +					 data->reg_num, &data->val_out); +		else +			ret = t4_mdio_wr(pi->adapter, 0, prtad, devad, +					 data->reg_num, data->val_in); +		break; +	default: +		return -EOPNOTSUPP; +	} +	return ret; +} + +static void cxgb_set_rxmode(struct net_device *dev) +{ +	/* unfortunately we can't return errors to the stack */ +	set_rxmode(dev, -1, false); +} + +static int cxgb_change_mtu(struct net_device *dev, int new_mtu) +{ +	int ret; +	struct port_info *pi = netdev_priv(dev); + +	if (new_mtu < 81 || new_mtu > MAX_MTU)         /* accommodate SACK */ +		return -EINVAL; +	ret = t4_set_rxmode(pi->adapter, 0, pi->viid, new_mtu, -1, -1, -1, +			    true); +	if (!ret) +		dev->mtu = new_mtu; +	return ret; +} + +static int cxgb_set_mac_addr(struct net_device *dev, void *p) +{ +	int ret; +	struct sockaddr *addr = p; +	struct port_info *pi = netdev_priv(dev); + +	if (!is_valid_ether_addr(addr->sa_data)) +		return -EINVAL; + +	ret = t4_change_mac(pi->adapter, 0, pi->viid, pi->xact_addr_filt, +			    addr->sa_data, true, true); +	if (ret < 0) +		return ret; + +	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); +	pi->xact_addr_filt = ret; +	return 0; +} + +static void vlan_rx_register(struct net_device *dev, struct vlan_group *grp) +{ +	struct port_info *pi = netdev_priv(dev); + +	pi->vlan_grp = grp; +	t4_set_vlan_accel(pi->adapter, 1 << pi->tx_chan, grp != NULL); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void cxgb_netpoll(struct net_device *dev) +{ +	struct port_info *pi = netdev_priv(dev); +	struct adapter *adap = pi->adapter; + +	if (adap->flags & USING_MSIX) { +		int i; +		struct sge_eth_rxq *rx = &adap->sge.ethrxq[pi->first_qset]; + +		for (i = pi->nqsets; i; i--, rx++) +			t4_sge_intr_msix(0, &rx->rspq); +	} else +		t4_intr_handler(adap)(0, adap); +} +#endif + +static const struct net_device_ops cxgb4_netdev_ops = { +	.ndo_open             = cxgb_open, +	.ndo_stop             = cxgb_close, +	.ndo_start_xmit       = t4_eth_xmit, +	.ndo_get_stats        = cxgb_get_stats, +	.ndo_set_rx_mode      = cxgb_set_rxmode, +	.ndo_set_mac_address  = cxgb_set_mac_addr, +	.ndo_validate_addr    = eth_validate_addr, +	.ndo_do_ioctl         = cxgb_ioctl, +	.ndo_change_mtu       = cxgb_change_mtu, +	.ndo_vlan_rx_register = vlan_rx_register, +#ifdef CONFIG_NET_POLL_CONTROLLER +	.ndo_poll_controller  = cxgb_netpoll, +#endif +}; + +void t4_fatal_err(struct adapter *adap) +{ +	t4_set_reg_field(adap, SGE_CONTROL, GLOBALENABLE, 0); +	t4_intr_disable(adap); +	dev_alert(adap->pdev_dev, "encountered fatal error, adapter stopped\n"); +} + +static void setup_memwin(struct adapter *adap) +{ +	u32 bar0; + +	bar0 = pci_resource_start(adap->pdev, 0);  /* truncation intentional */ +	t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 0), +		     (bar0 + MEMWIN0_BASE) | BIR(0) | +		     WINDOW(ilog2(MEMWIN0_APERTURE) - 10)); +	t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 1), +		     (bar0 + MEMWIN1_BASE) | BIR(0) | +		     WINDOW(ilog2(MEMWIN1_APERTURE) - 10)); +	t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2), +		     (bar0 + MEMWIN2_BASE) | BIR(0) | +		     WINDOW(ilog2(MEMWIN2_APERTURE) - 10)); +} + +/* + * Max # of ATIDs.  The absolute HW max is 16K but we keep it lower. + */ +#define MAX_ATIDS 8192U + +/* + * Phase 0 of initialization: contact FW, obtain config, perform basic init. + */ +static int adap_init0(struct adapter *adap) +{ +	int ret; +	u32 v, port_vec; +	enum dev_state state; +	u32 params[7], val[7]; +	struct fw_caps_config_cmd c; + +	ret = t4_check_fw_version(adap); +	if (ret == -EINVAL || ret > 0) { +		if (upgrade_fw(adap) >= 0)             /* recache FW version */ +			ret = t4_check_fw_version(adap); +	} +	if (ret < 0) +		return ret; + +	/* contact FW, request master */ +	ret = t4_fw_hello(adap, 0, 0, MASTER_MUST, &state); +	if (ret < 0) { +		dev_err(adap->pdev_dev, "could not connect to FW, error %d\n", +			ret); +		return ret; +	} + +	/* reset device */ +	ret = t4_fw_reset(adap, 0, PIORSTMODE | PIORST); +	if (ret < 0) +		goto bye; + +	/* get device capabilities */ +	memset(&c, 0, sizeof(c)); +	c.op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) | +			      FW_CMD_REQUEST | FW_CMD_READ); +	c.retval_len16 = htonl(FW_LEN16(c)); +	ret = t4_wr_mbox(adap, 0, &c, sizeof(c), &c); +	if (ret < 0) +		goto bye; + +	/* select capabilities we'll be using */ +	if (c.niccaps & htons(FW_CAPS_CONFIG_NIC_VM)) { +		if (!vf_acls) +			c.niccaps ^= htons(FW_CAPS_CONFIG_NIC_VM); +		else +			c.niccaps = htons(FW_CAPS_CONFIG_NIC_VM); +	} else if (vf_acls) { +		dev_err(adap->pdev_dev, "virtualization ACLs not supported"); +		goto bye; +	} +	c.op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) | +			      FW_CMD_REQUEST | FW_CMD_WRITE); +	ret = t4_wr_mbox(adap, 0, &c, sizeof(c), NULL); +	if (ret < 0) +		goto bye; + +	ret = t4_config_glbl_rss(adap, 0, +				 FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL, +				 FW_RSS_GLB_CONFIG_CMD_TNLMAPEN | +				 FW_RSS_GLB_CONFIG_CMD_TNLALLLKP); +	if (ret < 0) +		goto bye; + +	ret = t4_cfg_pfvf(adap, 0, 0, 0, 64, 64, 64, 0, 0, 4, 0xf, 0xf, 16, +			  FW_CMD_CAP_PF, FW_CMD_CAP_PF); +	if (ret < 0) +		goto bye; + +	for (v = 0; v < SGE_NTIMERS - 1; v++) +		adap->sge.timer_val[v] = min(intr_holdoff[v], MAX_SGE_TIMERVAL); +	adap->sge.timer_val[SGE_NTIMERS - 1] = MAX_SGE_TIMERVAL; +	adap->sge.counter_val[0] = 1; +	for (v = 1; v < SGE_NCOUNTERS; v++) +		adap->sge.counter_val[v] = min(intr_cnt[v - 1], +					       THRESHOLD_3_MASK); +	t4_sge_init(adap); + +	/* get basic stuff going */ +	ret = t4_early_init(adap, 0); +	if (ret < 0) +		goto bye; + +#define FW_PARAM_DEV(param) \ +	(FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \ +	 FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param)) + +#define FW_PARAM_PFVF(param) \ +	(FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \ +	 FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param)) + +	params[0] = FW_PARAM_DEV(PORTVEC); +	params[1] = FW_PARAM_PFVF(L2T_START); +	params[2] = FW_PARAM_PFVF(L2T_END); +	params[3] = FW_PARAM_PFVF(FILTER_START); +	params[4] = FW_PARAM_PFVF(FILTER_END); +	ret = t4_query_params(adap, 0, 0, 0, 5, params, val); +	if (ret < 0) +		goto bye; +	port_vec = val[0]; +	adap->tids.ftid_base = val[3]; +	adap->tids.nftids = val[4] - val[3] + 1; + +	if (c.ofldcaps) { +		/* query offload-related parameters */ +		params[0] = FW_PARAM_DEV(NTID); +		params[1] = FW_PARAM_PFVF(SERVER_START); +		params[2] = FW_PARAM_PFVF(SERVER_END); +		params[3] = FW_PARAM_PFVF(TDDP_START); +		params[4] = FW_PARAM_PFVF(TDDP_END); +		params[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); +		ret = t4_query_params(adap, 0, 0, 0, 6, params, val); +		if (ret < 0) +			goto bye; +		adap->tids.ntids = val[0]; +		adap->tids.natids = min(adap->tids.ntids / 2, MAX_ATIDS); +		adap->tids.stid_base = val[1]; +		adap->tids.nstids = val[2] - val[1] + 1; +		adap->vres.ddp.start = val[3]; +		adap->vres.ddp.size = val[4] - val[3] + 1; +		adap->params.ofldq_wr_cred = val[5]; +		adap->params.offload = 1; +	} +	if (c.rdmacaps) { +		params[0] = FW_PARAM_PFVF(STAG_START); +		params[1] = FW_PARAM_PFVF(STAG_END); +		params[2] = FW_PARAM_PFVF(RQ_START); +		params[3] = FW_PARAM_PFVF(RQ_END); +		params[4] = FW_PARAM_PFVF(PBL_START); +		params[5] = FW_PARAM_PFVF(PBL_END); +		ret = t4_query_params(adap, 0, 0, 0, 6, params, val); +		if (ret < 0) +			goto bye; +		adap->vres.stag.start = val[0]; +		adap->vres.stag.size = val[1] - val[0] + 1; +		adap->vres.rq.start = val[2]; +		adap->vres.rq.size = val[3] - val[2] + 1; +		adap->vres.pbl.start = val[4]; +		adap->vres.pbl.size = val[5] - val[4] + 1; +	} +	if (c.iscsicaps) { +		params[0] = FW_PARAM_PFVF(ISCSI_START); +		params[1] = FW_PARAM_PFVF(ISCSI_END); +		ret = t4_query_params(adap, 0, 0, 0, 2, params, val); +		if (ret < 0) +			goto bye; +		adap->vres.iscsi.start = val[0]; +		adap->vres.iscsi.size = val[1] - val[0] + 1; +	} +#undef FW_PARAM_PFVF +#undef FW_PARAM_DEV + +	adap->params.nports = hweight32(port_vec); +	adap->params.portvec = port_vec; +	adap->flags |= FW_OK; + +	/* These are finalized by FW initialization, load their values now */ +	v = t4_read_reg(adap, TP_TIMER_RESOLUTION); +	adap->params.tp.tre = TIMERRESOLUTION_GET(v); +	t4_read_mtu_tbl(adap, adap->params.mtus, NULL); +	t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd, +		     adap->params.b_wnd); + +	/* tweak some settings */ +	t4_write_reg(adap, TP_SHIFT_CNT, 0x64f8849); +	t4_write_reg(adap, ULP_RX_TDDP_PSZ, HPZ0(PAGE_SHIFT - 12)); +	t4_write_reg(adap, TP_PIO_ADDR, TP_INGRESS_CONFIG); +	v = t4_read_reg(adap, TP_PIO_DATA); +	t4_write_reg(adap, TP_PIO_DATA, v & ~CSUM_HAS_PSEUDO_HDR); +	setup_memwin(adap); +	return 0; + +	/* +	 * If a command timed out or failed with EIO FW does not operate within +	 * its spec or something catastrophic happened to HW/FW, stop issuing +	 * commands. +	 */ +bye:	if (ret != -ETIMEDOUT && ret != -EIO) +		t4_fw_bye(adap, 0); +	return ret; +} + +static inline bool is_10g_port(const struct link_config *lc) +{ +	return (lc->supported & FW_PORT_CAP_SPEED_10G) != 0; +} + +static inline void init_rspq(struct sge_rspq *q, u8 timer_idx, u8 pkt_cnt_idx, +			     unsigned int size, unsigned int iqe_size) +{ +	q->intr_params = QINTR_TIMER_IDX(timer_idx) | +			 (pkt_cnt_idx < SGE_NCOUNTERS ? QINTR_CNT_EN : 0); +	q->pktcnt_idx = pkt_cnt_idx < SGE_NCOUNTERS ? pkt_cnt_idx : 0; +	q->iqe_len = iqe_size; +	q->size = size; +} + +/* + * Perform default configuration of DMA queues depending on the number and type + * of ports we found and the number of available CPUs.  Most settings can be + * modified by the admin prior to actual use. + */ +static void __devinit cfg_queues(struct adapter *adap) +{ +	struct sge *s = &adap->sge; +	int i, q10g = 0, n10g = 0, qidx = 0; + +	for_each_port(adap, i) +		n10g += is_10g_port(&adap2pinfo(adap, i)->link_cfg); + +	/* +	 * We default to 1 queue per non-10G port and up to # of cores queues +	 * per 10G port. +	 */ +	if (n10g) +		q10g = (MAX_ETH_QSETS - (adap->params.nports - n10g)) / n10g; +	if (q10g > num_online_cpus()) +		q10g = num_online_cpus(); + +	for_each_port(adap, i) { +		struct port_info *pi = adap2pinfo(adap, i); + +		pi->first_qset = qidx; +		pi->nqsets = is_10g_port(&pi->link_cfg) ? q10g : 1; +		qidx += pi->nqsets; +	} + +	s->ethqsets = qidx; +	s->max_ethqsets = qidx;   /* MSI-X may lower it later */ + +	if (is_offload(adap)) { +		/* +		 * For offload we use 1 queue/channel if all ports are up to 1G, +		 * otherwise we divide all available queues amongst the channels +		 * capped by the number of available cores. +		 */ +		if (n10g) { +			i = min_t(int, ARRAY_SIZE(s->ofldrxq), +				  num_online_cpus()); +			s->ofldqsets = roundup(i, adap->params.nports); +		} else +			s->ofldqsets = adap->params.nports; +		/* For RDMA one Rx queue per channel suffices */ +		s->rdmaqs = adap->params.nports; +	} + +	for (i = 0; i < ARRAY_SIZE(s->ethrxq); i++) { +		struct sge_eth_rxq *r = &s->ethrxq[i]; + +		init_rspq(&r->rspq, 0, 0, 1024, 64); +		r->fl.size = 72; +	} + +	for (i = 0; i < ARRAY_SIZE(s->ethtxq); i++) +		s->ethtxq[i].q.size = 1024; + +	for (i = 0; i < ARRAY_SIZE(s->ctrlq); i++) +		s->ctrlq[i].q.size = 512; + +	for (i = 0; i < ARRAY_SIZE(s->ofldtxq); i++) +		s->ofldtxq[i].q.size = 1024; + +	for (i = 0; i < ARRAY_SIZE(s->ofldrxq); i++) { +		struct sge_ofld_rxq *r = &s->ofldrxq[i]; + +		init_rspq(&r->rspq, 0, 0, 1024, 64); +		r->rspq.uld = CXGB4_ULD_ISCSI; +		r->fl.size = 72; +	} + +	for (i = 0; i < ARRAY_SIZE(s->rdmarxq); i++) { +		struct sge_ofld_rxq *r = &s->rdmarxq[i]; + +		init_rspq(&r->rspq, 0, 0, 511, 64); +		r->rspq.uld = CXGB4_ULD_RDMA; +		r->fl.size = 72; +	} + +	init_rspq(&s->fw_evtq, 6, 0, 512, 64); +	init_rspq(&s->intrq, 6, 0, 2 * MAX_INGQ, 64); +} + +/* + * Reduce the number of Ethernet queues across all ports to at most n. + * n provides at least one queue per port. + */ +static void __devinit reduce_ethqs(struct adapter *adap, int n) +{ +	int i; +	struct port_info *pi; + +	while (n < adap->sge.ethqsets) +		for_each_port(adap, i) { +			pi = adap2pinfo(adap, i); +			if (pi->nqsets > 1) { +				pi->nqsets--; +				adap->sge.ethqsets--; +				if (adap->sge.ethqsets <= n) +					break; +			} +		} + +	n = 0; +	for_each_port(adap, i) { +		pi = adap2pinfo(adap, i); +		pi->first_qset = n; +		n += pi->nqsets; +	} +} + +/* 2 MSI-X vectors needed for the FW queue and non-data interrupts */ +#define EXTRA_VECS 2 + +static int __devinit enable_msix(struct adapter *adap) +{ +	int ofld_need = 0; +	int i, err, want, need; +	struct sge *s = &adap->sge; +	unsigned int nchan = adap->params.nports; +	struct msix_entry entries[MAX_INGQ + 1]; + +	for (i = 0; i < ARRAY_SIZE(entries); ++i) +		entries[i].entry = i; + +	want = s->max_ethqsets + EXTRA_VECS; +	if (is_offload(adap)) { +		want += s->rdmaqs + s->ofldqsets; +		/* need nchan for each possible ULD */ +		ofld_need = 2 * nchan; +	} +	need = adap->params.nports + EXTRA_VECS + ofld_need; + +	while ((err = pci_enable_msix(adap->pdev, entries, want)) >= need) +		want = err; + +	if (!err) { +		/* +		 * Distribute available vectors to the various queue groups. +		 * Every group gets its minimum requirement and NIC gets top +		 * priority for leftovers. +		 */ +		i = want - EXTRA_VECS - ofld_need; +		if (i < s->max_ethqsets) { +			s->max_ethqsets = i; +			if (i < s->ethqsets) +				reduce_ethqs(adap, i); +		} +		if (is_offload(adap)) { +			i = want - EXTRA_VECS - s->max_ethqsets; +			i -= ofld_need - nchan; +			s->ofldqsets = (i / nchan) * nchan;  /* round down */ +		} +		for (i = 0; i < want; ++i) +			adap->msix_info[i].vec = entries[i].vector; +	} else if (err > 0) +		dev_info(adap->pdev_dev, +			 "only %d MSI-X vectors left, not using MSI-X\n", err); +	return err; +} + +#undef EXTRA_VECS + +static void __devinit print_port_info(struct adapter *adap) +{ +	static const char *base[] = { +		"R", "KX4", "T", "KX", "T", "KR", "CX4" +	}; + +	int i; +	char buf[80]; + +	for_each_port(adap, i) { +		struct net_device *dev = adap->port[i]; +		const struct port_info *pi = netdev_priv(dev); +		char *bufp = buf; + +		if (!test_bit(i, &adap->registered_device_map)) +			continue; + +		if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_100M) +			bufp += sprintf(bufp, "100/"); +		if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_1G) +			bufp += sprintf(bufp, "1000/"); +		if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_10G) +			bufp += sprintf(bufp, "10G/"); +		if (bufp != buf) +			--bufp; +		sprintf(bufp, "BASE-%s", base[pi->port_type]); + +		netdev_info(dev, "Chelsio %s rev %d %s %sNIC PCIe x%d%s\n", +			    adap->params.vpd.id, adap->params.rev, +			    buf, is_offload(adap) ? "R" : "", +			    adap->params.pci.width, +			    (adap->flags & USING_MSIX) ? " MSI-X" : +			    (adap->flags & USING_MSI) ? " MSI" : ""); +		if (adap->name == dev->name) +			netdev_info(dev, "S/N: %s, E/C: %s\n", +				    adap->params.vpd.sn, adap->params.vpd.ec); +	} +} + +#define VLAN_FEAT (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | NETIF_F_TSO6 |\ +		   NETIF_F_IPV6_CSUM | NETIF_F_HIGHDMA) + +static int __devinit init_one(struct pci_dev *pdev, +			      const struct pci_device_id *ent) +{ +	int func, i, err; +	struct port_info *pi; +	unsigned int highdma = 0; +	struct adapter *adapter = NULL; + +	printk_once(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION); + +	err = pci_request_regions(pdev, KBUILD_MODNAME); +	if (err) { +		/* Just info, some other driver may have claimed the device. */ +		dev_info(&pdev->dev, "cannot obtain PCI resources\n"); +		return err; +	} + +	/* We control everything through PF 0 */ +	func = PCI_FUNC(pdev->devfn); +	if (func > 0) +		goto sriov; + +	err = pci_enable_device(pdev); +	if (err) { +		dev_err(&pdev->dev, "cannot enable PCI device\n"); +		goto out_release_regions; +	} + +	if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { +		highdma = NETIF_F_HIGHDMA; +		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); +		if (err) { +			dev_err(&pdev->dev, "unable to obtain 64-bit DMA for " +				"coherent allocations\n"); +			goto out_disable_device; +		} +	} else { +		err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); +		if (err) { +			dev_err(&pdev->dev, "no usable DMA configuration\n"); +			goto out_disable_device; +		} +	} + +	pci_enable_pcie_error_reporting(pdev); +	pci_set_master(pdev); +	pci_save_state(pdev); + +	adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); +	if (!adapter) { +		err = -ENOMEM; +		goto out_disable_device; +	} + +	adapter->regs = pci_ioremap_bar(pdev, 0); +	if (!adapter->regs) { +		dev_err(&pdev->dev, "cannot map device registers\n"); +		err = -ENOMEM; +		goto out_free_adapter; +	} + +	adapter->pdev = pdev; +	adapter->pdev_dev = &pdev->dev; +	adapter->name = pci_name(pdev); +	adapter->msg_enable = dflt_msg_enable; +	memset(adapter->chan_map, 0xff, sizeof(adapter->chan_map)); + +	spin_lock_init(&adapter->stats_lock); +	spin_lock_init(&adapter->tid_release_lock); + +	INIT_WORK(&adapter->tid_release_task, process_tid_release_list); + +	err = t4_prep_adapter(adapter); +	if (err) +		goto out_unmap_bar; +	err = adap_init0(adapter); +	if (err) +		goto out_unmap_bar; + +	for_each_port(adapter, i) { +		struct net_device *netdev; + +		netdev = alloc_etherdev_mq(sizeof(struct port_info), +					   MAX_ETH_QSETS); +		if (!netdev) { +			err = -ENOMEM; +			goto out_free_dev; +		} + +		SET_NETDEV_DEV(netdev, &pdev->dev); + +		adapter->port[i] = netdev; +		pi = netdev_priv(netdev); +		pi->adapter = adapter; +		pi->xact_addr_filt = -1; +		pi->rx_offload = RX_CSO; +		pi->port_id = i; +		netif_carrier_off(netdev); +		netif_tx_stop_all_queues(netdev); +		netdev->irq = pdev->irq; + +		netdev->features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6; +		netdev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; +		netdev->features |= NETIF_F_GRO | highdma; +		netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; +		netdev->vlan_features = netdev->features & VLAN_FEAT; + +		netdev->netdev_ops = &cxgb4_netdev_ops; +		SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops); +	} + +	pci_set_drvdata(pdev, adapter); + +	if (adapter->flags & FW_OK) { +		err = t4_port_init(adapter, 0, 0, 0); +		if (err) +			goto out_free_dev; +	} + +	/* +	 * Configure queues and allocate tables now, they can be needed as +	 * soon as the first register_netdev completes. +	 */ +	cfg_queues(adapter); + +	adapter->l2t = t4_init_l2t(); +	if (!adapter->l2t) { +		/* We tolerate a lack of L2T, giving up some functionality */ +		dev_warn(&pdev->dev, "could not allocate L2T, continuing\n"); +		adapter->params.offload = 0; +	} + +	if (is_offload(adapter) && tid_init(&adapter->tids) < 0) { +		dev_warn(&pdev->dev, "could not allocate TID table, " +			 "continuing\n"); +		adapter->params.offload = 0; +	} + +	/* +	 * The card is now ready to go.  If any errors occur during device +	 * registration we do not fail the whole card but rather proceed only +	 * with the ports we manage to register successfully.  However we must +	 * register at least one net device. +	 */ +	for_each_port(adapter, i) { +		err = register_netdev(adapter->port[i]); +		if (err) +			dev_warn(&pdev->dev, +				 "cannot register net device %s, skipping\n", +				 adapter->port[i]->name); +		else { +			/* +			 * Change the name we use for messages to the name of +			 * the first successfully registered interface. +			 */ +			if (!adapter->registered_device_map) +				adapter->name = adapter->port[i]->name; + +			__set_bit(i, &adapter->registered_device_map); +			adapter->chan_map[adap2pinfo(adapter, i)->tx_chan] = i; +		} +	} +	if (!adapter->registered_device_map) { +		dev_err(&pdev->dev, "could not register any net devices\n"); +		goto out_free_dev; +	} + +	if (cxgb4_debugfs_root) { +		adapter->debugfs_root = debugfs_create_dir(pci_name(pdev), +							   cxgb4_debugfs_root); +		setup_debugfs(adapter); +	} + +	/* See what interrupts we'll be using */ +	if (msi > 1 && enable_msix(adapter) == 0) +		adapter->flags |= USING_MSIX; +	else if (msi > 0 && pci_enable_msi(pdev) == 0) +		adapter->flags |= USING_MSI; + +	if (is_offload(adapter)) +		attach_ulds(adapter); + +	print_port_info(adapter); + +sriov: +#ifdef CONFIG_PCI_IOV +	if (func < ARRAY_SIZE(num_vf) && num_vf[func] > 0) +		if (pci_enable_sriov(pdev, num_vf[func]) == 0) +			dev_info(&pdev->dev, +				 "instantiated %u virtual functions\n", +				 num_vf[func]); +#endif +	return 0; + + out_free_dev: +	t4_free_mem(adapter->tids.tid_tab); +	t4_free_mem(adapter->l2t); +	for_each_port(adapter, i) +		if (adapter->port[i]) +			free_netdev(adapter->port[i]); +	if (adapter->flags & FW_OK) +		t4_fw_bye(adapter, 0); + out_unmap_bar: +	iounmap(adapter->regs); + out_free_adapter: +	kfree(adapter); + out_disable_device: +	pci_disable_pcie_error_reporting(pdev); +	pci_disable_device(pdev); + out_release_regions: +	pci_release_regions(pdev); +	pci_set_drvdata(pdev, NULL); +	return err; +} + +static void __devexit remove_one(struct pci_dev *pdev) +{ +	struct adapter *adapter = pci_get_drvdata(pdev); + +	pci_disable_sriov(pdev); + +	if (adapter) { +		int i; + +		if (is_offload(adapter)) +			detach_ulds(adapter); + +		for_each_port(adapter, i) +			if (test_bit(i, &adapter->registered_device_map)) +				unregister_netdev(adapter->port[i]); + +		if (adapter->debugfs_root) +			debugfs_remove_recursive(adapter->debugfs_root); + +		t4_sge_stop(adapter); +		t4_free_sge_resources(adapter); +		t4_free_mem(adapter->l2t); +		t4_free_mem(adapter->tids.tid_tab); +		disable_msi(adapter); + +		for_each_port(adapter, i) +			if (adapter->port[i]) +				free_netdev(adapter->port[i]); + +		if (adapter->flags & FW_OK) +			t4_fw_bye(adapter, 0); +		iounmap(adapter->regs); +		kfree(adapter); +		pci_disable_pcie_error_reporting(pdev); +		pci_disable_device(pdev); +		pci_release_regions(pdev); +		pci_set_drvdata(pdev, NULL); +	} else if (PCI_FUNC(pdev->devfn) > 0) +		pci_release_regions(pdev); +} + +static struct pci_driver cxgb4_driver = { +	.name     = KBUILD_MODNAME, +	.id_table = cxgb4_pci_tbl, +	.probe    = init_one, +	.remove   = __devexit_p(remove_one), +}; + +static int __init cxgb4_init_module(void) +{ +	int ret; + +	/* Debugfs support is optional, just warn if this fails */ +	cxgb4_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); +	if (!cxgb4_debugfs_root) +		pr_warning("could not create debugfs entry, continuing\n"); + +	ret = pci_register_driver(&cxgb4_driver); +	if (ret < 0) +		debugfs_remove(cxgb4_debugfs_root); +	return ret; +} + +static void __exit cxgb4_cleanup_module(void) +{ +	pci_unregister_driver(&cxgb4_driver); +	debugfs_remove(cxgb4_debugfs_root);  /* NULL ok */ +} + +module_init(cxgb4_init_module); +module_exit(cxgb4_cleanup_module); diff --git a/drivers/net/cxgb4/cxgb4_uld.h b/drivers/net/cxgb4/cxgb4_uld.h new file mode 100644 index 00000000000..5b98546ac92 --- /dev/null +++ b/drivers/net/cxgb4/cxgb4_uld.h @@ -0,0 +1,239 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses.  You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + *     Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *      - Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + * + *      - Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __CXGB4_OFLD_H +#define __CXGB4_OFLD_H + +#include <linux/cache.h> +#include <linux/spinlock.h> +#include <linux/skbuff.h> +#include <asm/atomic.h> + +/* CPL message priority levels */ +enum { +	CPL_PRIORITY_DATA     = 0,  /* data messages */ +	CPL_PRIORITY_SETUP    = 1,  /* connection setup messages */ +	CPL_PRIORITY_TEARDOWN = 0,  /* connection teardown messages */ +	CPL_PRIORITY_LISTEN   = 1,  /* listen start/stop messages */ +	CPL_PRIORITY_ACK      = 1,  /* RX ACK messages */ +	CPL_PRIORITY_CONTROL  = 1   /* control messages */ +}; + +#define INIT_TP_WR(w, tid) do { \ +	(w)->wr.wr_hi = htonl(FW_WR_OP(FW_TP_WR) | \ +			      FW_WR_IMMDLEN(sizeof(*w) - sizeof(w->wr))); \ +	(w)->wr.wr_mid = htonl(FW_WR_LEN16(DIV_ROUND_UP(sizeof(*w), 16)) | \ +			       FW_WR_FLOWID(tid)); \ +	(w)->wr.wr_lo = cpu_to_be64(0); \ +} while (0) + +#define INIT_TP_WR_CPL(w, cpl, tid) do { \ +	INIT_TP_WR(w, tid); \ +	OPCODE_TID(w) = htonl(MK_OPCODE_TID(cpl, tid)); \ +} while (0) + +#define INIT_ULPTX_WR(w, wrlen, atomic, tid) do { \ +	(w)->wr.wr_hi = htonl(FW_WR_OP(FW_ULPTX_WR) | FW_WR_ATOMIC(atomic)); \ +	(w)->wr.wr_mid = htonl(FW_WR_LEN16(DIV_ROUND_UP(wrlen, 16)) | \ +			       FW_WR_FLOWID(tid)); \ +	(w)->wr.wr_lo = cpu_to_be64(0); \ +} while (0) + +/* Special asynchronous notification message */ +#define CXGB4_MSG_AN ((void *)1) + +struct serv_entry { +	void *data; +}; + +union aopen_entry { +	void *data; +	union aopen_entry *next; +}; + +/* + * Holds the size, base address, free list start, etc of the TID, server TID, + * and active-open TID tables.  The tables themselves are allocated dynamically. + */ +struct tid_info { +	void **tid_tab; +	unsigned int ntids; + +	struct serv_entry *stid_tab; +	unsigned long *stid_bmap; +	unsigned int nstids; +	unsigned int stid_base; + +	union aopen_entry *atid_tab; +	unsigned int natids; + +	unsigned int nftids; +	unsigned int ftid_base; + +	spinlock_t atid_lock ____cacheline_aligned_in_smp; +	union aopen_entry *afree; +	unsigned int atids_in_use; + +	spinlock_t stid_lock; +	unsigned int stids_in_use; + +	atomic_t tids_in_use; +}; + +static inline void *lookup_tid(const struct tid_info *t, unsigned int tid) +{ +	return tid < t->ntids ? t->tid_tab[tid] : NULL; +} + +static inline void *lookup_atid(const struct tid_info *t, unsigned int atid) +{ +	return atid < t->natids ? t->atid_tab[atid].data : NULL; +} + +static inline void *lookup_stid(const struct tid_info *t, unsigned int stid) +{ +	stid -= t->stid_base; +	return stid < t->nstids ? t->stid_tab[stid].data : NULL; +} + +static inline void cxgb4_insert_tid(struct tid_info *t, void *data, +				    unsigned int tid) +{ +	t->tid_tab[tid] = data; +	atomic_inc(&t->tids_in_use); +} + +int cxgb4_alloc_atid(struct tid_info *t, void *data); +int cxgb4_alloc_stid(struct tid_info *t, int family, void *data); +void cxgb4_free_atid(struct tid_info *t, unsigned int atid); +void cxgb4_free_stid(struct tid_info *t, unsigned int stid, int family); +void cxgb4_remove_tid(struct tid_info *t, unsigned int qid, unsigned int tid); +void cxgb4_queue_tid_release(struct tid_info *t, unsigned int chan, +			     unsigned int tid); + +struct in6_addr; + +int cxgb4_create_server(const struct net_device *dev, unsigned int stid, +			__be32 sip, __be16 sport, unsigned int queue); +int cxgb4_create_server6(const struct net_device *dev, unsigned int stid, +			 const struct in6_addr *sip, __be16 sport, +			 unsigned int queue); + +static inline void set_wr_txq(struct sk_buff *skb, int prio, int queue) +{ +	skb_set_queue_mapping(skb, (queue << 1) | prio); +} + +enum cxgb4_uld { +	CXGB4_ULD_RDMA, +	CXGB4_ULD_ISCSI, +	CXGB4_ULD_MAX +}; + +enum cxgb4_state { +	CXGB4_STATE_UP, +	CXGB4_STATE_START_RECOVERY, +	CXGB4_STATE_DOWN, +	CXGB4_STATE_DETACH +}; + +struct pci_dev; +struct l2t_data; +struct net_device; +struct pkt_gl; +struct tp_tcp_stats; + +struct cxgb4_range { +	unsigned int start; +	unsigned int size; +}; + +struct cxgb4_virt_res {                      /* virtualized HW resources */ +	struct cxgb4_range ddp; +	struct cxgb4_range iscsi; +	struct cxgb4_range stag; +	struct cxgb4_range rq; +	struct cxgb4_range pbl; +}; + +/* + * Block of information the LLD provides to ULDs attaching to a device. + */ +struct cxgb4_lld_info { +	struct pci_dev *pdev;                /* associated PCI device */ +	struct l2t_data *l2t;                /* L2 table */ +	struct tid_info *tids;               /* TID table */ +	struct net_device **ports;           /* device ports */ +	const struct cxgb4_virt_res *vr;     /* assorted HW resources */ +	const unsigned short *mtus;          /* MTU table */ +	const unsigned short *rxq_ids;       /* the ULD's Rx queue ids */ +	unsigned short nrxq;                 /* # of Rx queues */ +	unsigned short ntxq;                 /* # of Tx queues */ +	unsigned char nchan:4;               /* # of channels */ +	unsigned char nports:4;              /* # of ports */ +	unsigned char wr_cred;               /* WR 16-byte credits */ +	unsigned char adapter_type;          /* type of adapter */ +	unsigned char fw_api_ver;            /* FW API version */ +	unsigned int fw_vers;                /* FW version */ +	unsigned int iscsi_iolen;            /* iSCSI max I/O length */ +	unsigned short udb_density;          /* # of user DB/page */ +	unsigned short ucq_density;          /* # of user CQs/page */ +	void __iomem *gts_reg;               /* address of GTS register */ +	void __iomem *db_reg;                /* address of kernel doorbell */ +}; + +struct cxgb4_uld_info { +	const char *name; +	void *(*add)(const struct cxgb4_lld_info *p); +	int (*rx_handler)(void *handle, const __be64 *rsp, +			  const struct pkt_gl *gl); +	int (*state_change)(void *handle, enum cxgb4_state new_state); +}; + +int cxgb4_register_uld(enum cxgb4_uld type, const struct cxgb4_uld_info *p); +int cxgb4_unregister_uld(enum cxgb4_uld type); +int cxgb4_ofld_send(struct net_device *dev, struct sk_buff *skb); +unsigned int cxgb4_port_chan(const struct net_device *dev); +unsigned int cxgb4_port_viid(const struct net_device *dev); +unsigned int cxgb4_port_idx(const struct net_device *dev); +struct net_device *cxgb4_netdev_by_hwid(struct pci_dev *pdev, unsigned int id); +unsigned int cxgb4_best_mtu(const unsigned short *mtus, unsigned short mtu, +			    unsigned int *idx); +void cxgb4_get_tcp_stats(struct pci_dev *pdev, struct tp_tcp_stats *v4, +			 struct tp_tcp_stats *v6); +void cxgb4_iscsi_init(struct net_device *dev, unsigned int tag_mask, +		      const unsigned int *pgsz_order); +struct sk_buff *cxgb4_pktgl_to_skb(const struct pkt_gl *gl, +				   unsigned int skb_len, unsigned int pull_len); +#endif  /* !__CXGB4_OFLD_H */ diff --git a/drivers/net/cxgb4/l2t.c b/drivers/net/cxgb4/l2t.c new file mode 100644 index 00000000000..9f96724a133 --- /dev/null +++ b/drivers/net/cxgb4/l2t.c @@ -0,0 +1,624 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses.  You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + *     Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *      - Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + * + *      - Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/if.h> +#include <linux/if_vlan.h> +#include <linux/jhash.h> +#include <net/neighbour.h> +#include "cxgb4.h" +#include "l2t.h" +#include "t4_msg.h" +#include "t4fw_api.h" + +#define VLAN_NONE 0xfff + +/* identifies sync vs async L2T_WRITE_REQs */ +#define F_SYNC_WR    (1 << 12) + +enum { +	L2T_STATE_VALID,      /* entry is up to date */ +	L2T_STATE_STALE,      /* entry may be used but needs revalidation */ +	L2T_STATE_RESOLVING,  /* entry needs address resolution */ +	L2T_STATE_SYNC_WRITE, /* synchronous write of entry underway */ + +	/* when state is one of the below the entry is not hashed */ +	L2T_STATE_SWITCHING,  /* entry is being used by a switching filter */ +	L2T_STATE_UNUSED      /* entry not in use */ +}; + +struct l2t_data { +	rwlock_t lock; +	atomic_t nfree;             /* number of free entries */ +	struct l2t_entry *rover;    /* starting point for next allocation */ +	struct l2t_entry l2tab[L2T_SIZE]; +}; + +static inline unsigned int vlan_prio(const struct l2t_entry *e) +{ +	return e->vlan >> 13; +} + +static inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e) +{ +	if (atomic_add_return(1, &e->refcnt) == 1)  /* 0 -> 1 transition */ +		atomic_dec(&d->nfree); +} + +/* + * To avoid having to check address families we do not allow v4 and v6 + * neighbors to be on the same hash chain.  We keep v4 entries in the first + * half of available hash buckets and v6 in the second. + */ +enum { +	L2T_SZ_HALF = L2T_SIZE / 2, +	L2T_HASH_MASK = L2T_SZ_HALF - 1 +}; + +static inline unsigned int arp_hash(const u32 *key, int ifindex) +{ +	return jhash_2words(*key, ifindex, 0) & L2T_HASH_MASK; +} + +static inline unsigned int ipv6_hash(const u32 *key, int ifindex) +{ +	u32 xor = key[0] ^ key[1] ^ key[2] ^ key[3]; + +	return L2T_SZ_HALF + (jhash_2words(xor, ifindex, 0) & L2T_HASH_MASK); +} + +static unsigned int addr_hash(const u32 *addr, int addr_len, int ifindex) +{ +	return addr_len == 4 ? arp_hash(addr, ifindex) : +			       ipv6_hash(addr, ifindex); +} + +/* + * Checks if an L2T entry is for the given IP/IPv6 address.  It does not check + * whether the L2T entry and the address are of the same address family. + * Callers ensure an address is only checked against L2T entries of the same + * family, something made trivial by the separation of IP and IPv6 hash chains + * mentioned above.  Returns 0 if there's a match, + */ +static int addreq(const struct l2t_entry *e, const u32 *addr) +{ +	if (e->v6) +		return (e->addr[0] ^ addr[0]) | (e->addr[1] ^ addr[1]) | +		       (e->addr[2] ^ addr[2]) | (e->addr[3] ^ addr[3]); +	return e->addr[0] ^ addr[0]; +} + +static void neigh_replace(struct l2t_entry *e, struct neighbour *n) +{ +	neigh_hold(n); +	if (e->neigh) +		neigh_release(e->neigh); +	e->neigh = n; +} + +/* + * Write an L2T entry.  Must be called with the entry locked. + * The write may be synchronous or asynchronous. + */ +static int write_l2e(struct adapter *adap, struct l2t_entry *e, int sync) +{ +	struct sk_buff *skb; +	struct cpl_l2t_write_req *req; + +	skb = alloc_skb(sizeof(*req), GFP_ATOMIC); +	if (!skb) +		return -ENOMEM; + +	req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req)); +	INIT_TP_WR(req, 0); + +	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, +					e->idx | (sync ? F_SYNC_WR : 0) | +					TID_QID(adap->sge.fw_evtq.abs_id))); +	req->params = htons(L2T_W_PORT(e->lport) | L2T_W_NOREPLY(!sync)); +	req->l2t_idx = htons(e->idx); +	req->vlan = htons(e->vlan); +	if (e->neigh) +		memcpy(e->dmac, e->neigh->ha, sizeof(e->dmac)); +	memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac)); + +	set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); +	t4_ofld_send(adap, skb); + +	if (sync && e->state != L2T_STATE_SWITCHING) +		e->state = L2T_STATE_SYNC_WRITE; +	return 0; +} + +/* + * Send packets waiting in an L2T entry's ARP queue.  Must be called with the + * entry locked. + */ +static void send_pending(struct adapter *adap, struct l2t_entry *e) +{ +	while (e->arpq_head) { +		struct sk_buff *skb = e->arpq_head; + +		e->arpq_head = skb->next; +		skb->next = NULL; +		t4_ofld_send(adap, skb); +	} +	e->arpq_tail = NULL; +} + +/* + * Process a CPL_L2T_WRITE_RPL.  Wake up the ARP queue if it completes a + * synchronous L2T_WRITE.  Note that the TID in the reply is really the L2T + * index it refers to. + */ +void do_l2t_write_rpl(struct adapter *adap, const struct cpl_l2t_write_rpl *rpl) +{ +	unsigned int tid = GET_TID(rpl); +	unsigned int idx = tid & (L2T_SIZE - 1); + +	if (unlikely(rpl->status != CPL_ERR_NONE)) { +		dev_err(adap->pdev_dev, +			"Unexpected L2T_WRITE_RPL status %u for entry %u\n", +			rpl->status, idx); +		return; +	} + +	if (tid & F_SYNC_WR) { +		struct l2t_entry *e = &adap->l2t->l2tab[idx]; + +		spin_lock(&e->lock); +		if (e->state != L2T_STATE_SWITCHING) { +			send_pending(adap, e); +			e->state = (e->neigh->nud_state & NUD_STALE) ? +					L2T_STATE_STALE : L2T_STATE_VALID; +		} +		spin_unlock(&e->lock); +	} +} + +/* + * Add a packet to an L2T entry's queue of packets awaiting resolution. + * Must be called with the entry's lock held. + */ +static inline void arpq_enqueue(struct l2t_entry *e, struct sk_buff *skb) +{ +	skb->next = NULL; +	if (e->arpq_head) +		e->arpq_tail->next = skb; +	else +		e->arpq_head = skb; +	e->arpq_tail = skb; +} + +int cxgb4_l2t_send(struct net_device *dev, struct sk_buff *skb, +		   struct l2t_entry *e) +{ +	struct adapter *adap = netdev2adap(dev); + +again: +	switch (e->state) { +	case L2T_STATE_STALE:     /* entry is stale, kick off revalidation */ +		neigh_event_send(e->neigh, NULL); +		spin_lock_bh(&e->lock); +		if (e->state == L2T_STATE_STALE) +			e->state = L2T_STATE_VALID; +		spin_unlock_bh(&e->lock); +	case L2T_STATE_VALID:     /* fast-path, send the packet on */ +		return t4_ofld_send(adap, skb); +	case L2T_STATE_RESOLVING: +	case L2T_STATE_SYNC_WRITE: +		spin_lock_bh(&e->lock); +		if (e->state != L2T_STATE_SYNC_WRITE && +		    e->state != L2T_STATE_RESOLVING) { +			spin_unlock_bh(&e->lock); +			goto again; +		} +		arpq_enqueue(e, skb); +		spin_unlock_bh(&e->lock); + +		if (e->state == L2T_STATE_RESOLVING && +		    !neigh_event_send(e->neigh, NULL)) { +			spin_lock_bh(&e->lock); +			if (e->state == L2T_STATE_RESOLVING && e->arpq_head) +				write_l2e(adap, e, 1); +			spin_unlock_bh(&e->lock); +		} +	} +	return 0; +} +EXPORT_SYMBOL(cxgb4_l2t_send); + +/* + * Allocate a free L2T entry.  Must be called with l2t_data.lock held. + */ +static struct l2t_entry *alloc_l2e(struct l2t_data *d) +{ +	struct l2t_entry *end, *e, **p; + +	if (!atomic_read(&d->nfree)) +		return NULL; + +	/* there's definitely a free entry */ +	for (e = d->rover, end = &d->l2tab[L2T_SIZE]; e != end; ++e) +		if (atomic_read(&e->refcnt) == 0) +			goto found; + +	for (e = d->l2tab; atomic_read(&e->refcnt); ++e) +		; +found: +	d->rover = e + 1; +	atomic_dec(&d->nfree); + +	/* +	 * The entry we found may be an inactive entry that is +	 * presently in the hash table.  We need to remove it. +	 */ +	if (e->state < L2T_STATE_SWITCHING) +		for (p = &d->l2tab[e->hash].first; *p; p = &(*p)->next) +			if (*p == e) { +				*p = e->next; +				e->next = NULL; +				break; +			} + +	e->state = L2T_STATE_UNUSED; +	return e; +} + +/* + * Called when an L2T entry has no more users. + */ +static void t4_l2e_free(struct l2t_entry *e) +{ +	struct l2t_data *d; + +	spin_lock_bh(&e->lock); +	if (atomic_read(&e->refcnt) == 0) {  /* hasn't been recycled */ +		if (e->neigh) { +			neigh_release(e->neigh); +			e->neigh = NULL; +		} +	} +	spin_unlock_bh(&e->lock); + +	d = container_of(e, struct l2t_data, l2tab[e->idx]); +	atomic_inc(&d->nfree); +} + +void cxgb4_l2t_release(struct l2t_entry *e) +{ +	if (atomic_dec_and_test(&e->refcnt)) +		t4_l2e_free(e); +} +EXPORT_SYMBOL(cxgb4_l2t_release); + +/* + * Update an L2T entry that was previously used for the same next hop as neigh. + * Must be called with softirqs disabled. + */ +static void reuse_entry(struct l2t_entry *e, struct neighbour *neigh) +{ +	unsigned int nud_state; + +	spin_lock(&e->lock);                /* avoid race with t4_l2t_free */ +	if (neigh != e->neigh) +		neigh_replace(e, neigh); +	nud_state = neigh->nud_state; +	if (memcmp(e->dmac, neigh->ha, sizeof(e->dmac)) || +	    !(nud_state & NUD_VALID)) +		e->state = L2T_STATE_RESOLVING; +	else if (nud_state & NUD_CONNECTED) +		e->state = L2T_STATE_VALID; +	else +		e->state = L2T_STATE_STALE; +	spin_unlock(&e->lock); +} + +struct l2t_entry *cxgb4_l2t_get(struct l2t_data *d, struct neighbour *neigh, +				const struct net_device *physdev, +				unsigned int priority) +{ +	u8 lport; +	u16 vlan; +	struct l2t_entry *e; +	int addr_len = neigh->tbl->key_len; +	u32 *addr = (u32 *)neigh->primary_key; +	int ifidx = neigh->dev->ifindex; +	int hash = addr_hash(addr, addr_len, ifidx); + +	if (neigh->dev->flags & IFF_LOOPBACK) +		lport = netdev2pinfo(physdev)->tx_chan + 4; +	else +		lport = netdev2pinfo(physdev)->lport; + +	if (neigh->dev->priv_flags & IFF_802_1Q_VLAN) +		vlan = vlan_dev_vlan_id(neigh->dev); +	else +		vlan = VLAN_NONE; + +	write_lock_bh(&d->lock); +	for (e = d->l2tab[hash].first; e; e = e->next) +		if (!addreq(e, addr) && e->ifindex == ifidx && +		    e->vlan == vlan && e->lport == lport) { +			l2t_hold(d, e); +			if (atomic_read(&e->refcnt) == 1) +				reuse_entry(e, neigh); +			goto done; +		} + +	/* Need to allocate a new entry */ +	e = alloc_l2e(d); +	if (e) { +		spin_lock(&e->lock);          /* avoid race with t4_l2t_free */ +		e->state = L2T_STATE_RESOLVING; +		memcpy(e->addr, addr, addr_len); +		e->ifindex = ifidx; +		e->hash = hash; +		e->lport = lport; +		e->v6 = addr_len == 16; +		atomic_set(&e->refcnt, 1); +		neigh_replace(e, neigh); +		e->vlan = vlan; +		e->next = d->l2tab[hash].first; +		d->l2tab[hash].first = e; +		spin_unlock(&e->lock); +	} +done: +	write_unlock_bh(&d->lock); +	return e; +} +EXPORT_SYMBOL(cxgb4_l2t_get); + +/* + * Called when address resolution fails for an L2T entry to handle packets + * on the arpq head.  If a packet specifies a failure handler it is invoked, + * otherwise the packet is sent to the device. + */ +static void handle_failed_resolution(struct adapter *adap, struct sk_buff *arpq) +{ +	while (arpq) { +		struct sk_buff *skb = arpq; +		const struct l2t_skb_cb *cb = L2T_SKB_CB(skb); + +		arpq = skb->next; +		skb->next = NULL; +		if (cb->arp_err_handler) +			cb->arp_err_handler(cb->handle, skb); +		else +			t4_ofld_send(adap, skb); +	} +} + +/* + * Called when the host's neighbor layer makes a change to some entry that is + * loaded into the HW L2 table. + */ +void t4_l2t_update(struct adapter *adap, struct neighbour *neigh) +{ +	struct l2t_entry *e; +	struct sk_buff *arpq = NULL; +	struct l2t_data *d = adap->l2t; +	int addr_len = neigh->tbl->key_len; +	u32 *addr = (u32 *) neigh->primary_key; +	int ifidx = neigh->dev->ifindex; +	int hash = addr_hash(addr, addr_len, ifidx); + +	read_lock_bh(&d->lock); +	for (e = d->l2tab[hash].first; e; e = e->next) +		if (!addreq(e, addr) && e->ifindex == ifidx) { +			spin_lock(&e->lock); +			if (atomic_read(&e->refcnt)) +				goto found; +			spin_unlock(&e->lock); +			break; +		} +	read_unlock_bh(&d->lock); +	return; + + found: +	read_unlock(&d->lock); + +	if (neigh != e->neigh) +		neigh_replace(e, neigh); + +	if (e->state == L2T_STATE_RESOLVING) { +		if (neigh->nud_state & NUD_FAILED) { +			arpq = e->arpq_head; +			e->arpq_head = e->arpq_tail = NULL; +		} else if ((neigh->nud_state & (NUD_CONNECTED | NUD_STALE)) && +			   e->arpq_head) { +			write_l2e(adap, e, 1); +		} +	} else { +		e->state = neigh->nud_state & NUD_CONNECTED ? +			L2T_STATE_VALID : L2T_STATE_STALE; +		if (memcmp(e->dmac, neigh->ha, sizeof(e->dmac))) +			write_l2e(adap, e, 0); +	} + +	spin_unlock_bh(&e->lock); + +	if (arpq) +		handle_failed_resolution(adap, arpq); +} + +/* + * Allocate an L2T entry for use by a switching rule.  Such entries need to be + * explicitly freed and while busy they are not on any hash chain, so normal + * address resolution updates do not see them. + */ +struct l2t_entry *t4_l2t_alloc_switching(struct l2t_data *d) +{ +	struct l2t_entry *e; + +	write_lock_bh(&d->lock); +	e = alloc_l2e(d); +	if (e) { +		spin_lock(&e->lock);          /* avoid race with t4_l2t_free */ +		e->state = L2T_STATE_SWITCHING; +		atomic_set(&e->refcnt, 1); +		spin_unlock(&e->lock); +	} +	write_unlock_bh(&d->lock); +	return e; +} + +/* + * Sets/updates the contents of a switching L2T entry that has been allocated + * with an earlier call to @t4_l2t_alloc_switching. + */ +int t4_l2t_set_switching(struct adapter *adap, struct l2t_entry *e, u16 vlan, +			 u8 port, u8 *eth_addr) +{ +	e->vlan = vlan; +	e->lport = port; +	memcpy(e->dmac, eth_addr, ETH_ALEN); +	return write_l2e(adap, e, 0); +} + +struct l2t_data *t4_init_l2t(void) +{ +	int i; +	struct l2t_data *d; + +	d = t4_alloc_mem(sizeof(*d)); +	if (!d) +		return NULL; + +	d->rover = d->l2tab; +	atomic_set(&d->nfree, L2T_SIZE); +	rwlock_init(&d->lock); + +	for (i = 0; i < L2T_SIZE; ++i) { +		d->l2tab[i].idx = i; +		d->l2tab[i].state = L2T_STATE_UNUSED; +		spin_lock_init(&d->l2tab[i].lock); +		atomic_set(&d->l2tab[i].refcnt, 0); +	} +	return d; +} + +#include <linux/module.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> + +static inline void *l2t_get_idx(struct seq_file *seq, loff_t pos) +{ +	struct l2t_entry *l2tab = seq->private; + +	return pos >= L2T_SIZE ? NULL : &l2tab[pos]; +} + +static void *l2t_seq_start(struct seq_file *seq, loff_t *pos) +{ +	return *pos ? l2t_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; +} + +static void *l2t_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ +	v = l2t_get_idx(seq, *pos); +	if (v) +		++*pos; +	return v; +} + +static void l2t_seq_stop(struct seq_file *seq, void *v) +{ +} + +static char l2e_state(const struct l2t_entry *e) +{ +	switch (e->state) { +	case L2T_STATE_VALID: return 'V'; +	case L2T_STATE_STALE: return 'S'; +	case L2T_STATE_SYNC_WRITE: return 'W'; +	case L2T_STATE_RESOLVING: return e->arpq_head ? 'A' : 'R'; +	case L2T_STATE_SWITCHING: return 'X'; +	default: +		return 'U'; +	} +} + +static int l2t_seq_show(struct seq_file *seq, void *v) +{ +	if (v == SEQ_START_TOKEN) +		seq_puts(seq, " Idx IP address                " +			 "Ethernet address  VLAN/P LP State Users Port\n"); +	else { +		char ip[60]; +		struct l2t_entry *e = v; + +		spin_lock_bh(&e->lock); +		if (e->state == L2T_STATE_SWITCHING) +			ip[0] = '\0'; +		else +			sprintf(ip, e->v6 ? "%pI6c" : "%pI4", e->addr); +		seq_printf(seq, "%4u %-25s %17pM %4d %u %2u   %c   %5u %s\n", +			   e->idx, ip, e->dmac, +			   e->vlan & VLAN_VID_MASK, vlan_prio(e), e->lport, +			   l2e_state(e), atomic_read(&e->refcnt), +			   e->neigh ? e->neigh->dev->name : ""); +		spin_unlock_bh(&e->lock); +	} +	return 0; +} + +static const struct seq_operations l2t_seq_ops = { +	.start = l2t_seq_start, +	.next = l2t_seq_next, +	.stop = l2t_seq_stop, +	.show = l2t_seq_show +}; + +static int l2t_seq_open(struct inode *inode, struct file *file) +{ +	int rc = seq_open(file, &l2t_seq_ops); + +	if (!rc) { +		struct adapter *adap = inode->i_private; +		struct seq_file *seq = file->private_data; + +		seq->private = adap->l2t->l2tab; +	} +	return rc; +} + +const struct file_operations t4_l2t_fops = { +	.owner = THIS_MODULE, +	.open = l2t_seq_open, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = seq_release, +}; diff --git a/drivers/net/cxgb4/l2t.h b/drivers/net/cxgb4/l2t.h new file mode 100644 index 00000000000..643f27ed3cf --- /dev/null +++ b/drivers/net/cxgb4/l2t.h @@ -0,0 +1,110 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses.  You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + *     Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *      - Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + * + *      - Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __CXGB4_L2T_H +#define __CXGB4_L2T_H + +#include <linux/spinlock.h> +#include <linux/if_ether.h> +#include <asm/atomic.h> + +struct adapter; +struct l2t_data; +struct neighbour; +struct net_device; +struct file_operations; +struct cpl_l2t_write_rpl; + +/* + * Each L2T entry plays multiple roles.  First of all, it keeps state for the + * corresponding entry of the HW L2 table and maintains a queue of offload + * packets awaiting address resolution.  Second, it is a node of a hash table + * chain, where the nodes of the chain are linked together through their next + * pointer.  Finally, each node is a bucket of a hash table, pointing to the + * first element in its chain through its first pointer. + */ +struct l2t_entry { +	u16 state;                  /* entry state */ +	u16 idx;                    /* entry index */ +	u32 addr[4];                /* next hop IP or IPv6 address */ +	int ifindex;                /* neighbor's net_device's ifindex */ +	struct neighbour *neigh;    /* associated neighbour */ +	struct l2t_entry *first;    /* start of hash chain */ +	struct l2t_entry *next;     /* next l2t_entry on chain */ +	struct sk_buff *arpq_head;  /* queue of packets awaiting resolution */ +	struct sk_buff *arpq_tail; +	spinlock_t lock; +	atomic_t refcnt;            /* entry reference count */ +	u16 hash;                   /* hash bucket the entry is on */ +	u16 vlan;                   /* VLAN TCI (id: bits 0-11, prio: 13-15 */ +	u8 v6;                      /* whether entry is for IPv6 */ +	u8 lport;                   /* associated offload logical interface */ +	u8 dmac[ETH_ALEN];          /* neighbour's MAC address */ +}; + +typedef void (*arp_err_handler_t)(void *handle, struct sk_buff *skb); + +/* + * Callback stored in an skb to handle address resolution failure. + */ +struct l2t_skb_cb { +	void *handle; +	arp_err_handler_t arp_err_handler; +}; + +#define L2T_SKB_CB(skb) ((struct l2t_skb_cb *)(skb)->cb) + +static inline void t4_set_arp_err_handler(struct sk_buff *skb, void *handle, +					  arp_err_handler_t handler) +{ +	L2T_SKB_CB(skb)->handle = handle; +	L2T_SKB_CB(skb)->arp_err_handler = handler; +} + +void cxgb4_l2t_release(struct l2t_entry *e); +int cxgb4_l2t_send(struct net_device *dev, struct sk_buff *skb, +		   struct l2t_entry *e); +struct l2t_entry *cxgb4_l2t_get(struct l2t_data *d, struct neighbour *neigh, +				const struct net_device *physdev, +				unsigned int priority); + +void t4_l2t_update(struct adapter *adap, struct neighbour *neigh); +struct l2t_entry *t4_l2t_alloc_switching(struct l2t_data *d); +int t4_l2t_set_switching(struct adapter *adap, struct l2t_entry *e, u16 vlan, +			 u8 port, u8 *eth_addr); +struct l2t_data *t4_init_l2t(void); +void do_l2t_write_rpl(struct adapter *p, const struct cpl_l2t_write_rpl *rpl); + +extern const struct file_operations t4_l2t_fops; +#endif  /* __CXGB4_L2T_H */ diff --git a/drivers/net/cxgb4/sge.c b/drivers/net/cxgb4/sge.c new file mode 100644 index 00000000000..14adc58e71c --- /dev/null +++ b/drivers/net/cxgb4/sge.c @@ -0,0 +1,2431 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses.  You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + *     Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *      - Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + * + *      - Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/if_vlan.h> +#include <linux/ip.h> +#include <linux/dma-mapping.h> +#include <linux/jiffies.h> +#include <net/ipv6.h> +#include <net/tcp.h> +#include "cxgb4.h" +#include "t4_regs.h" +#include "t4_msg.h" +#include "t4fw_api.h" + +/* + * Rx buffer size.  We use largish buffers if possible but settle for single + * pages under memory shortage. + */ +#if PAGE_SHIFT >= 16 +# define FL_PG_ORDER 0 +#else +# define FL_PG_ORDER (16 - PAGE_SHIFT) +#endif + +/* RX_PULL_LEN should be <= RX_COPY_THRES */ +#define RX_COPY_THRES    256 +#define RX_PULL_LEN      128 + +/* + * Main body length for sk_buffs used for Rx Ethernet packets with fragments. + * Should be >= RX_PULL_LEN but possibly bigger to give pskb_may_pull some room. + */ +#define RX_PKT_SKB_LEN   512 + +/* Ethernet header padding prepended to RX_PKTs */ +#define RX_PKT_PAD 2 + +/* + * Max number of Tx descriptors we clean up at a time.  Should be modest as + * freeing skbs isn't cheap and it happens while holding locks.  We just need + * to free packets faster than they arrive, we eventually catch up and keep + * the amortized cost reasonable.  Must be >= 2 * TXQ_STOP_THRES. + */ +#define MAX_TX_RECLAIM 16 + +/* + * Max number of Rx buffers we replenish at a time.  Again keep this modest, + * allocating buffers isn't cheap either. + */ +#define MAX_RX_REFILL 16U + +/* + * Period of the Rx queue check timer.  This timer is infrequent as it has + * something to do only when the system experiences severe memory shortage. + */ +#define RX_QCHECK_PERIOD (HZ / 2) + +/* + * Period of the Tx queue check timer. + */ +#define TX_QCHECK_PERIOD (HZ / 2) + +/* + * Max number of Tx descriptors to be reclaimed by the Tx timer. + */ +#define MAX_TIMER_TX_RECLAIM 100 + +/* + * Timer index used when backing off due to memory shortage. + */ +#define NOMEM_TMR_IDX (SGE_NTIMERS - 1) + +/* + * An FL with <= FL_STARVE_THRES buffers is starving and a periodic timer will + * attempt to refill it. + */ +#define FL_STARVE_THRES 4 + +/* + * Suspend an Ethernet Tx queue with fewer available descriptors than this. + * This is the same as calc_tx_descs() for a TSO packet with + * nr_frags == MAX_SKB_FRAGS. + */ +#define ETHTXQ_STOP_THRES \ +	(1 + DIV_ROUND_UP((3 * MAX_SKB_FRAGS) / 2 + (MAX_SKB_FRAGS & 1), 8)) + +/* + * Suspension threshold for non-Ethernet Tx queues.  We require enough room + * for a full sized WR. + */ +#define TXQ_STOP_THRES (SGE_MAX_WR_LEN / sizeof(struct tx_desc)) + +/* + * Max Tx descriptor space we allow for an Ethernet packet to be inlined + * into a WR. + */ +#define MAX_IMM_TX_PKT_LEN 128 + +/* + * Max size of a WR sent through a control Tx queue. + */ +#define MAX_CTRL_WR_LEN SGE_MAX_WR_LEN + +enum { +	/* packet alignment in FL buffers */ +	FL_ALIGN = L1_CACHE_BYTES < 32 ? 32 : L1_CACHE_BYTES, +	/* egress status entry size */ +	STAT_LEN = L1_CACHE_BYTES > 64 ? 128 : 64 +}; + +struct tx_sw_desc {                /* SW state per Tx descriptor */ +	struct sk_buff *skb; +	struct ulptx_sgl *sgl; +}; + +struct rx_sw_desc {                /* SW state per Rx descriptor */ +	struct page *page; +	dma_addr_t dma_addr; +}; + +/* + * The low bits of rx_sw_desc.dma_addr have special meaning. + */ +enum { +	RX_LARGE_BUF    = 1 << 0, /* buffer is larger than PAGE_SIZE */ +	RX_UNMAPPED_BUF = 1 << 1, /* buffer is not mapped */ +}; + +static inline dma_addr_t get_buf_addr(const struct rx_sw_desc *d) +{ +	return d->dma_addr & ~(dma_addr_t)(RX_LARGE_BUF | RX_UNMAPPED_BUF); +} + +static inline bool is_buf_mapped(const struct rx_sw_desc *d) +{ +	return !(d->dma_addr & RX_UNMAPPED_BUF); +} + +/** + *	txq_avail - return the number of available slots in a Tx queue + *	@q: the Tx queue + * + *	Returns the number of descriptors in a Tx queue available to write new + *	packets. + */ +static inline unsigned int txq_avail(const struct sge_txq *q) +{ +	return q->size - 1 - q->in_use; +} + +/** + *	fl_cap - return the capacity of a free-buffer list + *	@fl: the FL + * + *	Returns the capacity of a free-buffer list.  The capacity is less than + *	the size because one descriptor needs to be left unpopulated, otherwise + *	HW will think the FL is empty. + */ +static inline unsigned int fl_cap(const struct sge_fl *fl) +{ +	return fl->size - 8;   /* 1 descriptor = 8 buffers */ +} + +static inline bool fl_starving(const struct sge_fl *fl) +{ +	return fl->avail - fl->pend_cred <= FL_STARVE_THRES; +} + +static int map_skb(struct device *dev, const struct sk_buff *skb, +		   dma_addr_t *addr) +{ +	const skb_frag_t *fp, *end; +	const struct skb_shared_info *si; + +	*addr = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); +	if (dma_mapping_error(dev, *addr)) +		goto out_err; + +	si = skb_shinfo(skb); +	end = &si->frags[si->nr_frags]; + +	for (fp = si->frags; fp < end; fp++) { +		*++addr = dma_map_page(dev, fp->page, fp->page_offset, fp->size, +				       DMA_TO_DEVICE); +		if (dma_mapping_error(dev, *addr)) +			goto unwind; +	} +	return 0; + +unwind: +	while (fp-- > si->frags) +		dma_unmap_page(dev, *--addr, fp->size, DMA_TO_DEVICE); + +	dma_unmap_single(dev, addr[-1], skb_headlen(skb), DMA_TO_DEVICE); +out_err: +	return -ENOMEM; +} + +#ifdef CONFIG_NEED_DMA_MAP_STATE +static void unmap_skb(struct device *dev, const struct sk_buff *skb, +		      const dma_addr_t *addr) +{ +	const skb_frag_t *fp, *end; +	const struct skb_shared_info *si; + +	dma_unmap_single(dev, *addr++, skb_headlen(skb), DMA_TO_DEVICE); + +	si = skb_shinfo(skb); +	end = &si->frags[si->nr_frags]; +	for (fp = si->frags; fp < end; fp++) +		dma_unmap_page(dev, *addr++, fp->size, DMA_TO_DEVICE); +} + +/** + *	deferred_unmap_destructor - unmap a packet when it is freed + *	@skb: the packet + * + *	This is the packet destructor used for Tx packets that need to remain + *	mapped until they are freed rather than until their Tx descriptors are + *	freed. + */ +static void deferred_unmap_destructor(struct sk_buff *skb) +{ +	unmap_skb(skb->dev->dev.parent, skb, (dma_addr_t *)skb->head); +} +#endif + +static void unmap_sgl(struct device *dev, const struct sk_buff *skb, +		      const struct ulptx_sgl *sgl, const struct sge_txq *q) +{ +	const struct ulptx_sge_pair *p; +	unsigned int nfrags = skb_shinfo(skb)->nr_frags; + +	if (likely(skb_headlen(skb))) +		dma_unmap_single(dev, be64_to_cpu(sgl->addr0), ntohl(sgl->len0), +				 DMA_TO_DEVICE); +	else { +		dma_unmap_page(dev, be64_to_cpu(sgl->addr0), ntohl(sgl->len0), +			       DMA_TO_DEVICE); +		nfrags--; +	} + +	/* +	 * the complexity below is because of the possibility of a wrap-around +	 * in the middle of an SGL +	 */ +	for (p = sgl->sge; nfrags >= 2; nfrags -= 2) { +		if (likely((u8 *)(p + 1) <= (u8 *)q->stat)) { +unmap:			dma_unmap_page(dev, be64_to_cpu(p->addr[0]), +				       ntohl(p->len[0]), DMA_TO_DEVICE); +			dma_unmap_page(dev, be64_to_cpu(p->addr[1]), +				       ntohl(p->len[1]), DMA_TO_DEVICE); +			p++; +		} else if ((u8 *)p == (u8 *)q->stat) { +			p = (const struct ulptx_sge_pair *)q->desc; +			goto unmap; +		} else if ((u8 *)p + 8 == (u8 *)q->stat) { +			const __be64 *addr = (const __be64 *)q->desc; + +			dma_unmap_page(dev, be64_to_cpu(addr[0]), +				       ntohl(p->len[0]), DMA_TO_DEVICE); +			dma_unmap_page(dev, be64_to_cpu(addr[1]), +				       ntohl(p->len[1]), DMA_TO_DEVICE); +			p = (const struct ulptx_sge_pair *)&addr[2]; +		} else { +			const __be64 *addr = (const __be64 *)q->desc; + +			dma_unmap_page(dev, be64_to_cpu(p->addr[0]), +				       ntohl(p->len[0]), DMA_TO_DEVICE); +			dma_unmap_page(dev, be64_to_cpu(addr[0]), +				       ntohl(p->len[1]), DMA_TO_DEVICE); +			p = (const struct ulptx_sge_pair *)&addr[1]; +		} +	} +	if (nfrags) { +		__be64 addr; + +		if ((u8 *)p == (u8 *)q->stat) +			p = (const struct ulptx_sge_pair *)q->desc; +		addr = (u8 *)p + 16 <= (u8 *)q->stat ? p->addr[0] : +						       *(const __be64 *)q->desc; +		dma_unmap_page(dev, be64_to_cpu(addr), ntohl(p->len[0]), +			       DMA_TO_DEVICE); +	} +} + +/** + *	free_tx_desc - reclaims Tx descriptors and their buffers + *	@adapter: the adapter + *	@q: the Tx queue to reclaim descriptors from + *	@n: the number of descriptors to reclaim + *	@unmap: whether the buffers should be unmapped for DMA + * + *	Reclaims Tx descriptors from an SGE Tx queue and frees the associated + *	Tx buffers.  Called with the Tx queue lock held. + */ +static void free_tx_desc(struct adapter *adap, struct sge_txq *q, +			 unsigned int n, bool unmap) +{ +	struct tx_sw_desc *d; +	unsigned int cidx = q->cidx; +	struct device *dev = adap->pdev_dev; + +	d = &q->sdesc[cidx]; +	while (n--) { +		if (d->skb) {                       /* an SGL is present */ +			if (unmap) +				unmap_sgl(dev, d->skb, d->sgl, q); +			kfree_skb(d->skb); +			d->skb = NULL; +		} +		++d; +		if (++cidx == q->size) { +			cidx = 0; +			d = q->sdesc; +		} +	} +	q->cidx = cidx; +} + +/* + * Return the number of reclaimable descriptors in a Tx queue. + */ +static inline int reclaimable(const struct sge_txq *q) +{ +	int hw_cidx = ntohs(q->stat->cidx); +	hw_cidx -= q->cidx; +	return hw_cidx < 0 ? hw_cidx + q->size : hw_cidx; +} + +/** + *	reclaim_completed_tx - reclaims completed Tx descriptors + *	@adap: the adapter + *	@q: the Tx queue to reclaim completed descriptors from + *	@unmap: whether the buffers should be unmapped for DMA + * + *	Reclaims Tx descriptors that the SGE has indicated it has processed, + *	and frees the associated buffers if possible.  Called with the Tx + *	queue locked. + */ +static inline void reclaim_completed_tx(struct adapter *adap, struct sge_txq *q, +					bool unmap) +{ +	int avail = reclaimable(q); + +	if (avail) { +		/* +		 * Limit the amount of clean up work we do at a time to keep +		 * the Tx lock hold time O(1). +		 */ +		if (avail > MAX_TX_RECLAIM) +			avail = MAX_TX_RECLAIM; + +		free_tx_desc(adap, q, avail, unmap); +		q->in_use -= avail; +	} +} + +static inline int get_buf_size(const struct rx_sw_desc *d) +{ +#if FL_PG_ORDER > 0 +	return (d->dma_addr & RX_LARGE_BUF) ? (PAGE_SIZE << FL_PG_ORDER) : +					      PAGE_SIZE; +#else +	return PAGE_SIZE; +#endif +} + +/** + *	free_rx_bufs - free the Rx buffers on an SGE free list + *	@adap: the adapter + *	@q: the SGE free list to free buffers from + *	@n: how many buffers to free + * + *	Release the next @n buffers on an SGE free-buffer Rx queue.   The + *	buffers must be made inaccessible to HW before calling this function. + */ +static void free_rx_bufs(struct adapter *adap, struct sge_fl *q, int n) +{ +	while (n--) { +		struct rx_sw_desc *d = &q->sdesc[q->cidx]; + +		if (is_buf_mapped(d)) +			dma_unmap_page(adap->pdev_dev, get_buf_addr(d), +				       get_buf_size(d), PCI_DMA_FROMDEVICE); +		put_page(d->page); +		d->page = NULL; +		if (++q->cidx == q->size) +			q->cidx = 0; +		q->avail--; +	} +} + +/** + *	unmap_rx_buf - unmap the current Rx buffer on an SGE free list + *	@adap: the adapter + *	@q: the SGE free list + * + *	Unmap the current buffer on an SGE free-buffer Rx queue.   The + *	buffer must be made inaccessible to HW before calling this function. + * + *	This is similar to @free_rx_bufs above but does not free the buffer. + *	Do note that the FL still loses any further access to the buffer. + */ +static void unmap_rx_buf(struct adapter *adap, struct sge_fl *q) +{ +	struct rx_sw_desc *d = &q->sdesc[q->cidx]; + +	if (is_buf_mapped(d)) +		dma_unmap_page(adap->pdev_dev, get_buf_addr(d), +			       get_buf_size(d), PCI_DMA_FROMDEVICE); +	d->page = NULL; +	if (++q->cidx == q->size) +		q->cidx = 0; +	q->avail--; +} + +static inline void ring_fl_db(struct adapter *adap, struct sge_fl *q) +{ +	if (q->pend_cred >= 8) { +		wmb(); +		t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), DBPRIO | +			     QID(q->cntxt_id) | PIDX(q->pend_cred / 8)); +		q->pend_cred &= 7; +	} +} + +static inline void set_rx_sw_desc(struct rx_sw_desc *sd, struct page *pg, +				  dma_addr_t mapping) +{ +	sd->page = pg; +	sd->dma_addr = mapping;      /* includes size low bits */ +} + +/** + *	refill_fl - refill an SGE Rx buffer ring + *	@adap: the adapter + *	@q: the ring to refill + *	@n: the number of new buffers to allocate + *	@gfp: the gfp flags for the allocations + * + *	(Re)populate an SGE free-buffer queue with up to @n new packet buffers, + *	allocated with the supplied gfp flags.  The caller must assure that + *	@n does not exceed the queue's capacity.  If afterwards the queue is + *	found critically low mark it as starving in the bitmap of starving FLs. + * + *	Returns the number of buffers allocated. + */ +static unsigned int refill_fl(struct adapter *adap, struct sge_fl *q, int n, +			      gfp_t gfp) +{ +	struct page *pg; +	dma_addr_t mapping; +	unsigned int cred = q->avail; +	__be64 *d = &q->desc[q->pidx]; +	struct rx_sw_desc *sd = &q->sdesc[q->pidx]; + +	gfp |= __GFP_NOWARN;         /* failures are expected */ + +#if FL_PG_ORDER > 0 +	/* +	 * Prefer large buffers +	 */ +	while (n) { +		pg = alloc_pages(gfp | __GFP_COMP, FL_PG_ORDER); +		if (unlikely(!pg)) { +			q->large_alloc_failed++; +			break;       /* fall back to single pages */ +		} + +		mapping = dma_map_page(adap->pdev_dev, pg, 0, +				       PAGE_SIZE << FL_PG_ORDER, +				       PCI_DMA_FROMDEVICE); +		if (unlikely(dma_mapping_error(adap->pdev_dev, mapping))) { +			__free_pages(pg, FL_PG_ORDER); +			goto out;   /* do not try small pages for this error */ +		} +		mapping |= RX_LARGE_BUF; +		*d++ = cpu_to_be64(mapping); + +		set_rx_sw_desc(sd, pg, mapping); +		sd++; + +		q->avail++; +		if (++q->pidx == q->size) { +			q->pidx = 0; +			sd = q->sdesc; +			d = q->desc; +		} +		n--; +	} +#endif + +	while (n--) { +		pg = __netdev_alloc_page(adap->port[0], gfp); +		if (unlikely(!pg)) { +			q->alloc_failed++; +			break; +		} + +		mapping = dma_map_page(adap->pdev_dev, pg, 0, PAGE_SIZE, +				       PCI_DMA_FROMDEVICE); +		if (unlikely(dma_mapping_error(adap->pdev_dev, mapping))) { +			netdev_free_page(adap->port[0], pg); +			goto out; +		} +		*d++ = cpu_to_be64(mapping); + +		set_rx_sw_desc(sd, pg, mapping); +		sd++; + +		q->avail++; +		if (++q->pidx == q->size) { +			q->pidx = 0; +			sd = q->sdesc; +			d = q->desc; +		} +	} + +out:	cred = q->avail - cred; +	q->pend_cred += cred; +	ring_fl_db(adap, q); + +	if (unlikely(fl_starving(q))) { +		smp_wmb(); +		set_bit(q->cntxt_id, adap->sge.starving_fl); +	} + +	return cred; +} + +static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl) +{ +	refill_fl(adap, fl, min(MAX_RX_REFILL, fl_cap(fl) - fl->avail), +		  GFP_ATOMIC); +} + +/** + *	alloc_ring - allocate resources for an SGE descriptor ring + *	@dev: the PCI device's core device + *	@nelem: the number of descriptors + *	@elem_size: the size of each descriptor + *	@sw_size: the size of the SW state associated with each ring element + *	@phys: the physical address of the allocated ring + *	@metadata: address of the array holding the SW state for the ring + *	@stat_size: extra space in HW ring for status information + * + *	Allocates resources for an SGE descriptor ring, such as Tx queues, + *	free buffer lists, or response queues.  Each SGE ring requires + *	space for its HW descriptors plus, optionally, space for the SW state + *	associated with each HW entry (the metadata).  The function returns + *	three values: the virtual address for the HW ring (the return value + *	of the function), the bus address of the HW ring, and the address + *	of the SW ring. + */ +static void *alloc_ring(struct device *dev, size_t nelem, size_t elem_size, +			size_t sw_size, dma_addr_t *phys, void *metadata, +			size_t stat_size) +{ +	size_t len = nelem * elem_size + stat_size; +	void *s = NULL; +	void *p = dma_alloc_coherent(dev, len, phys, GFP_KERNEL); + +	if (!p) +		return NULL; +	if (sw_size) { +		s = kcalloc(nelem, sw_size, GFP_KERNEL); + +		if (!s) { +			dma_free_coherent(dev, len, p, *phys); +			return NULL; +		} +	} +	if (metadata) +		*(void **)metadata = s; +	memset(p, 0, len); +	return p; +} + +/** + *	sgl_len - calculates the size of an SGL of the given capacity + *	@n: the number of SGL entries + * + *	Calculates the number of flits needed for a scatter/gather list that + *	can hold the given number of entries. + */ +static inline unsigned int sgl_len(unsigned int n) +{ +	n--; +	return (3 * n) / 2 + (n & 1) + 2; +} + +/** + *	flits_to_desc - returns the num of Tx descriptors for the given flits + *	@n: the number of flits + * + *	Returns the number of Tx descriptors needed for the supplied number + *	of flits. + */ +static inline unsigned int flits_to_desc(unsigned int n) +{ +	BUG_ON(n > SGE_MAX_WR_LEN / 8); +	return DIV_ROUND_UP(n, 8); +} + +/** + *	is_eth_imm - can an Ethernet packet be sent as immediate data? + *	@skb: the packet + * + *	Returns whether an Ethernet packet is small enough to fit as + *	immediate data. + */ +static inline int is_eth_imm(const struct sk_buff *skb) +{ +	return skb->len <= MAX_IMM_TX_PKT_LEN - sizeof(struct cpl_tx_pkt); +} + +/** + *	calc_tx_flits - calculate the number of flits for a packet Tx WR + *	@skb: the packet + * + *	Returns the number of flits needed for a Tx WR for the given Ethernet + *	packet, including the needed WR and CPL headers. + */ +static inline unsigned int calc_tx_flits(const struct sk_buff *skb) +{ +	unsigned int flits; + +	if (is_eth_imm(skb)) +		return DIV_ROUND_UP(skb->len + sizeof(struct cpl_tx_pkt), 8); + +	flits = sgl_len(skb_shinfo(skb)->nr_frags + 1) + 4; +	if (skb_shinfo(skb)->gso_size) +		flits += 2; +	return flits; +} + +/** + *	calc_tx_descs - calculate the number of Tx descriptors for a packet + *	@skb: the packet + * + *	Returns the number of Tx descriptors needed for the given Ethernet + *	packet, including the needed WR and CPL headers. + */ +static inline unsigned int calc_tx_descs(const struct sk_buff *skb) +{ +	return flits_to_desc(calc_tx_flits(skb)); +} + +/** + *	write_sgl - populate a scatter/gather list for a packet + *	@skb: the packet + *	@q: the Tx queue we are writing into + *	@sgl: starting location for writing the SGL + *	@end: points right after the end of the SGL + *	@start: start offset into skb main-body data to include in the SGL + *	@addr: the list of bus addresses for the SGL elements + * + *	Generates a gather list for the buffers that make up a packet. + *	The caller must provide adequate space for the SGL that will be written. + *	The SGL includes all of the packet's page fragments and the data in its + *	main body except for the first @start bytes.  @sgl must be 16-byte + *	aligned and within a Tx descriptor with available space.  @end points + *	right after the end of the SGL but does not account for any potential + *	wrap around, i.e., @end > @sgl. + */ +static void write_sgl(const struct sk_buff *skb, struct sge_txq *q, +		      struct ulptx_sgl *sgl, u64 *end, unsigned int start, +		      const dma_addr_t *addr) +{ +	unsigned int i, len; +	struct ulptx_sge_pair *to; +	const struct skb_shared_info *si = skb_shinfo(skb); +	unsigned int nfrags = si->nr_frags; +	struct ulptx_sge_pair buf[MAX_SKB_FRAGS / 2 + 1]; + +	len = skb_headlen(skb) - start; +	if (likely(len)) { +		sgl->len0 = htonl(len); +		sgl->addr0 = cpu_to_be64(addr[0] + start); +		nfrags++; +	} else { +		sgl->len0 = htonl(si->frags[0].size); +		sgl->addr0 = cpu_to_be64(addr[1]); +	} + +	sgl->cmd_nsge = htonl(ULPTX_CMD(ULP_TX_SC_DSGL) | ULPTX_NSGE(nfrags)); +	if (likely(--nfrags == 0)) +		return; +	/* +	 * Most of the complexity below deals with the possibility we hit the +	 * end of the queue in the middle of writing the SGL.  For this case +	 * only we create the SGL in a temporary buffer and then copy it. +	 */ +	to = (u8 *)end > (u8 *)q->stat ? buf : sgl->sge; + +	for (i = (nfrags != si->nr_frags); nfrags >= 2; nfrags -= 2, to++) { +		to->len[0] = cpu_to_be32(si->frags[i].size); +		to->len[1] = cpu_to_be32(si->frags[++i].size); +		to->addr[0] = cpu_to_be64(addr[i]); +		to->addr[1] = cpu_to_be64(addr[++i]); +	} +	if (nfrags) { +		to->len[0] = cpu_to_be32(si->frags[i].size); +		to->len[1] = cpu_to_be32(0); +		to->addr[0] = cpu_to_be64(addr[i + 1]); +	} +	if (unlikely((u8 *)end > (u8 *)q->stat)) { +		unsigned int part0 = (u8 *)q->stat - (u8 *)sgl->sge, part1; + +		if (likely(part0)) +			memcpy(sgl->sge, buf, part0); +		part1 = (u8 *)end - (u8 *)q->stat; +		memcpy(q->desc, (u8 *)buf + part0, part1); +		end = (void *)q->desc + part1; +	} +	if ((uintptr_t)end & 8)           /* 0-pad to multiple of 16 */ +		*(u64 *)end = 0; +} + +/** + *	ring_tx_db - check and potentially ring a Tx queue's doorbell + *	@adap: the adapter + *	@q: the Tx queue + *	@n: number of new descriptors to give to HW + * + *	Ring the doorbel for a Tx queue. + */ +static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n) +{ +	wmb();            /* write descriptors before telling HW */ +	t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), +		     QID(q->cntxt_id) | PIDX(n)); +} + +/** + *	inline_tx_skb - inline a packet's data into Tx descriptors + *	@skb: the packet + *	@q: the Tx queue where the packet will be inlined + *	@pos: starting position in the Tx queue where to inline the packet + * + *	Inline a packet's contents directly into Tx descriptors, starting at + *	the given position within the Tx DMA ring. + *	Most of the complexity of this operation is dealing with wrap arounds + *	in the middle of the packet we want to inline. + */ +static void inline_tx_skb(const struct sk_buff *skb, const struct sge_txq *q, +			  void *pos) +{ +	u64 *p; +	int left = (void *)q->stat - pos; + +	if (likely(skb->len <= left)) { +		if (likely(!skb->data_len)) +			skb_copy_from_linear_data(skb, pos, skb->len); +		else +			skb_copy_bits(skb, 0, pos, skb->len); +		pos += skb->len; +	} else { +		skb_copy_bits(skb, 0, pos, left); +		skb_copy_bits(skb, left, q->desc, skb->len - left); +		pos = (void *)q->desc + (skb->len - left); +	} + +	/* 0-pad to multiple of 16 */ +	p = PTR_ALIGN(pos, 8); +	if ((uintptr_t)p & 8) +		*p = 0; +} + +/* + * Figure out what HW csum a packet wants and return the appropriate control + * bits. + */ +static u64 hwcsum(const struct sk_buff *skb) +{ +	int csum_type; +	const struct iphdr *iph = ip_hdr(skb); + +	if (iph->version == 4) { +		if (iph->protocol == IPPROTO_TCP) +			csum_type = TX_CSUM_TCPIP; +		else if (iph->protocol == IPPROTO_UDP) +			csum_type = TX_CSUM_UDPIP; +		else { +nocsum:			/* +			 * unknown protocol, disable HW csum +			 * and hope a bad packet is detected +			 */ +			return TXPKT_L4CSUM_DIS; +		} +	} else { +		/* +		 * this doesn't work with extension headers +		 */ +		const struct ipv6hdr *ip6h = (const struct ipv6hdr *)iph; + +		if (ip6h->nexthdr == IPPROTO_TCP) +			csum_type = TX_CSUM_TCPIP6; +		else if (ip6h->nexthdr == IPPROTO_UDP) +			csum_type = TX_CSUM_UDPIP6; +		else +			goto nocsum; +	} + +	if (likely(csum_type >= TX_CSUM_TCPIP)) +		return TXPKT_CSUM_TYPE(csum_type) | +			TXPKT_IPHDR_LEN(skb_network_header_len(skb)) | +			TXPKT_ETHHDR_LEN(skb_network_offset(skb) - ETH_HLEN); +	else { +		int start = skb_transport_offset(skb); + +		return TXPKT_CSUM_TYPE(csum_type) | TXPKT_CSUM_START(start) | +			TXPKT_CSUM_LOC(start + skb->csum_offset); +	} +} + +static void eth_txq_stop(struct sge_eth_txq *q) +{ +	netif_tx_stop_queue(q->txq); +	q->q.stops++; +} + +static inline void txq_advance(struct sge_txq *q, unsigned int n) +{ +	q->in_use += n; +	q->pidx += n; +	if (q->pidx >= q->size) +		q->pidx -= q->size; +} + +/** + *	t4_eth_xmit - add a packet to an Ethernet Tx queue + *	@skb: the packet + *	@dev: the egress net device + * + *	Add a packet to an SGE Ethernet Tx queue.  Runs with softirqs disabled. + */ +netdev_tx_t t4_eth_xmit(struct sk_buff *skb, struct net_device *dev) +{ +	u32 wr_mid; +	u64 cntrl, *end; +	int qidx, credits; +	unsigned int flits, ndesc; +	struct adapter *adap; +	struct sge_eth_txq *q; +	const struct port_info *pi; +	struct fw_eth_tx_pkt_wr *wr; +	struct cpl_tx_pkt_core *cpl; +	const struct skb_shared_info *ssi; +	dma_addr_t addr[MAX_SKB_FRAGS + 1]; + +	/* +	 * The chip min packet length is 10 octets but play safe and reject +	 * anything shorter than an Ethernet header. +	 */ +	if (unlikely(skb->len < ETH_HLEN)) { +out_free:	dev_kfree_skb(skb); +		return NETDEV_TX_OK; +	} + +	pi = netdev_priv(dev); +	adap = pi->adapter; +	qidx = skb_get_queue_mapping(skb); +	q = &adap->sge.ethtxq[qidx + pi->first_qset]; + +	reclaim_completed_tx(adap, &q->q, true); + +	flits = calc_tx_flits(skb); +	ndesc = flits_to_desc(flits); +	credits = txq_avail(&q->q) - ndesc; + +	if (unlikely(credits < 0)) { +		eth_txq_stop(q); +		dev_err(adap->pdev_dev, +			"%s: Tx ring %u full while queue awake!\n", +			dev->name, qidx); +		return NETDEV_TX_BUSY; +	} + +	if (!is_eth_imm(skb) && +	    unlikely(map_skb(adap->pdev_dev, skb, addr) < 0)) { +		q->mapping_err++; +		goto out_free; +	} + +	wr_mid = FW_WR_LEN16(DIV_ROUND_UP(flits, 2)); +	if (unlikely(credits < ETHTXQ_STOP_THRES)) { +		eth_txq_stop(q); +		wr_mid |= FW_WR_EQUEQ | FW_WR_EQUIQ; +	} + +	wr = (void *)&q->q.desc[q->q.pidx]; +	wr->equiq_to_len16 = htonl(wr_mid); +	wr->r3 = cpu_to_be64(0); +	end = (u64 *)wr + flits; + +	ssi = skb_shinfo(skb); +	if (ssi->gso_size) { +		struct cpl_tx_pkt_lso *lso = (void *)wr; +		bool v6 = (ssi->gso_type & SKB_GSO_TCPV6) != 0; +		int l3hdr_len = skb_network_header_len(skb); +		int eth_xtra_len = skb_network_offset(skb) - ETH_HLEN; + +		wr->op_immdlen = htonl(FW_WR_OP(FW_ETH_TX_PKT_WR) | +				       FW_WR_IMMDLEN(sizeof(*lso))); +		lso->lso_ctrl = htonl(LSO_OPCODE(CPL_TX_PKT_LSO) | +				      LSO_FIRST_SLICE | LSO_LAST_SLICE | +				      LSO_IPV6(v6) | +				      LSO_ETHHDR_LEN(eth_xtra_len / 4) | +				      LSO_IPHDR_LEN(l3hdr_len / 4) | +				      LSO_TCPHDR_LEN(tcp_hdr(skb)->doff)); +		lso->ipid_ofst = htons(0); +		lso->mss = htons(ssi->gso_size); +		lso->seqno_offset = htonl(0); +		lso->len = htonl(skb->len); +		cpl = (void *)(lso + 1); +		cntrl = TXPKT_CSUM_TYPE(v6 ? TX_CSUM_TCPIP6 : TX_CSUM_TCPIP) | +			TXPKT_IPHDR_LEN(l3hdr_len) | +			TXPKT_ETHHDR_LEN(eth_xtra_len); +		q->tso++; +		q->tx_cso += ssi->gso_segs; +	} else { +		int len; + +		len = is_eth_imm(skb) ? skb->len + sizeof(*cpl) : sizeof(*cpl); +		wr->op_immdlen = htonl(FW_WR_OP(FW_ETH_TX_PKT_WR) | +				       FW_WR_IMMDLEN(len)); +		cpl = (void *)(wr + 1); +		if (skb->ip_summed == CHECKSUM_PARTIAL) { +			cntrl = hwcsum(skb) | TXPKT_IPCSUM_DIS; +			q->tx_cso++; +		} else +			cntrl = TXPKT_L4CSUM_DIS | TXPKT_IPCSUM_DIS; +	} + +	if (vlan_tx_tag_present(skb)) { +		q->vlan_ins++; +		cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(vlan_tx_tag_get(skb)); +	} + +	cpl->ctrl0 = htonl(TXPKT_OPCODE(CPL_TX_PKT_XT) | +			   TXPKT_INTF(pi->tx_chan) | TXPKT_PF(0)); +	cpl->pack = htons(0); +	cpl->len = htons(skb->len); +	cpl->ctrl1 = cpu_to_be64(cntrl); + +	if (is_eth_imm(skb)) { +		inline_tx_skb(skb, &q->q, cpl + 1); +		dev_kfree_skb(skb); +	} else { +		int last_desc; + +		write_sgl(skb, &q->q, (struct ulptx_sgl *)(cpl + 1), end, 0, +			  addr); +		skb_orphan(skb); + +		last_desc = q->q.pidx + ndesc - 1; +		if (last_desc >= q->q.size) +			last_desc -= q->q.size; +		q->q.sdesc[last_desc].skb = skb; +		q->q.sdesc[last_desc].sgl = (struct ulptx_sgl *)(cpl + 1); +	} + +	txq_advance(&q->q, ndesc); + +	ring_tx_db(adap, &q->q, ndesc); +	return NETDEV_TX_OK; +} + +/** + *	reclaim_completed_tx_imm - reclaim completed control-queue Tx descs + *	@q: the SGE control Tx queue + * + *	This is a variant of reclaim_completed_tx() that is used for Tx queues + *	that send only immediate data (presently just the control queues) and + *	thus do not have any sk_buffs to release. + */ +static inline void reclaim_completed_tx_imm(struct sge_txq *q) +{ +	int hw_cidx = ntohs(q->stat->cidx); +	int reclaim = hw_cidx - q->cidx; + +	if (reclaim < 0) +		reclaim += q->size; + +	q->in_use -= reclaim; +	q->cidx = hw_cidx; +} + +/** + *	is_imm - check whether a packet can be sent as immediate data + *	@skb: the packet + * + *	Returns true if a packet can be sent as a WR with immediate data. + */ +static inline int is_imm(const struct sk_buff *skb) +{ +	return skb->len <= MAX_CTRL_WR_LEN; +} + +/** + *	ctrlq_check_stop - check if a control queue is full and should stop + *	@q: the queue + *	@wr: most recent WR written to the queue + * + *	Check if a control queue has become full and should be stopped. + *	We clean up control queue descriptors very lazily, only when we are out. + *	If the queue is still full after reclaiming any completed descriptors + *	we suspend it and have the last WR wake it up. + */ +static void ctrlq_check_stop(struct sge_ctrl_txq *q, struct fw_wr_hdr *wr) +{ +	reclaim_completed_tx_imm(&q->q); +	if (unlikely(txq_avail(&q->q) < TXQ_STOP_THRES)) { +		wr->lo |= htonl(FW_WR_EQUEQ | FW_WR_EQUIQ); +		q->q.stops++; +		q->full = 1; +	} +} + +/** + *	ctrl_xmit - send a packet through an SGE control Tx queue + *	@q: the control queue + *	@skb: the packet + * + *	Send a packet through an SGE control Tx queue.  Packets sent through + *	a control queue must fit entirely as immediate data. + */ +static int ctrl_xmit(struct sge_ctrl_txq *q, struct sk_buff *skb) +{ +	unsigned int ndesc; +	struct fw_wr_hdr *wr; + +	if (unlikely(!is_imm(skb))) { +		WARN_ON(1); +		dev_kfree_skb(skb); +		return NET_XMIT_DROP; +	} + +	ndesc = DIV_ROUND_UP(skb->len, sizeof(struct tx_desc)); +	spin_lock(&q->sendq.lock); + +	if (unlikely(q->full)) { +		skb->priority = ndesc;                  /* save for restart */ +		__skb_queue_tail(&q->sendq, skb); +		spin_unlock(&q->sendq.lock); +		return NET_XMIT_CN; +	} + +	wr = (struct fw_wr_hdr *)&q->q.desc[q->q.pidx]; +	inline_tx_skb(skb, &q->q, wr); + +	txq_advance(&q->q, ndesc); +	if (unlikely(txq_avail(&q->q) < TXQ_STOP_THRES)) +		ctrlq_check_stop(q, wr); + +	ring_tx_db(q->adap, &q->q, ndesc); +	spin_unlock(&q->sendq.lock); + +	kfree_skb(skb); +	return NET_XMIT_SUCCESS; +} + +/** + *	restart_ctrlq - restart a suspended control queue + *	@data: the control queue to restart + * + *	Resumes transmission on a suspended Tx control queue. + */ +static void restart_ctrlq(unsigned long data) +{ +	struct sk_buff *skb; +	unsigned int written = 0; +	struct sge_ctrl_txq *q = (struct sge_ctrl_txq *)data; + +	spin_lock(&q->sendq.lock); +	reclaim_completed_tx_imm(&q->q); +	BUG_ON(txq_avail(&q->q) < TXQ_STOP_THRES);  /* q should be empty */ + +	while ((skb = __skb_dequeue(&q->sendq)) != NULL) { +		struct fw_wr_hdr *wr; +		unsigned int ndesc = skb->priority;     /* previously saved */ + +		/* +		 * Write descriptors and free skbs outside the lock to limit +		 * wait times.  q->full is still set so new skbs will be queued. +		 */ +		spin_unlock(&q->sendq.lock); + +		wr = (struct fw_wr_hdr *)&q->q.desc[q->q.pidx]; +		inline_tx_skb(skb, &q->q, wr); +		kfree_skb(skb); + +		written += ndesc; +		txq_advance(&q->q, ndesc); +		if (unlikely(txq_avail(&q->q) < TXQ_STOP_THRES)) { +			unsigned long old = q->q.stops; + +			ctrlq_check_stop(q, wr); +			if (q->q.stops != old) {          /* suspended anew */ +				spin_lock(&q->sendq.lock); +				goto ringdb; +			} +		} +		if (written > 16) { +			ring_tx_db(q->adap, &q->q, written); +			written = 0; +		} +		spin_lock(&q->sendq.lock); +	} +	q->full = 0; +ringdb: if (written) +		ring_tx_db(q->adap, &q->q, written); +	spin_unlock(&q->sendq.lock); +} + +/** + *	t4_mgmt_tx - send a management message + *	@adap: the adapter + *	@skb: the packet containing the management message + * + *	Send a management message through control queue 0. + */ +int t4_mgmt_tx(struct adapter *adap, struct sk_buff *skb) +{ +	int ret; + +	local_bh_disable(); +	ret = ctrl_xmit(&adap->sge.ctrlq[0], skb); +	local_bh_enable(); +	return ret; +} + +/** + *	is_ofld_imm - check whether a packet can be sent as immediate data + *	@skb: the packet + * + *	Returns true if a packet can be sent as an offload WR with immediate + *	data.  We currently use the same limit as for Ethernet packets. + */ +static inline int is_ofld_imm(const struct sk_buff *skb) +{ +	return skb->len <= MAX_IMM_TX_PKT_LEN; +} + +/** + *	calc_tx_flits_ofld - calculate # of flits for an offload packet + *	@skb: the packet + * + *	Returns the number of flits needed for the given offload packet. + *	These packets are already fully constructed and no additional headers + *	will be added. + */ +static inline unsigned int calc_tx_flits_ofld(const struct sk_buff *skb) +{ +	unsigned int flits, cnt; + +	if (is_ofld_imm(skb)) +		return DIV_ROUND_UP(skb->len, 8); + +	flits = skb_transport_offset(skb) / 8U;   /* headers */ +	cnt = skb_shinfo(skb)->nr_frags; +	if (skb->tail != skb->transport_header) +		cnt++; +	return flits + sgl_len(cnt); +} + +/** + *	txq_stop_maperr - stop a Tx queue due to I/O MMU exhaustion + *	@adap: the adapter + *	@q: the queue to stop + * + *	Mark a Tx queue stopped due to I/O MMU exhaustion and resulting + *	inability to map packets.  A periodic timer attempts to restart + *	queues so marked. + */ +static void txq_stop_maperr(struct sge_ofld_txq *q) +{ +	q->mapping_err++; +	q->q.stops++; +	set_bit(q->q.cntxt_id, q->adap->sge.txq_maperr); +} + +/** + *	ofldtxq_stop - stop an offload Tx queue that has become full + *	@q: the queue to stop + *	@skb: the packet causing the queue to become full + * + *	Stops an offload Tx queue that has become full and modifies the packet + *	being written to request a wakeup. + */ +static void ofldtxq_stop(struct sge_ofld_txq *q, struct sk_buff *skb) +{ +	struct fw_wr_hdr *wr = (struct fw_wr_hdr *)skb->data; + +	wr->lo |= htonl(FW_WR_EQUEQ | FW_WR_EQUIQ); +	q->q.stops++; +	q->full = 1; +} + +/** + *	service_ofldq - restart a suspended offload queue + *	@q: the offload queue + * + *	Services an offload Tx queue by moving packets from its packet queue + *	to the HW Tx ring.  The function starts and ends with the queue locked. + */ +static void service_ofldq(struct sge_ofld_txq *q) +{ +	u64 *pos; +	int credits; +	struct sk_buff *skb; +	unsigned int written = 0; +	unsigned int flits, ndesc; + +	while ((skb = skb_peek(&q->sendq)) != NULL && !q->full) { +		/* +		 * We drop the lock but leave skb on sendq, thus retaining +		 * exclusive access to the state of the queue. +		 */ +		spin_unlock(&q->sendq.lock); + +		reclaim_completed_tx(q->adap, &q->q, false); + +		flits = skb->priority;                /* previously saved */ +		ndesc = flits_to_desc(flits); +		credits = txq_avail(&q->q) - ndesc; +		BUG_ON(credits < 0); +		if (unlikely(credits < TXQ_STOP_THRES)) +			ofldtxq_stop(q, skb); + +		pos = (u64 *)&q->q.desc[q->q.pidx]; +		if (is_ofld_imm(skb)) +			inline_tx_skb(skb, &q->q, pos); +		else if (map_skb(q->adap->pdev_dev, skb, +				 (dma_addr_t *)skb->head)) { +			txq_stop_maperr(q); +			spin_lock(&q->sendq.lock); +			break; +		} else { +			int last_desc, hdr_len = skb_transport_offset(skb); + +			memcpy(pos, skb->data, hdr_len); +			write_sgl(skb, &q->q, (void *)pos + hdr_len, +				  pos + flits, hdr_len, +				  (dma_addr_t *)skb->head); +#ifdef CONFIG_NEED_DMA_MAP_STATE +			skb->dev = q->adap->port[0]; +			skb->destructor = deferred_unmap_destructor; +#endif +			last_desc = q->q.pidx + ndesc - 1; +			if (last_desc >= q->q.size) +				last_desc -= q->q.size; +			q->q.sdesc[last_desc].skb = skb; +		} + +		txq_advance(&q->q, ndesc); +		written += ndesc; +		if (unlikely(written > 32)) { +			ring_tx_db(q->adap, &q->q, written); +			written = 0; +		} + +		spin_lock(&q->sendq.lock); +		__skb_unlink(skb, &q->sendq); +		if (is_ofld_imm(skb)) +			kfree_skb(skb); +	} +	if (likely(written)) +		ring_tx_db(q->adap, &q->q, written); +} + +/** + *	ofld_xmit - send a packet through an offload queue + *	@q: the Tx offload queue + *	@skb: the packet + * + *	Send an offload packet through an SGE offload queue. + */ +static int ofld_xmit(struct sge_ofld_txq *q, struct sk_buff *skb) +{ +	skb->priority = calc_tx_flits_ofld(skb);       /* save for restart */ +	spin_lock(&q->sendq.lock); +	__skb_queue_tail(&q->sendq, skb); +	if (q->sendq.qlen == 1) +		service_ofldq(q); +	spin_unlock(&q->sendq.lock); +	return NET_XMIT_SUCCESS; +} + +/** + *	restart_ofldq - restart a suspended offload queue + *	@data: the offload queue to restart + * + *	Resumes transmission on a suspended Tx offload queue. + */ +static void restart_ofldq(unsigned long data) +{ +	struct sge_ofld_txq *q = (struct sge_ofld_txq *)data; + +	spin_lock(&q->sendq.lock); +	q->full = 0;            /* the queue actually is completely empty now */ +	service_ofldq(q); +	spin_unlock(&q->sendq.lock); +} + +/** + *	skb_txq - return the Tx queue an offload packet should use + *	@skb: the packet + * + *	Returns the Tx queue an offload packet should use as indicated by bits + *	1-15 in the packet's queue_mapping. + */ +static inline unsigned int skb_txq(const struct sk_buff *skb) +{ +	return skb->queue_mapping >> 1; +} + +/** + *	is_ctrl_pkt - return whether an offload packet is a control packet + *	@skb: the packet + * + *	Returns whether an offload packet should use an OFLD or a CTRL + *	Tx queue as indicated by bit 0 in the packet's queue_mapping. + */ +static inline unsigned int is_ctrl_pkt(const struct sk_buff *skb) +{ +	return skb->queue_mapping & 1; +} + +static inline int ofld_send(struct adapter *adap, struct sk_buff *skb) +{ +	unsigned int idx = skb_txq(skb); + +	if (unlikely(is_ctrl_pkt(skb))) +		return ctrl_xmit(&adap->sge.ctrlq[idx], skb); +	return ofld_xmit(&adap->sge.ofldtxq[idx], skb); +} + +/** + *	t4_ofld_send - send an offload packet + *	@adap: the adapter + *	@skb: the packet + * + *	Sends an offload packet.  We use the packet queue_mapping to select the + *	appropriate Tx queue as follows: bit 0 indicates whether the packet + *	should be sent as regular or control, bits 1-15 select the queue. + */ +int t4_ofld_send(struct adapter *adap, struct sk_buff *skb) +{ +	int ret; + +	local_bh_disable(); +	ret = ofld_send(adap, skb); +	local_bh_enable(); +	return ret; +} + +/** + *	cxgb4_ofld_send - send an offload packet + *	@dev: the net device + *	@skb: the packet + * + *	Sends an offload packet.  This is an exported version of @t4_ofld_send, + *	intended for ULDs. + */ +int cxgb4_ofld_send(struct net_device *dev, struct sk_buff *skb) +{ +	return t4_ofld_send(netdev2adap(dev), skb); +} +EXPORT_SYMBOL(cxgb4_ofld_send); + +static inline void copy_frags(struct skb_shared_info *ssi, +			      const struct pkt_gl *gl, unsigned int offset) +{ +	unsigned int n; + +	/* usually there's just one frag */ +	ssi->frags[0].page = gl->frags[0].page; +	ssi->frags[0].page_offset = gl->frags[0].page_offset + offset; +	ssi->frags[0].size = gl->frags[0].size - offset; +	ssi->nr_frags = gl->nfrags; +	n = gl->nfrags - 1; +	if (n) +		memcpy(&ssi->frags[1], &gl->frags[1], n * sizeof(skb_frag_t)); + +	/* get a reference to the last page, we don't own it */ +	get_page(gl->frags[n].page); +} + +/** + *	cxgb4_pktgl_to_skb - build an sk_buff from a packet gather list + *	@gl: the gather list + *	@skb_len: size of sk_buff main body if it carries fragments + *	@pull_len: amount of data to move to the sk_buff's main body + * + *	Builds an sk_buff from the given packet gather list.  Returns the + *	sk_buff or %NULL if sk_buff allocation failed. + */ +struct sk_buff *cxgb4_pktgl_to_skb(const struct pkt_gl *gl, +				   unsigned int skb_len, unsigned int pull_len) +{ +	struct sk_buff *skb; + +	/* +	 * Below we rely on RX_COPY_THRES being less than the smallest Rx buffer +	 * size, which is expected since buffers are at least PAGE_SIZEd. +	 * In this case packets up to RX_COPY_THRES have only one fragment. +	 */ +	if (gl->tot_len <= RX_COPY_THRES) { +		skb = dev_alloc_skb(gl->tot_len); +		if (unlikely(!skb)) +			goto out; +		__skb_put(skb, gl->tot_len); +		skb_copy_to_linear_data(skb, gl->va, gl->tot_len); +	} else { +		skb = dev_alloc_skb(skb_len); +		if (unlikely(!skb)) +			goto out; +		__skb_put(skb, pull_len); +		skb_copy_to_linear_data(skb, gl->va, pull_len); + +		copy_frags(skb_shinfo(skb), gl, pull_len); +		skb->len = gl->tot_len; +		skb->data_len = skb->len - pull_len; +		skb->truesize += skb->data_len; +	} +out:	return skb; +} +EXPORT_SYMBOL(cxgb4_pktgl_to_skb); + +/** + *	t4_pktgl_free - free a packet gather list + *	@gl: the gather list + * + *	Releases the pages of a packet gather list.  We do not own the last + *	page on the list and do not free it. + */ +void t4_pktgl_free(const struct pkt_gl *gl) +{ +	int n; +	const skb_frag_t *p; + +	for (p = gl->frags, n = gl->nfrags - 1; n--; p++) +		put_page(p->page); +} + +/* + * Process an MPS trace packet.  Give it an unused protocol number so it won't + * be delivered to anyone and send it to the stack for capture. + */ +static noinline int handle_trace_pkt(struct adapter *adap, +				     const struct pkt_gl *gl) +{ +	struct sk_buff *skb; +	struct cpl_trace_pkt *p; + +	skb = cxgb4_pktgl_to_skb(gl, RX_PULL_LEN, RX_PULL_LEN); +	if (unlikely(!skb)) { +		t4_pktgl_free(gl); +		return 0; +	} + +	p = (struct cpl_trace_pkt *)skb->data; +	__skb_pull(skb, sizeof(*p)); +	skb_reset_mac_header(skb); +	skb->protocol = htons(0xffff); +	skb->dev = adap->port[0]; +	netif_receive_skb(skb); +	return 0; +} + +static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl, +		   const struct cpl_rx_pkt *pkt) +{ +	int ret; +	struct sk_buff *skb; + +	skb = napi_get_frags(&rxq->rspq.napi); +	if (unlikely(!skb)) { +		t4_pktgl_free(gl); +		rxq->stats.rx_drops++; +		return; +	} + +	copy_frags(skb_shinfo(skb), gl, RX_PKT_PAD); +	skb->len = gl->tot_len - RX_PKT_PAD; +	skb->data_len = skb->len; +	skb->truesize += skb->data_len; +	skb->ip_summed = CHECKSUM_UNNECESSARY; +	skb_record_rx_queue(skb, rxq->rspq.idx); + +	if (unlikely(pkt->vlan_ex)) { +		struct port_info *pi = netdev_priv(rxq->rspq.netdev); +		struct vlan_group *grp = pi->vlan_grp; + +		rxq->stats.vlan_ex++; +		if (likely(grp)) { +			ret = vlan_gro_frags(&rxq->rspq.napi, grp, +					     ntohs(pkt->vlan)); +			goto stats; +		} +	} +	ret = napi_gro_frags(&rxq->rspq.napi); +stats:	if (ret == GRO_HELD) +		rxq->stats.lro_pkts++; +	else if (ret == GRO_MERGED || ret == GRO_MERGED_FREE) +		rxq->stats.lro_merged++; +	rxq->stats.pkts++; +	rxq->stats.rx_cso++; +} + +/** + *	t4_ethrx_handler - process an ingress ethernet packet + *	@q: the response queue that received the packet + *	@rsp: the response queue descriptor holding the RX_PKT message + *	@si: the gather list of packet fragments + * + *	Process an ingress ethernet packet and deliver it to the stack. + */ +int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, +		     const struct pkt_gl *si) +{ +	bool csum_ok; +	struct sk_buff *skb; +	struct port_info *pi; +	const struct cpl_rx_pkt *pkt; +	struct sge_eth_rxq *rxq = container_of(q, struct sge_eth_rxq, rspq); + +	if (unlikely(*(u8 *)rsp == CPL_TRACE_PKT)) +		return handle_trace_pkt(q->adap, si); + +	pkt = (void *)&rsp[1]; +	csum_ok = pkt->csum_calc && !pkt->err_vec; +	if ((pkt->l2info & htonl(RXF_TCP)) && +	    (q->netdev->features & NETIF_F_GRO) && csum_ok && !pkt->ip_frag) { +		do_gro(rxq, si, pkt); +		return 0; +	} + +	skb = cxgb4_pktgl_to_skb(si, RX_PKT_SKB_LEN, RX_PULL_LEN); +	if (unlikely(!skb)) { +		t4_pktgl_free(si); +		rxq->stats.rx_drops++; +		return 0; +	} + +	__skb_pull(skb, RX_PKT_PAD);      /* remove ethernet header padding */ +	skb->protocol = eth_type_trans(skb, q->netdev); +	skb_record_rx_queue(skb, q->idx); +	pi = netdev_priv(skb->dev); +	rxq->stats.pkts++; + +	if (csum_ok && (pi->rx_offload & RX_CSO) && +	    (pkt->l2info & htonl(RXF_UDP | RXF_TCP))) { +		if (!pkt->ip_frag) +			skb->ip_summed = CHECKSUM_UNNECESSARY; +		else { +			__sum16 c = (__force __sum16)pkt->csum; +			skb->csum = csum_unfold(c); +			skb->ip_summed = CHECKSUM_COMPLETE; +		} +		rxq->stats.rx_cso++; +	} else +		skb->ip_summed = CHECKSUM_NONE; + +	if (unlikely(pkt->vlan_ex)) { +		struct vlan_group *grp = pi->vlan_grp; + +		rxq->stats.vlan_ex++; +		if (likely(grp)) +			vlan_hwaccel_receive_skb(skb, grp, ntohs(pkt->vlan)); +		else +			dev_kfree_skb_any(skb); +	} else +		netif_receive_skb(skb); + +	return 0; +} + +/** + *	restore_rx_bufs - put back a packet's Rx buffers + *	@si: the packet gather list + *	@q: the SGE free list + *	@frags: number of FL buffers to restore + * + *	Puts back on an FL the Rx buffers associated with @si.  The buffers + *	have already been unmapped and are left unmapped, we mark them so to + *	prevent further unmapping attempts. + * + *	This function undoes a series of @unmap_rx_buf calls when we find out + *	that the current packet can't be processed right away afterall and we + *	need to come back to it later.  This is a very rare event and there's + *	no effort to make this particularly efficient. + */ +static void restore_rx_bufs(const struct pkt_gl *si, struct sge_fl *q, +			    int frags) +{ +	struct rx_sw_desc *d; + +	while (frags--) { +		if (q->cidx == 0) +			q->cidx = q->size - 1; +		else +			q->cidx--; +		d = &q->sdesc[q->cidx]; +		d->page = si->frags[frags].page; +		d->dma_addr |= RX_UNMAPPED_BUF; +		q->avail++; +	} +} + +/** + *	is_new_response - check if a response is newly written + *	@r: the response descriptor + *	@q: the response queue + * + *	Returns true if a response descriptor contains a yet unprocessed + *	response. + */ +static inline bool is_new_response(const struct rsp_ctrl *r, +				   const struct sge_rspq *q) +{ +	return RSPD_GEN(r->type_gen) == q->gen; +} + +/** + *	rspq_next - advance to the next entry in a response queue + *	@q: the queue + * + *	Updates the state of a response queue to advance it to the next entry. + */ +static inline void rspq_next(struct sge_rspq *q) +{ +	q->cur_desc = (void *)q->cur_desc + q->iqe_len; +	if (unlikely(++q->cidx == q->size)) { +		q->cidx = 0; +		q->gen ^= 1; +		q->cur_desc = q->desc; +	} +} + +/** + *	process_responses - process responses from an SGE response queue + *	@q: the ingress queue to process + *	@budget: how many responses can be processed in this round + * + *	Process responses from an SGE response queue up to the supplied budget. + *	Responses include received packets as well as control messages from FW + *	or HW. + * + *	Additionally choose the interrupt holdoff time for the next interrupt + *	on this queue.  If the system is under memory shortage use a fairly + *	long delay to help recovery. + */ +static int process_responses(struct sge_rspq *q, int budget) +{ +	int ret, rsp_type; +	int budget_left = budget; +	const struct rsp_ctrl *rc; +	struct sge_eth_rxq *rxq = container_of(q, struct sge_eth_rxq, rspq); + +	while (likely(budget_left)) { +		rc = (void *)q->cur_desc + (q->iqe_len - sizeof(*rc)); +		if (!is_new_response(rc, q)) +			break; + +		rmb(); +		rsp_type = RSPD_TYPE(rc->type_gen); +		if (likely(rsp_type == RSP_TYPE_FLBUF)) { +			skb_frag_t *fp; +			struct pkt_gl si; +			const struct rx_sw_desc *rsd; +			u32 len = ntohl(rc->pldbuflen_qid), bufsz, frags; + +			if (len & RSPD_NEWBUF) { +				if (likely(q->offset > 0)) { +					free_rx_bufs(q->adap, &rxq->fl, 1); +					q->offset = 0; +				} +				len &= RSPD_LEN; +			} +			si.tot_len = len; + +			/* gather packet fragments */ +			for (frags = 0, fp = si.frags; ; frags++, fp++) { +				rsd = &rxq->fl.sdesc[rxq->fl.cidx]; +				bufsz = get_buf_size(rsd); +				fp->page = rsd->page; +				fp->page_offset = q->offset; +				fp->size = min(bufsz, len); +				len -= fp->size; +				if (!len) +					break; +				unmap_rx_buf(q->adap, &rxq->fl); +			} + +			/* +			 * Last buffer remains mapped so explicitly make it +			 * coherent for CPU access. +			 */ +			dma_sync_single_for_cpu(q->adap->pdev_dev, +						get_buf_addr(rsd), +						fp->size, DMA_FROM_DEVICE); + +			si.va = page_address(si.frags[0].page) + +				si.frags[0].page_offset; +			prefetch(si.va); + +			si.nfrags = frags + 1; +			ret = q->handler(q, q->cur_desc, &si); +			if (likely(ret == 0)) +				q->offset += ALIGN(fp->size, FL_ALIGN); +			else +				restore_rx_bufs(&si, &rxq->fl, frags); +		} else if (likely(rsp_type == RSP_TYPE_CPL)) { +			ret = q->handler(q, q->cur_desc, NULL); +		} else { +			ret = q->handler(q, (const __be64 *)rc, CXGB4_MSG_AN); +		} + +		if (unlikely(ret)) { +			/* couldn't process descriptor, back off for recovery */ +			q->next_intr_params = QINTR_TIMER_IDX(NOMEM_TMR_IDX); +			break; +		} + +		rspq_next(q); +		budget_left--; +	} + +	if (q->offset >= 0 && rxq->fl.size - rxq->fl.avail >= 16) +		__refill_fl(q->adap, &rxq->fl); +	return budget - budget_left; +} + +/** + *	napi_rx_handler - the NAPI handler for Rx processing + *	@napi: the napi instance + *	@budget: how many packets we can process in this round + * + *	Handler for new data events when using NAPI.  This does not need any + *	locking or protection from interrupts as data interrupts are off at + *	this point and other adapter interrupts do not interfere (the latter + *	in not a concern at all with MSI-X as non-data interrupts then have + *	a separate handler). + */ +static int napi_rx_handler(struct napi_struct *napi, int budget) +{ +	unsigned int params; +	struct sge_rspq *q = container_of(napi, struct sge_rspq, napi); +	int work_done = process_responses(q, budget); + +	if (likely(work_done < budget)) { +		napi_complete(napi); +		params = q->next_intr_params; +		q->next_intr_params = q->intr_params; +	} else +		params = QINTR_TIMER_IDX(7); + +	t4_write_reg(q->adap, MYPF_REG(SGE_PF_GTS), CIDXINC(work_done) | +		     INGRESSQID((u32)q->cntxt_id) | SEINTARM(params)); +	return work_done; +} + +/* + * The MSI-X interrupt handler for an SGE response queue. + */ +irqreturn_t t4_sge_intr_msix(int irq, void *cookie) +{ +	struct sge_rspq *q = cookie; + +	napi_schedule(&q->napi); +	return IRQ_HANDLED; +} + +/* + * Process the indirect interrupt entries in the interrupt queue and kick off + * NAPI for each queue that has generated an entry. + */ +static unsigned int process_intrq(struct adapter *adap) +{ +	unsigned int credits; +	const struct rsp_ctrl *rc; +	struct sge_rspq *q = &adap->sge.intrq; + +	spin_lock(&adap->sge.intrq_lock); +	for (credits = 0; ; credits++) { +		rc = (void *)q->cur_desc + (q->iqe_len - sizeof(*rc)); +		if (!is_new_response(rc, q)) +			break; + +		rmb(); +		if (RSPD_TYPE(rc->type_gen) == RSP_TYPE_INTR) { +			unsigned int qid = ntohl(rc->pldbuflen_qid); + +			napi_schedule(&adap->sge.ingr_map[qid]->napi); +		} + +		rspq_next(q); +	} + +	t4_write_reg(adap, MYPF_REG(SGE_PF_GTS), CIDXINC(credits) | +		     INGRESSQID(q->cntxt_id) | SEINTARM(q->intr_params)); +	spin_unlock(&adap->sge.intrq_lock); +	return credits; +} + +/* + * The MSI interrupt handler, which handles data events from SGE response queues + * as well as error and other async events as they all use the same MSI vector. + */ +static irqreturn_t t4_intr_msi(int irq, void *cookie) +{ +	struct adapter *adap = cookie; + +	t4_slow_intr_handler(adap); +	process_intrq(adap); +	return IRQ_HANDLED; +} + +/* + * Interrupt handler for legacy INTx interrupts. + * Handles data events from SGE response queues as well as error and other + * async events as they all use the same interrupt line. + */ +static irqreturn_t t4_intr_intx(int irq, void *cookie) +{ +	struct adapter *adap = cookie; + +	t4_write_reg(adap, MYPF_REG(PCIE_PF_CLI), 0); +	if (t4_slow_intr_handler(adap) | process_intrq(adap)) +		return IRQ_HANDLED; +	return IRQ_NONE;             /* probably shared interrupt */ +} + +/** + *	t4_intr_handler - select the top-level interrupt handler + *	@adap: the adapter + * + *	Selects the top-level interrupt handler based on the type of interrupts + *	(MSI-X, MSI, or INTx). + */ +irq_handler_t t4_intr_handler(struct adapter *adap) +{ +	if (adap->flags & USING_MSIX) +		return t4_sge_intr_msix; +	if (adap->flags & USING_MSI) +		return t4_intr_msi; +	return t4_intr_intx; +} + +static void sge_rx_timer_cb(unsigned long data) +{ +	unsigned long m; +	unsigned int i, cnt[2]; +	struct adapter *adap = (struct adapter *)data; +	struct sge *s = &adap->sge; + +	for (i = 0; i < ARRAY_SIZE(s->starving_fl); i++) +		for (m = s->starving_fl[i]; m; m &= m - 1) { +			struct sge_eth_rxq *rxq; +			unsigned int id = __ffs(m) + i * BITS_PER_LONG; +			struct sge_fl *fl = s->egr_map[id]; + +			clear_bit(id, s->starving_fl); +			smp_mb__after_clear_bit(); + +			if (fl_starving(fl)) { +				rxq = container_of(fl, struct sge_eth_rxq, fl); +				if (napi_reschedule(&rxq->rspq.napi)) +					fl->starving++; +				else +					set_bit(id, s->starving_fl); +			} +		} + +	t4_write_reg(adap, SGE_DEBUG_INDEX, 13); +	cnt[0] = t4_read_reg(adap, SGE_DEBUG_DATA_HIGH); +	cnt[1] = t4_read_reg(adap, SGE_DEBUG_DATA_LOW); + +	for (i = 0; i < 2; i++) +		if (cnt[i] >= s->starve_thres) { +			if (s->idma_state[i] || cnt[i] == 0xffffffff) +				continue; +			s->idma_state[i] = 1; +			t4_write_reg(adap, SGE_DEBUG_INDEX, 11); +			m = t4_read_reg(adap, SGE_DEBUG_DATA_LOW) >> (i * 16); +			dev_warn(adap->pdev_dev, +				 "SGE idma%u starvation detected for " +				 "queue %lu\n", i, m & 0xffff); +		} else if (s->idma_state[i]) +			s->idma_state[i] = 0; + +	mod_timer(&s->rx_timer, jiffies + RX_QCHECK_PERIOD); +} + +static void sge_tx_timer_cb(unsigned long data) +{ +	unsigned long m; +	unsigned int i, budget; +	struct adapter *adap = (struct adapter *)data; +	struct sge *s = &adap->sge; + +	for (i = 0; i < ARRAY_SIZE(s->txq_maperr); i++) +		for (m = s->txq_maperr[i]; m; m &= m - 1) { +			unsigned long id = __ffs(m) + i * BITS_PER_LONG; +			struct sge_ofld_txq *txq = s->egr_map[id]; + +			clear_bit(id, s->txq_maperr); +			tasklet_schedule(&txq->qresume_tsk); +		} + +	budget = MAX_TIMER_TX_RECLAIM; +	i = s->ethtxq_rover; +	do { +		struct sge_eth_txq *q = &s->ethtxq[i]; + +		if (q->q.in_use && +		    time_after_eq(jiffies, q->txq->trans_start + HZ / 100) && +		    __netif_tx_trylock(q->txq)) { +			int avail = reclaimable(&q->q); + +			if (avail) { +				if (avail > budget) +					avail = budget; + +				free_tx_desc(adap, &q->q, avail, true); +				q->q.in_use -= avail; +				budget -= avail; +			} +			__netif_tx_unlock(q->txq); +		} + +		if (++i >= s->ethqsets) +			i = 0; +	} while (budget && i != s->ethtxq_rover); +	s->ethtxq_rover = i; +	mod_timer(&s->tx_timer, jiffies + (budget ? TX_QCHECK_PERIOD : 2)); +} + +int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq, +		     struct net_device *dev, int intr_idx, +		     struct sge_fl *fl, rspq_handler_t hnd) +{ +	int ret, flsz = 0; +	struct fw_iq_cmd c; +	struct port_info *pi = netdev_priv(dev); + +	/* Size needs to be multiple of 16, including status entry. */ +	iq->size = roundup(iq->size, 16); + +	iq->desc = alloc_ring(adap->pdev_dev, iq->size, iq->iqe_len, 0, +			      &iq->phys_addr, NULL, 0); +	if (!iq->desc) +		return -ENOMEM; + +	memset(&c, 0, sizeof(c)); +	c.op_to_vfn = htonl(FW_CMD_OP(FW_IQ_CMD) | FW_CMD_REQUEST | +			    FW_CMD_WRITE | FW_CMD_EXEC | +			    FW_IQ_CMD_PFN(0) | FW_IQ_CMD_VFN(0)); +	c.alloc_to_len16 = htonl(FW_IQ_CMD_ALLOC | FW_IQ_CMD_IQSTART(1) | +				 FW_LEN16(c)); +	c.type_to_iqandstindex = htonl(FW_IQ_CMD_TYPE(FW_IQ_TYPE_FL_INT_CAP) | +		FW_IQ_CMD_IQASYNCH(fwevtq) | FW_IQ_CMD_VIID(pi->viid) | +		FW_IQ_CMD_IQANDST(intr_idx < 0) | FW_IQ_CMD_IQANUD(1) | +		FW_IQ_CMD_IQANDSTINDEX(intr_idx >= 0 ? intr_idx : +							-intr_idx - 1)); +	c.iqdroprss_to_iqesize = htons(FW_IQ_CMD_IQPCIECH(pi->tx_chan) | +		FW_IQ_CMD_IQGTSMODE | +		FW_IQ_CMD_IQINTCNTTHRESH(iq->pktcnt_idx) | +		FW_IQ_CMD_IQESIZE(ilog2(iq->iqe_len) - 4)); +	c.iqsize = htons(iq->size); +	c.iqaddr = cpu_to_be64(iq->phys_addr); + +	if (fl) { +		fl->size = roundup(fl->size, 8); +		fl->desc = alloc_ring(adap->pdev_dev, fl->size, sizeof(__be64), +				      sizeof(struct rx_sw_desc), &fl->addr, +				      &fl->sdesc, STAT_LEN); +		if (!fl->desc) +			goto fl_nomem; + +		flsz = fl->size / 8 + STAT_LEN / sizeof(struct tx_desc); +		c.iqns_to_fl0congen = htonl(FW_IQ_CMD_FL0PACKEN | +					    FW_IQ_CMD_FL0PADEN); +		c.fl0dcaen_to_fl0cidxfthresh = htons(FW_IQ_CMD_FL0FBMIN(2) | +				FW_IQ_CMD_FL0FBMAX(3)); +		c.fl0size = htons(flsz); +		c.fl0addr = cpu_to_be64(fl->addr); +	} + +	ret = t4_wr_mbox(adap, 0, &c, sizeof(c), &c); +	if (ret) +		goto err; + +	netif_napi_add(dev, &iq->napi, napi_rx_handler, 64); +	iq->cur_desc = iq->desc; +	iq->cidx = 0; +	iq->gen = 1; +	iq->next_intr_params = iq->intr_params; +	iq->cntxt_id = ntohs(c.iqid); +	iq->abs_id = ntohs(c.physiqid); +	iq->size--;                           /* subtract status entry */ +	iq->adap = adap; +	iq->netdev = dev; +	iq->handler = hnd; + +	/* set offset to -1 to distinguish ingress queues without FL */ +	iq->offset = fl ? 0 : -1; + +	adap->sge.ingr_map[iq->cntxt_id] = iq; + +	if (fl) { +		fl->cntxt_id = htons(c.fl0id); +		fl->avail = fl->pend_cred = 0; +		fl->pidx = fl->cidx = 0; +		fl->alloc_failed = fl->large_alloc_failed = fl->starving = 0; +		adap->sge.egr_map[fl->cntxt_id] = fl; +		refill_fl(adap, fl, fl_cap(fl), GFP_KERNEL); +	} +	return 0; + +fl_nomem: +	ret = -ENOMEM; +err: +	if (iq->desc) { +		dma_free_coherent(adap->pdev_dev, iq->size * iq->iqe_len, +				  iq->desc, iq->phys_addr); +		iq->desc = NULL; +	} +	if (fl && fl->desc) { +		kfree(fl->sdesc); +		fl->sdesc = NULL; +		dma_free_coherent(adap->pdev_dev, flsz * sizeof(struct tx_desc), +				  fl->desc, fl->addr); +		fl->desc = NULL; +	} +	return ret; +} + +static void init_txq(struct adapter *adap, struct sge_txq *q, unsigned int id) +{ +	q->in_use = 0; +	q->cidx = q->pidx = 0; +	q->stops = q->restarts = 0; +	q->stat = (void *)&q->desc[q->size]; +	q->cntxt_id = id; +	adap->sge.egr_map[id] = q; +} + +int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq, +			 struct net_device *dev, struct netdev_queue *netdevq, +			 unsigned int iqid) +{ +	int ret, nentries; +	struct fw_eq_eth_cmd c; +	struct port_info *pi = netdev_priv(dev); + +	/* Add status entries */ +	nentries = txq->q.size + STAT_LEN / sizeof(struct tx_desc); + +	txq->q.desc = alloc_ring(adap->pdev_dev, txq->q.size, +			sizeof(struct tx_desc), sizeof(struct tx_sw_desc), +			&txq->q.phys_addr, &txq->q.sdesc, STAT_LEN); +	if (!txq->q.desc) +		return -ENOMEM; + +	memset(&c, 0, sizeof(c)); +	c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_ETH_CMD) | FW_CMD_REQUEST | +			    FW_CMD_WRITE | FW_CMD_EXEC | +			    FW_EQ_ETH_CMD_PFN(0) | FW_EQ_ETH_CMD_VFN(0)); +	c.alloc_to_len16 = htonl(FW_EQ_ETH_CMD_ALLOC | +				 FW_EQ_ETH_CMD_EQSTART | FW_LEN16(c)); +	c.viid_pkd = htonl(FW_EQ_ETH_CMD_VIID(pi->viid)); +	c.fetchszm_to_iqid = htonl(FW_EQ_ETH_CMD_HOSTFCMODE(2) | +				   FW_EQ_ETH_CMD_PCIECHN(pi->tx_chan) | +				   FW_EQ_ETH_CMD_IQID(iqid)); +	c.dcaen_to_eqsize = htonl(FW_EQ_ETH_CMD_FBMIN(2) | +				  FW_EQ_ETH_CMD_FBMAX(3) | +				  FW_EQ_ETH_CMD_CIDXFTHRESH(5) | +				  FW_EQ_ETH_CMD_EQSIZE(nentries)); +	c.eqaddr = cpu_to_be64(txq->q.phys_addr); + +	ret = t4_wr_mbox(adap, 0, &c, sizeof(c), &c); +	if (ret) { +		kfree(txq->q.sdesc); +		txq->q.sdesc = NULL; +		dma_free_coherent(adap->pdev_dev, +				  nentries * sizeof(struct tx_desc), +				  txq->q.desc, txq->q.phys_addr); +		txq->q.desc = NULL; +		return ret; +	} + +	init_txq(adap, &txq->q, FW_EQ_ETH_CMD_EQID_GET(ntohl(c.eqid_pkd))); +	txq->txq = netdevq; +	txq->tso = txq->tx_cso = txq->vlan_ins = 0; +	txq->mapping_err = 0; +	return 0; +} + +int t4_sge_alloc_ctrl_txq(struct adapter *adap, struct sge_ctrl_txq *txq, +			  struct net_device *dev, unsigned int iqid, +			  unsigned int cmplqid) +{ +	int ret, nentries; +	struct fw_eq_ctrl_cmd c; +	struct port_info *pi = netdev_priv(dev); + +	/* Add status entries */ +	nentries = txq->q.size + STAT_LEN / sizeof(struct tx_desc); + +	txq->q.desc = alloc_ring(adap->pdev_dev, nentries, +				 sizeof(struct tx_desc), 0, &txq->q.phys_addr, +				 NULL, 0); +	if (!txq->q.desc) +		return -ENOMEM; + +	c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_CTRL_CMD) | FW_CMD_REQUEST | +			    FW_CMD_WRITE | FW_CMD_EXEC | +			    FW_EQ_CTRL_CMD_PFN(0) | FW_EQ_CTRL_CMD_VFN(0)); +	c.alloc_to_len16 = htonl(FW_EQ_CTRL_CMD_ALLOC | +				 FW_EQ_CTRL_CMD_EQSTART | FW_LEN16(c)); +	c.cmpliqid_eqid = htonl(FW_EQ_CTRL_CMD_CMPLIQID(cmplqid)); +	c.physeqid_pkd = htonl(0); +	c.fetchszm_to_iqid = htonl(FW_EQ_CTRL_CMD_HOSTFCMODE(2) | +				   FW_EQ_CTRL_CMD_PCIECHN(pi->tx_chan) | +				   FW_EQ_CTRL_CMD_IQID(iqid)); +	c.dcaen_to_eqsize = htonl(FW_EQ_CTRL_CMD_FBMIN(2) | +				  FW_EQ_CTRL_CMD_FBMAX(3) | +				  FW_EQ_CTRL_CMD_CIDXFTHRESH(5) | +				  FW_EQ_CTRL_CMD_EQSIZE(nentries)); +	c.eqaddr = cpu_to_be64(txq->q.phys_addr); + +	ret = t4_wr_mbox(adap, 0, &c, sizeof(c), &c); +	if (ret) { +		dma_free_coherent(adap->pdev_dev, +				  nentries * sizeof(struct tx_desc), +				  txq->q.desc, txq->q.phys_addr); +		txq->q.desc = NULL; +		return ret; +	} + +	init_txq(adap, &txq->q, FW_EQ_CTRL_CMD_EQID_GET(ntohl(c.cmpliqid_eqid))); +	txq->adap = adap; +	skb_queue_head_init(&txq->sendq); +	tasklet_init(&txq->qresume_tsk, restart_ctrlq, (unsigned long)txq); +	txq->full = 0; +	return 0; +} + +int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_ofld_txq *txq, +			  struct net_device *dev, unsigned int iqid) +{ +	int ret, nentries; +	struct fw_eq_ofld_cmd c; +	struct port_info *pi = netdev_priv(dev); + +	/* Add status entries */ +	nentries = txq->q.size + STAT_LEN / sizeof(struct tx_desc); + +	txq->q.desc = alloc_ring(adap->pdev_dev, txq->q.size, +			sizeof(struct tx_desc), sizeof(struct tx_sw_desc), +			&txq->q.phys_addr, &txq->q.sdesc, STAT_LEN); +	if (!txq->q.desc) +		return -ENOMEM; + +	memset(&c, 0, sizeof(c)); +	c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_OFLD_CMD) | FW_CMD_REQUEST | +			    FW_CMD_WRITE | FW_CMD_EXEC | +			    FW_EQ_OFLD_CMD_PFN(0) | FW_EQ_OFLD_CMD_VFN(0)); +	c.alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_ALLOC | +				 FW_EQ_OFLD_CMD_EQSTART | FW_LEN16(c)); +	c.fetchszm_to_iqid = htonl(FW_EQ_OFLD_CMD_HOSTFCMODE(2) | +				   FW_EQ_OFLD_CMD_PCIECHN(pi->tx_chan) | +				   FW_EQ_OFLD_CMD_IQID(iqid)); +	c.dcaen_to_eqsize = htonl(FW_EQ_OFLD_CMD_FBMIN(2) | +				  FW_EQ_OFLD_CMD_FBMAX(3) | +				  FW_EQ_OFLD_CMD_CIDXFTHRESH(5) | +				  FW_EQ_OFLD_CMD_EQSIZE(nentries)); +	c.eqaddr = cpu_to_be64(txq->q.phys_addr); + +	ret = t4_wr_mbox(adap, 0, &c, sizeof(c), &c); +	if (ret) { +		kfree(txq->q.sdesc); +		txq->q.sdesc = NULL; +		dma_free_coherent(adap->pdev_dev, +				  nentries * sizeof(struct tx_desc), +				  txq->q.desc, txq->q.phys_addr); +		txq->q.desc = NULL; +		return ret; +	} + +	init_txq(adap, &txq->q, FW_EQ_OFLD_CMD_EQID_GET(ntohl(c.eqid_pkd))); +	txq->adap = adap; +	skb_queue_head_init(&txq->sendq); +	tasklet_init(&txq->qresume_tsk, restart_ofldq, (unsigned long)txq); +	txq->full = 0; +	txq->mapping_err = 0; +	return 0; +} + +static void free_txq(struct adapter *adap, struct sge_txq *q) +{ +	dma_free_coherent(adap->pdev_dev, +			  q->size * sizeof(struct tx_desc) + STAT_LEN, +			  q->desc, q->phys_addr); +	q->cntxt_id = 0; +	q->sdesc = NULL; +	q->desc = NULL; +} + +static void free_rspq_fl(struct adapter *adap, struct sge_rspq *rq, +			 struct sge_fl *fl) +{ +	unsigned int fl_id = fl ? fl->cntxt_id : 0xffff; + +	adap->sge.ingr_map[rq->cntxt_id] = NULL; +	t4_iq_free(adap, 0, 0, 0, FW_IQ_TYPE_FL_INT_CAP, rq->cntxt_id, fl_id, +		   0xffff); +	dma_free_coherent(adap->pdev_dev, (rq->size + 1) * rq->iqe_len, +			  rq->desc, rq->phys_addr); +	netif_napi_del(&rq->napi); +	rq->netdev = NULL; +	rq->cntxt_id = rq->abs_id = 0; +	rq->desc = NULL; + +	if (fl) { +		free_rx_bufs(adap, fl, fl->avail); +		dma_free_coherent(adap->pdev_dev, fl->size * 8 + STAT_LEN, +				  fl->desc, fl->addr); +		kfree(fl->sdesc); +		fl->sdesc = NULL; +		fl->cntxt_id = 0; +		fl->desc = NULL; +	} +} + +/** + *	t4_free_sge_resources - free SGE resources + *	@adap: the adapter + * + *	Frees resources used by the SGE queue sets. + */ +void t4_free_sge_resources(struct adapter *adap) +{ +	int i; +	struct sge_eth_rxq *eq = adap->sge.ethrxq; +	struct sge_eth_txq *etq = adap->sge.ethtxq; +	struct sge_ofld_rxq *oq = adap->sge.ofldrxq; + +	/* clean up Ethernet Tx/Rx queues */ +	for (i = 0; i < adap->sge.ethqsets; i++, eq++, etq++) { +		if (eq->rspq.desc) +			free_rspq_fl(adap, &eq->rspq, &eq->fl); +		if (etq->q.desc) { +			t4_eth_eq_free(adap, 0, 0, 0, etq->q.cntxt_id); +			free_tx_desc(adap, &etq->q, etq->q.in_use, true); +			kfree(etq->q.sdesc); +			free_txq(adap, &etq->q); +		} +	} + +	/* clean up RDMA and iSCSI Rx queues */ +	for (i = 0; i < adap->sge.ofldqsets; i++, oq++) { +		if (oq->rspq.desc) +			free_rspq_fl(adap, &oq->rspq, &oq->fl); +	} +	for (i = 0, oq = adap->sge.rdmarxq; i < adap->sge.rdmaqs; i++, oq++) { +		if (oq->rspq.desc) +			free_rspq_fl(adap, &oq->rspq, &oq->fl); +	} + +	/* clean up offload Tx queues */ +	for (i = 0; i < ARRAY_SIZE(adap->sge.ofldtxq); i++) { +		struct sge_ofld_txq *q = &adap->sge.ofldtxq[i]; + +		if (q->q.desc) { +			tasklet_kill(&q->qresume_tsk); +			t4_ofld_eq_free(adap, 0, 0, 0, q->q.cntxt_id); +			free_tx_desc(adap, &q->q, q->q.in_use, false); +			kfree(q->q.sdesc); +			__skb_queue_purge(&q->sendq); +			free_txq(adap, &q->q); +		} +	} + +	/* clean up control Tx queues */ +	for (i = 0; i < ARRAY_SIZE(adap->sge.ctrlq); i++) { +		struct sge_ctrl_txq *cq = &adap->sge.ctrlq[i]; + +		if (cq->q.desc) { +			tasklet_kill(&cq->qresume_tsk); +			t4_ctrl_eq_free(adap, 0, 0, 0, cq->q.cntxt_id); +			__skb_queue_purge(&cq->sendq); +			free_txq(adap, &cq->q); +		} +	} + +	if (adap->sge.fw_evtq.desc) +		free_rspq_fl(adap, &adap->sge.fw_evtq, NULL); + +	if (adap->sge.intrq.desc) +		free_rspq_fl(adap, &adap->sge.intrq, NULL); + +	/* clear the reverse egress queue map */ +	memset(adap->sge.egr_map, 0, sizeof(adap->sge.egr_map)); +} + +void t4_sge_start(struct adapter *adap) +{ +	adap->sge.ethtxq_rover = 0; +	mod_timer(&adap->sge.rx_timer, jiffies + RX_QCHECK_PERIOD); +	mod_timer(&adap->sge.tx_timer, jiffies + TX_QCHECK_PERIOD); +} + +/** + *	t4_sge_stop - disable SGE operation + *	@adap: the adapter + * + *	Stop tasklets and timers associated with the DMA engine.  Note that + *	this is effective only if measures have been taken to disable any HW + *	events that may restart them. + */ +void t4_sge_stop(struct adapter *adap) +{ +	int i; +	struct sge *s = &adap->sge; + +	if (in_interrupt())  /* actions below require waiting */ +		return; + +	if (s->rx_timer.function) +		del_timer_sync(&s->rx_timer); +	if (s->tx_timer.function) +		del_timer_sync(&s->tx_timer); + +	for (i = 0; i < ARRAY_SIZE(s->ofldtxq); i++) { +		struct sge_ofld_txq *q = &s->ofldtxq[i]; + +		if (q->q.desc) +			tasklet_kill(&q->qresume_tsk); +	} +	for (i = 0; i < ARRAY_SIZE(s->ctrlq); i++) { +		struct sge_ctrl_txq *cq = &s->ctrlq[i]; + +		if (cq->q.desc) +			tasklet_kill(&cq->qresume_tsk); +	} +} + +/** + *	t4_sge_init - initialize SGE + *	@adap: the adapter + * + *	Performs SGE initialization needed every time after a chip reset. + *	We do not initialize any of the queues here, instead the driver + *	top-level must request them individually. + */ +void t4_sge_init(struct adapter *adap) +{ +	struct sge *s = &adap->sge; +	unsigned int fl_align_log = ilog2(FL_ALIGN); + +	t4_set_reg_field(adap, SGE_CONTROL, PKTSHIFT_MASK | +			 INGPADBOUNDARY_MASK | EGRSTATUSPAGESIZE, +			 INGPADBOUNDARY(fl_align_log - 5) | PKTSHIFT(2) | +			 RXPKTCPLMODE | +			 (STAT_LEN == 128 ? EGRSTATUSPAGESIZE : 0)); +	t4_set_reg_field(adap, SGE_HOST_PAGE_SIZE, HOSTPAGESIZEPF0_MASK, +			 HOSTPAGESIZEPF0(PAGE_SHIFT - 10)); +	t4_write_reg(adap, SGE_FL_BUFFER_SIZE0, PAGE_SIZE); +#if FL_PG_ORDER > 0 +	t4_write_reg(adap, SGE_FL_BUFFER_SIZE1, PAGE_SIZE << FL_PG_ORDER); +#endif +	t4_write_reg(adap, SGE_INGRESS_RX_THRESHOLD, +		     THRESHOLD_0(s->counter_val[0]) | +		     THRESHOLD_1(s->counter_val[1]) | +		     THRESHOLD_2(s->counter_val[2]) | +		     THRESHOLD_3(s->counter_val[3])); +	t4_write_reg(adap, SGE_TIMER_VALUE_0_AND_1, +		     TIMERVALUE0(us_to_core_ticks(adap, s->timer_val[0])) | +		     TIMERVALUE1(us_to_core_ticks(adap, s->timer_val[1]))); +	t4_write_reg(adap, SGE_TIMER_VALUE_2_AND_3, +		     TIMERVALUE0(us_to_core_ticks(adap, s->timer_val[2])) | +		     TIMERVALUE1(us_to_core_ticks(adap, s->timer_val[3]))); +	t4_write_reg(adap, SGE_TIMER_VALUE_4_AND_5, +		     TIMERVALUE0(us_to_core_ticks(adap, s->timer_val[4])) | +		     TIMERVALUE1(us_to_core_ticks(adap, s->timer_val[5]))); +	setup_timer(&s->rx_timer, sge_rx_timer_cb, (unsigned long)adap); +	setup_timer(&s->tx_timer, sge_tx_timer_cb, (unsigned long)adap); +	s->starve_thres = core_ticks_per_usec(adap) * 1000000;  /* 1 s */ +	s->idma_state[0] = s->idma_state[1] = 0; +	spin_lock_init(&s->intrq_lock); +} diff --git a/drivers/net/cxgb4/t4_hw.c b/drivers/net/cxgb4/t4_hw.c new file mode 100644 index 00000000000..a814a3afe12 --- /dev/null +++ b/drivers/net/cxgb4/t4_hw.c @@ -0,0 +1,3131 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses.  You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + *     Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *      - Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + * + *      - Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/init.h> +#include <linux/delay.h> +#include "cxgb4.h" +#include "t4_regs.h" +#include "t4fw_api.h" + +/** + *	t4_wait_op_done_val - wait until an operation is completed + *	@adapter: the adapter performing the operation + *	@reg: the register to check for completion + *	@mask: a single-bit field within @reg that indicates completion + *	@polarity: the value of the field when the operation is completed + *	@attempts: number of check iterations + *	@delay: delay in usecs between iterations + *	@valp: where to store the value of the register at completion time + * + *	Wait until an operation is completed by checking a bit in a register + *	up to @attempts times.  If @valp is not NULL the value of the register + *	at the time it indicated completion is stored there.  Returns 0 if the + *	operation completes and	-EAGAIN	otherwise. + */ +int t4_wait_op_done_val(struct adapter *adapter, int reg, u32 mask, +			int polarity, int attempts, int delay, u32 *valp) +{ +	while (1) { +		u32 val = t4_read_reg(adapter, reg); + +		if (!!(val & mask) == polarity) { +			if (valp) +				*valp = val; +			return 0; +		} +		if (--attempts == 0) +			return -EAGAIN; +		if (delay) +			udelay(delay); +	} +} + +static inline int t4_wait_op_done(struct adapter *adapter, int reg, u32 mask, +				  int polarity, int attempts, int delay) +{ +	return t4_wait_op_done_val(adapter, reg, mask, polarity, attempts, +				   delay, NULL); +} + +/** + *	t4_set_reg_field - set a register field to a value + *	@adapter: the adapter to program + *	@addr: the register address + *	@mask: specifies the portion of the register to modify + *	@val: the new value for the register field + * + *	Sets a register field specified by the supplied mask to the + *	given value. + */ +void t4_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask, +		      u32 val) +{ +	u32 v = t4_read_reg(adapter, addr) & ~mask; + +	t4_write_reg(adapter, addr, v | val); +	(void) t4_read_reg(adapter, addr);      /* flush */ +} + +/** + *	t4_read_indirect - read indirectly addressed registers + *	@adap: the adapter + *	@addr_reg: register holding the indirect address + *	@data_reg: register holding the value of the indirect register + *	@vals: where the read register values are stored + *	@nregs: how many indirect registers to read + *	@start_idx: index of first indirect register to read + * + *	Reads registers that are accessed indirectly through an address/data + *	register pair. + */ +void t4_read_indirect(struct adapter *adap, unsigned int addr_reg, +		      unsigned int data_reg, u32 *vals, unsigned int nregs, +		      unsigned int start_idx) +{ +	while (nregs--) { +		t4_write_reg(adap, addr_reg, start_idx); +		*vals++ = t4_read_reg(adap, data_reg); +		start_idx++; +	} +} + +/** + *	t4_write_indirect - write indirectly addressed registers + *	@adap: the adapter + *	@addr_reg: register holding the indirect addresses + *	@data_reg: register holding the value for the indirect registers + *	@vals: values to write + *	@nregs: how many indirect registers to write + *	@start_idx: address of first indirect register to write + * + *	Writes a sequential block of registers that are accessed indirectly + *	through an address/data register pair. + */ +void t4_write_indirect(struct adapter *adap, unsigned int addr_reg, +		       unsigned int data_reg, const u32 *vals, +		       unsigned int nregs, unsigned int start_idx) +{ +	while (nregs--) { +		t4_write_reg(adap, addr_reg, start_idx++); +		t4_write_reg(adap, data_reg, *vals++); +	} +} + +/* + * Get the reply to a mailbox command and store it in @rpl in big-endian order. + */ +static void get_mbox_rpl(struct adapter *adap, __be64 *rpl, int nflit, +			 u32 mbox_addr) +{ +	for ( ; nflit; nflit--, mbox_addr += 8) +		*rpl++ = cpu_to_be64(t4_read_reg64(adap, mbox_addr)); +} + +/* + * Handle a FW assertion reported in a mailbox. + */ +static void fw_asrt(struct adapter *adap, u32 mbox_addr) +{ +	struct fw_debug_cmd asrt; + +	get_mbox_rpl(adap, (__be64 *)&asrt, sizeof(asrt) / 8, mbox_addr); +	dev_alert(adap->pdev_dev, +		  "FW assertion at %.16s:%u, val0 %#x, val1 %#x\n", +		  asrt.u.assert.filename_0_7, ntohl(asrt.u.assert.line), +		  ntohl(asrt.u.assert.x), ntohl(asrt.u.assert.y)); +} + +static void dump_mbox(struct adapter *adap, int mbox, u32 data_reg) +{ +	dev_err(adap->pdev_dev, +		"mbox %d: %llx %llx %llx %llx %llx %llx %llx %llx\n", mbox, +		(unsigned long long)t4_read_reg64(adap, data_reg), +		(unsigned long long)t4_read_reg64(adap, data_reg + 8), +		(unsigned long long)t4_read_reg64(adap, data_reg + 16), +		(unsigned long long)t4_read_reg64(adap, data_reg + 24), +		(unsigned long long)t4_read_reg64(adap, data_reg + 32), +		(unsigned long long)t4_read_reg64(adap, data_reg + 40), +		(unsigned long long)t4_read_reg64(adap, data_reg + 48), +		(unsigned long long)t4_read_reg64(adap, data_reg + 56)); +} + +/** + *	t4_wr_mbox_meat - send a command to FW through the given mailbox + *	@adap: the adapter + *	@mbox: index of the mailbox to use + *	@cmd: the command to write + *	@size: command length in bytes + *	@rpl: where to optionally store the reply + *	@sleep_ok: if true we may sleep while awaiting command completion + * + *	Sends the given command to FW through the selected mailbox and waits + *	for the FW to execute the command.  If @rpl is not %NULL it is used to + *	store the FW's reply to the command.  The command and its optional + *	reply are of the same length.  FW can take up to %FW_CMD_MAX_TIMEOUT ms + *	to respond.  @sleep_ok determines whether we may sleep while awaiting + *	the response.  If sleeping is allowed we use progressive backoff + *	otherwise we spin. + * + *	The return value is 0 on success or a negative errno on failure.  A + *	failure can happen either because we are not able to execute the + *	command or FW executes it but signals an error.  In the latter case + *	the return value is the error code indicated by FW (negated). + */ +int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size, +		    void *rpl, bool sleep_ok) +{ +	static int delay[] = { +		1, 1, 3, 5, 10, 10, 20, 50, 100, 200 +	}; + +	u32 v; +	u64 res; +	int i, ms, delay_idx; +	const __be64 *p = cmd; +	u32 data_reg = PF_REG(mbox, CIM_PF_MAILBOX_DATA); +	u32 ctl_reg = PF_REG(mbox, CIM_PF_MAILBOX_CTRL); + +	if ((size & 15) || size > MBOX_LEN) +		return -EINVAL; + +	v = MBOWNER_GET(t4_read_reg(adap, ctl_reg)); +	for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++) +		v = MBOWNER_GET(t4_read_reg(adap, ctl_reg)); + +	if (v != MBOX_OWNER_DRV) +		return v ? -EBUSY : -ETIMEDOUT; + +	for (i = 0; i < size; i += 8) +		t4_write_reg64(adap, data_reg + i, be64_to_cpu(*p++)); + +	t4_write_reg(adap, ctl_reg, MBMSGVALID | MBOWNER(MBOX_OWNER_FW)); +	t4_read_reg(adap, ctl_reg);          /* flush write */ + +	delay_idx = 0; +	ms = delay[0]; + +	for (i = 0; i < FW_CMD_MAX_TIMEOUT; i += ms) { +		if (sleep_ok) { +			ms = delay[delay_idx];  /* last element may repeat */ +			if (delay_idx < ARRAY_SIZE(delay) - 1) +				delay_idx++; +			msleep(ms); +		} else +			mdelay(ms); + +		v = t4_read_reg(adap, ctl_reg); +		if (MBOWNER_GET(v) == MBOX_OWNER_DRV) { +			if (!(v & MBMSGVALID)) { +				t4_write_reg(adap, ctl_reg, 0); +				continue; +			} + +			res = t4_read_reg64(adap, data_reg); +			if (FW_CMD_OP_GET(res >> 32) == FW_DEBUG_CMD) { +				fw_asrt(adap, data_reg); +				res = FW_CMD_RETVAL(EIO); +			} else if (rpl) +				get_mbox_rpl(adap, rpl, size / 8, data_reg); + +			if (FW_CMD_RETVAL_GET((int)res)) +				dump_mbox(adap, mbox, data_reg); +			t4_write_reg(adap, ctl_reg, 0); +			return -FW_CMD_RETVAL_GET((int)res); +		} +	} + +	dump_mbox(adap, mbox, data_reg); +	dev_err(adap->pdev_dev, "command %#x in mailbox %d timed out\n", +		*(const u8 *)cmd, mbox); +	return -ETIMEDOUT; +} + +/** + *	t4_mc_read - read from MC through backdoor accesses + *	@adap: the adapter + *	@addr: address of first byte requested + *	@data: 64 bytes of data containing the requested address + *	@ecc: where to store the corresponding 64-bit ECC word + * + *	Read 64 bytes of data from MC starting at a 64-byte-aligned address + *	that covers the requested address @addr.  If @parity is not %NULL it + *	is assigned the 64-bit ECC word for the read data. + */ +int t4_mc_read(struct adapter *adap, u32 addr, __be32 *data, u64 *ecc) +{ +	int i; + +	if (t4_read_reg(adap, MC_BIST_CMD) & START_BIST) +		return -EBUSY; +	t4_write_reg(adap, MC_BIST_CMD_ADDR, addr & ~0x3fU); +	t4_write_reg(adap, MC_BIST_CMD_LEN, 64); +	t4_write_reg(adap, MC_BIST_DATA_PATTERN, 0xc); +	t4_write_reg(adap, MC_BIST_CMD, BIST_OPCODE(1) | START_BIST | +		     BIST_CMD_GAP(1)); +	i = t4_wait_op_done(adap, MC_BIST_CMD, START_BIST, 0, 10, 1); +	if (i) +		return i; + +#define MC_DATA(i) MC_BIST_STATUS_REG(MC_BIST_STATUS_RDATA, i) + +	for (i = 15; i >= 0; i--) +		*data++ = htonl(t4_read_reg(adap, MC_DATA(i))); +	if (ecc) +		*ecc = t4_read_reg64(adap, MC_DATA(16)); +#undef MC_DATA +	return 0; +} + +/** + *	t4_edc_read - read from EDC through backdoor accesses + *	@adap: the adapter + *	@idx: which EDC to access + *	@addr: address of first byte requested + *	@data: 64 bytes of data containing the requested address + *	@ecc: where to store the corresponding 64-bit ECC word + * + *	Read 64 bytes of data from EDC starting at a 64-byte-aligned address + *	that covers the requested address @addr.  If @parity is not %NULL it + *	is assigned the 64-bit ECC word for the read data. + */ +int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc) +{ +	int i; + +	idx *= EDC_STRIDE; +	if (t4_read_reg(adap, EDC_BIST_CMD + idx) & START_BIST) +		return -EBUSY; +	t4_write_reg(adap, EDC_BIST_CMD_ADDR + idx, addr & ~0x3fU); +	t4_write_reg(adap, EDC_BIST_CMD_LEN + idx, 64); +	t4_write_reg(adap, EDC_BIST_DATA_PATTERN + idx, 0xc); +	t4_write_reg(adap, EDC_BIST_CMD + idx, +		     BIST_OPCODE(1) | BIST_CMD_GAP(1) | START_BIST); +	i = t4_wait_op_done(adap, EDC_BIST_CMD + idx, START_BIST, 0, 10, 1); +	if (i) +		return i; + +#define EDC_DATA(i) (EDC_BIST_STATUS_REG(EDC_BIST_STATUS_RDATA, i) + idx) + +	for (i = 15; i >= 0; i--) +		*data++ = htonl(t4_read_reg(adap, EDC_DATA(i))); +	if (ecc) +		*ecc = t4_read_reg64(adap, EDC_DATA(16)); +#undef EDC_DATA +	return 0; +} + +#define VPD_ENTRY(name, len) \ +	u8 name##_kword[2]; u8 name##_len; u8 name##_data[len] + +/* + * Partial EEPROM Vital Product Data structure.  Includes only the ID and + * VPD-R sections. + */ +struct t4_vpd { +	u8  id_tag; +	u8  id_len[2]; +	u8  id_data[ID_LEN]; +	u8  vpdr_tag; +	u8  vpdr_len[2]; +	VPD_ENTRY(pn, 16);                     /* part number */ +	VPD_ENTRY(ec, EC_LEN);                 /* EC level */ +	VPD_ENTRY(sn, SERNUM_LEN);             /* serial number */ +	VPD_ENTRY(na, 12);                     /* MAC address base */ +	VPD_ENTRY(port_type, 8);               /* port types */ +	VPD_ENTRY(gpio, 14);                   /* GPIO usage */ +	VPD_ENTRY(cclk, 6);                    /* core clock */ +	VPD_ENTRY(port_addr, 8);               /* port MDIO addresses */ +	VPD_ENTRY(rv, 1);                      /* csum */ +	u32 pad;                  /* for multiple-of-4 sizing and alignment */ +}; + +#define EEPROM_STAT_ADDR   0x7bfc +#define VPD_BASE           0 + +/** + *	t4_seeprom_wp - enable/disable EEPROM write protection + *	@adapter: the adapter + *	@enable: whether to enable or disable write protection + * + *	Enables or disables write protection on the serial EEPROM. + */ +int t4_seeprom_wp(struct adapter *adapter, bool enable) +{ +	unsigned int v = enable ? 0xc : 0; +	int ret = pci_write_vpd(adapter->pdev, EEPROM_STAT_ADDR, 4, &v); +	return ret < 0 ? ret : 0; +} + +/** + *	get_vpd_params - read VPD parameters from VPD EEPROM + *	@adapter: adapter to read + *	@p: where to store the parameters + * + *	Reads card parameters stored in VPD EEPROM. + */ +static int get_vpd_params(struct adapter *adapter, struct vpd_params *p) +{ +	int ret; +	struct t4_vpd vpd; +	u8 *q = (u8 *)&vpd, csum; + +	ret = pci_read_vpd(adapter->pdev, VPD_BASE, sizeof(vpd), &vpd); +	if (ret < 0) +		return ret; + +	for (csum = 0; q <= vpd.rv_data; q++) +		csum += *q; + +	if (csum) { +		dev_err(adapter->pdev_dev, +			"corrupted VPD EEPROM, actual csum %u\n", csum); +		return -EINVAL; +	} + +	p->cclk = simple_strtoul(vpd.cclk_data, NULL, 10); +	memcpy(p->id, vpd.id_data, sizeof(vpd.id_data)); +	strim(p->id); +	memcpy(p->ec, vpd.ec_data, sizeof(vpd.ec_data)); +	strim(p->ec); +	memcpy(p->sn, vpd.sn_data, sizeof(vpd.sn_data)); +	strim(p->sn); +	return 0; +} + +/* serial flash and firmware constants */ +enum { +	SF_ATTEMPTS = 10,             /* max retries for SF operations */ + +	/* flash command opcodes */ +	SF_PROG_PAGE    = 2,          /* program page */ +	SF_WR_DISABLE   = 4,          /* disable writes */ +	SF_RD_STATUS    = 5,          /* read status register */ +	SF_WR_ENABLE    = 6,          /* enable writes */ +	SF_RD_DATA_FAST = 0xb,        /* read flash */ +	SF_ERASE_SECTOR = 0xd8,       /* erase sector */ + +	FW_START_SEC = 8,             /* first flash sector for FW */ +	FW_END_SEC = 15,              /* last flash sector for FW */ +	FW_IMG_START = FW_START_SEC * SF_SEC_SIZE, +	FW_MAX_SIZE = (FW_END_SEC - FW_START_SEC + 1) * SF_SEC_SIZE, +}; + +/** + *	sf1_read - read data from the serial flash + *	@adapter: the adapter + *	@byte_cnt: number of bytes to read + *	@cont: whether another operation will be chained + *	@lock: whether to lock SF for PL access only + *	@valp: where to store the read data + * + *	Reads up to 4 bytes of data from the serial flash.  The location of + *	the read needs to be specified prior to calling this by issuing the + *	appropriate commands to the serial flash. + */ +static int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont, +		    int lock, u32 *valp) +{ +	int ret; + +	if (!byte_cnt || byte_cnt > 4) +		return -EINVAL; +	if (t4_read_reg(adapter, SF_OP) & BUSY) +		return -EBUSY; +	cont = cont ? SF_CONT : 0; +	lock = lock ? SF_LOCK : 0; +	t4_write_reg(adapter, SF_OP, lock | cont | BYTECNT(byte_cnt - 1)); +	ret = t4_wait_op_done(adapter, SF_OP, BUSY, 0, SF_ATTEMPTS, 5); +	if (!ret) +		*valp = t4_read_reg(adapter, SF_DATA); +	return ret; +} + +/** + *	sf1_write - write data to the serial flash + *	@adapter: the adapter + *	@byte_cnt: number of bytes to write + *	@cont: whether another operation will be chained + *	@lock: whether to lock SF for PL access only + *	@val: value to write + * + *	Writes up to 4 bytes of data to the serial flash.  The location of + *	the write needs to be specified prior to calling this by issuing the + *	appropriate commands to the serial flash. + */ +static int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont, +		     int lock, u32 val) +{ +	if (!byte_cnt || byte_cnt > 4) +		return -EINVAL; +	if (t4_read_reg(adapter, SF_OP) & BUSY) +		return -EBUSY; +	cont = cont ? SF_CONT : 0; +	lock = lock ? SF_LOCK : 0; +	t4_write_reg(adapter, SF_DATA, val); +	t4_write_reg(adapter, SF_OP, lock | +		     cont | BYTECNT(byte_cnt - 1) | OP_WR); +	return t4_wait_op_done(adapter, SF_OP, BUSY, 0, SF_ATTEMPTS, 5); +} + +/** + *	flash_wait_op - wait for a flash operation to complete + *	@adapter: the adapter + *	@attempts: max number of polls of the status register + *	@delay: delay between polls in ms + * + *	Wait for a flash operation to complete by polling the status register. + */ +static int flash_wait_op(struct adapter *adapter, int attempts, int delay) +{ +	int ret; +	u32 status; + +	while (1) { +		if ((ret = sf1_write(adapter, 1, 1, 1, SF_RD_STATUS)) != 0 || +		    (ret = sf1_read(adapter, 1, 0, 1, &status)) != 0) +			return ret; +		if (!(status & 1)) +			return 0; +		if (--attempts == 0) +			return -EAGAIN; +		if (delay) +			msleep(delay); +	} +} + +/** + *	t4_read_flash - read words from serial flash + *	@adapter: the adapter + *	@addr: the start address for the read + *	@nwords: how many 32-bit words to read + *	@data: where to store the read data + *	@byte_oriented: whether to store data as bytes or as words + * + *	Read the specified number of 32-bit words from the serial flash. + *	If @byte_oriented is set the read data is stored as a byte array + *	(i.e., big-endian), otherwise as 32-bit words in the platform's + *	natural endianess. + */ +int t4_read_flash(struct adapter *adapter, unsigned int addr, +		  unsigned int nwords, u32 *data, int byte_oriented) +{ +	int ret; + +	if (addr + nwords * sizeof(u32) > SF_SIZE || (addr & 3)) +		return -EINVAL; + +	addr = swab32(addr) | SF_RD_DATA_FAST; + +	if ((ret = sf1_write(adapter, 4, 1, 0, addr)) != 0 || +	    (ret = sf1_read(adapter, 1, 1, 0, data)) != 0) +		return ret; + +	for ( ; nwords; nwords--, data++) { +		ret = sf1_read(adapter, 4, nwords > 1, nwords == 1, data); +		if (nwords == 1) +			t4_write_reg(adapter, SF_OP, 0);    /* unlock SF */ +		if (ret) +			return ret; +		if (byte_oriented) +			*data = htonl(*data); +	} +	return 0; +} + +/** + *	t4_write_flash - write up to a page of data to the serial flash + *	@adapter: the adapter + *	@addr: the start address to write + *	@n: length of data to write in bytes + *	@data: the data to write + * + *	Writes up to a page of data (256 bytes) to the serial flash starting + *	at the given address.  All the data must be written to the same page. + */ +static int t4_write_flash(struct adapter *adapter, unsigned int addr, +			  unsigned int n, const u8 *data) +{ +	int ret; +	u32 buf[64]; +	unsigned int i, c, left, val, offset = addr & 0xff; + +	if (addr >= SF_SIZE || offset + n > SF_PAGE_SIZE) +		return -EINVAL; + +	val = swab32(addr) | SF_PROG_PAGE; + +	if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 || +	    (ret = sf1_write(adapter, 4, 1, 1, val)) != 0) +		goto unlock; + +	for (left = n; left; left -= c) { +		c = min(left, 4U); +		for (val = 0, i = 0; i < c; ++i) +			val = (val << 8) + *data++; + +		ret = sf1_write(adapter, c, c != left, 1, val); +		if (ret) +			goto unlock; +	} +	ret = flash_wait_op(adapter, 5, 1); +	if (ret) +		goto unlock; + +	t4_write_reg(adapter, SF_OP, 0);    /* unlock SF */ + +	/* Read the page to verify the write succeeded */ +	ret = t4_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 1); +	if (ret) +		return ret; + +	if (memcmp(data - n, (u8 *)buf + offset, n)) { +		dev_err(adapter->pdev_dev, +			"failed to correctly write the flash page at %#x\n", +			addr); +		return -EIO; +	} +	return 0; + +unlock: +	t4_write_reg(adapter, SF_OP, 0);    /* unlock SF */ +	return ret; +} + +/** + *	get_fw_version - read the firmware version + *	@adapter: the adapter + *	@vers: where to place the version + * + *	Reads the FW version from flash. + */ +static int get_fw_version(struct adapter *adapter, u32 *vers) +{ +	return t4_read_flash(adapter, +			     FW_IMG_START + offsetof(struct fw_hdr, fw_ver), 1, +			     vers, 0); +} + +/** + *	get_tp_version - read the TP microcode version + *	@adapter: the adapter + *	@vers: where to place the version + * + *	Reads the TP microcode version from flash. + */ +static int get_tp_version(struct adapter *adapter, u32 *vers) +{ +	return t4_read_flash(adapter, FW_IMG_START + offsetof(struct fw_hdr, +							      tp_microcode_ver), +			     1, vers, 0); +} + +/** + *	t4_check_fw_version - check if the FW is compatible with this driver + *	@adapter: the adapter + * + *	Checks if an adapter's FW is compatible with the driver.  Returns 0 + *	if there's exact match, a negative error if the version could not be + *	read or there's a major version mismatch, and a positive value if the + *	expected major version is found but there's a minor version mismatch. + */ +int t4_check_fw_version(struct adapter *adapter) +{ +	u32 api_vers[2]; +	int ret, major, minor, micro; + +	ret = get_fw_version(adapter, &adapter->params.fw_vers); +	if (!ret) +		ret = get_tp_version(adapter, &adapter->params.tp_vers); +	if (!ret) +		ret = t4_read_flash(adapter, +			FW_IMG_START + offsetof(struct fw_hdr, intfver_nic), +			2, api_vers, 1); +	if (ret) +		return ret; + +	major = FW_HDR_FW_VER_MAJOR_GET(adapter->params.fw_vers); +	minor = FW_HDR_FW_VER_MINOR_GET(adapter->params.fw_vers); +	micro = FW_HDR_FW_VER_MICRO_GET(adapter->params.fw_vers); +	memcpy(adapter->params.api_vers, api_vers, +	       sizeof(adapter->params.api_vers)); + +	if (major != FW_VERSION_MAJOR) {            /* major mismatch - fail */ +		dev_err(adapter->pdev_dev, +			"card FW has major version %u, driver wants %u\n", +			major, FW_VERSION_MAJOR); +		return -EINVAL; +	} + +	if (minor == FW_VERSION_MINOR && micro == FW_VERSION_MICRO) +		return 0;                                   /* perfect match */ + +	/* Minor/micro version mismatch.  Report it but often it's OK. */ +	return 1; +} + +/** + *	t4_flash_erase_sectors - erase a range of flash sectors + *	@adapter: the adapter + *	@start: the first sector to erase + *	@end: the last sector to erase + * + *	Erases the sectors in the given inclusive range. + */ +static int t4_flash_erase_sectors(struct adapter *adapter, int start, int end) +{ +	int ret = 0; + +	while (start <= end) { +		if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 || +		    (ret = sf1_write(adapter, 4, 0, 1, +				     SF_ERASE_SECTOR | (start << 8))) != 0 || +		    (ret = flash_wait_op(adapter, 5, 500)) != 0) { +			dev_err(adapter->pdev_dev, +				"erase of flash sector %d failed, error %d\n", +				start, ret); +			break; +		} +		start++; +	} +	t4_write_reg(adapter, SF_OP, 0);    /* unlock SF */ +	return ret; +} + +/** + *	t4_load_fw - download firmware + *	@adap: the adapter + *	@fw_data: the firmware image to write + *	@size: image size + * + *	Write the supplied firmware image to the card's serial flash. + */ +int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size) +{ +	u32 csum; +	int ret, addr; +	unsigned int i; +	u8 first_page[SF_PAGE_SIZE]; +	const u32 *p = (const u32 *)fw_data; +	const struct fw_hdr *hdr = (const struct fw_hdr *)fw_data; + +	if (!size) { +		dev_err(adap->pdev_dev, "FW image has no data\n"); +		return -EINVAL; +	} +	if (size & 511) { +		dev_err(adap->pdev_dev, +			"FW image size not multiple of 512 bytes\n"); +		return -EINVAL; +	} +	if (ntohs(hdr->len512) * 512 != size) { +		dev_err(adap->pdev_dev, +			"FW image size differs from size in FW header\n"); +		return -EINVAL; +	} +	if (size > FW_MAX_SIZE) { +		dev_err(adap->pdev_dev, "FW image too large, max is %u bytes\n", +			FW_MAX_SIZE); +		return -EFBIG; +	} + +	for (csum = 0, i = 0; i < size / sizeof(csum); i++) +		csum += ntohl(p[i]); + +	if (csum != 0xffffffff) { +		dev_err(adap->pdev_dev, +			"corrupted firmware image, checksum %#x\n", csum); +		return -EINVAL; +	} + +	i = DIV_ROUND_UP(size, SF_SEC_SIZE);        /* # of sectors spanned */ +	ret = t4_flash_erase_sectors(adap, FW_START_SEC, FW_START_SEC + i - 1); +	if (ret) +		goto out; + +	/* +	 * We write the correct version at the end so the driver can see a bad +	 * version if the FW write fails.  Start by writing a copy of the +	 * first page with a bad version. +	 */ +	memcpy(first_page, fw_data, SF_PAGE_SIZE); +	((struct fw_hdr *)first_page)->fw_ver = htonl(0xffffffff); +	ret = t4_write_flash(adap, FW_IMG_START, SF_PAGE_SIZE, first_page); +	if (ret) +		goto out; + +	addr = FW_IMG_START; +	for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) { +		addr += SF_PAGE_SIZE; +		fw_data += SF_PAGE_SIZE; +		ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, fw_data); +		if (ret) +			goto out; +	} + +	ret = t4_write_flash(adap, +			     FW_IMG_START + offsetof(struct fw_hdr, fw_ver), +			     sizeof(hdr->fw_ver), (const u8 *)&hdr->fw_ver); +out: +	if (ret) +		dev_err(adap->pdev_dev, "firmware download failed, error %d\n", +			ret); +	return ret; +} + +#define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\ +		     FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_ANEG) + +/** + *	t4_link_start - apply link configuration to MAC/PHY + *	@phy: the PHY to setup + *	@mac: the MAC to setup + *	@lc: the requested link configuration + * + *	Set up a port's MAC and PHY according to a desired link configuration. + *	- If the PHY can auto-negotiate first decide what to advertise, then + *	  enable/disable auto-negotiation as desired, and reset. + *	- If the PHY does not auto-negotiate just reset it. + *	- If auto-negotiation is off set the MAC to the proper speed/duplex/FC, + *	  otherwise do it later based on the outcome of auto-negotiation. + */ +int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port, +		  struct link_config *lc) +{ +	struct fw_port_cmd c; +	unsigned int fc = 0, mdi = FW_PORT_MDI(FW_PORT_MDI_AUTO); + +	lc->link_ok = 0; +	if (lc->requested_fc & PAUSE_RX) +		fc |= FW_PORT_CAP_FC_RX; +	if (lc->requested_fc & PAUSE_TX) +		fc |= FW_PORT_CAP_FC_TX; + +	memset(&c, 0, sizeof(c)); +	c.op_to_portid = htonl(FW_CMD_OP(FW_PORT_CMD) | FW_CMD_REQUEST | +			       FW_CMD_EXEC | FW_PORT_CMD_PORTID(port)); +	c.action_to_len16 = htonl(FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) | +				  FW_LEN16(c)); + +	if (!(lc->supported & FW_PORT_CAP_ANEG)) { +		c.u.l1cfg.rcap = htonl((lc->supported & ADVERT_MASK) | fc); +		lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); +	} else if (lc->autoneg == AUTONEG_DISABLE) { +		c.u.l1cfg.rcap = htonl(lc->requested_speed | fc | mdi); +		lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); +	} else +		c.u.l1cfg.rcap = htonl(lc->advertising | fc | mdi); + +	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + *	t4_restart_aneg - restart autonegotiation + *	@adap: the adapter + *	@mbox: mbox to use for the FW command + *	@port: the port id + * + *	Restarts autonegotiation for the selected port. + */ +int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port) +{ +	struct fw_port_cmd c; + +	memset(&c, 0, sizeof(c)); +	c.op_to_portid = htonl(FW_CMD_OP(FW_PORT_CMD) | FW_CMD_REQUEST | +			       FW_CMD_EXEC | FW_PORT_CMD_PORTID(port)); +	c.action_to_len16 = htonl(FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) | +				  FW_LEN16(c)); +	c.u.l1cfg.rcap = htonl(FW_PORT_CAP_ANEG); +	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + *	t4_set_vlan_accel - configure HW VLAN extraction + *	@adap: the adapter + *	@ports: bitmap of adapter ports to operate on + *	@on: enable (1) or disable (0) HW VLAN extraction + * + *	Enables or disables HW extraction of VLAN tags for the ports specified + *	by @ports.  @ports is a bitmap with the ith bit designating the port + *	associated with the ith adapter channel. + */ +void t4_set_vlan_accel(struct adapter *adap, unsigned int ports, int on) +{ +	ports <<= VLANEXTENABLE_SHIFT; +	t4_set_reg_field(adap, TP_OUT_CONFIG, ports, on ? ports : 0); +} + +struct intr_info { +	unsigned int mask;       /* bits to check in interrupt status */ +	const char *msg;         /* message to print or NULL */ +	short stat_idx;          /* stat counter to increment or -1 */ +	unsigned short fatal;    /* whether the condition reported is fatal */ +}; + +/** + *	t4_handle_intr_status - table driven interrupt handler + *	@adapter: the adapter that generated the interrupt + *	@reg: the interrupt status register to process + *	@acts: table of interrupt actions + * + *	A table driven interrupt handler that applies a set of masks to an + *	interrupt status word and performs the corresponding actions if the + *	interrupts described by the mask have occured.  The actions include + *	optionally emitting a warning or alert message.  The table is terminated + *	by an entry specifying mask 0.  Returns the number of fatal interrupt + *	conditions. + */ +static int t4_handle_intr_status(struct adapter *adapter, unsigned int reg, +				 const struct intr_info *acts) +{ +	int fatal = 0; +	unsigned int mask = 0; +	unsigned int status = t4_read_reg(adapter, reg); + +	for ( ; acts->mask; ++acts) { +		if (!(status & acts->mask)) +			continue; +		if (acts->fatal) { +			fatal++; +			dev_alert(adapter->pdev_dev, "%s (0x%x)\n", acts->msg, +				  status & acts->mask); +		} else if (acts->msg && printk_ratelimit()) +			dev_warn(adapter->pdev_dev, "%s (0x%x)\n", acts->msg, +				 status & acts->mask); +		mask |= acts->mask; +	} +	status &= mask; +	if (status)                           /* clear processed interrupts */ +		t4_write_reg(adapter, reg, status); +	return fatal; +} + +/* + * Interrupt handler for the PCIE module. + */ +static void pcie_intr_handler(struct adapter *adapter) +{ +	static struct intr_info sysbus_intr_info[] = { +		{ RNPP, "RXNP array parity error", -1, 1 }, +		{ RPCP, "RXPC array parity error", -1, 1 }, +		{ RCIP, "RXCIF array parity error", -1, 1 }, +		{ RCCP, "Rx completions control array parity error", -1, 1 }, +		{ RFTP, "RXFT array parity error", -1, 1 }, +		{ 0 } +	}; +	static struct intr_info pcie_port_intr_info[] = { +		{ TPCP, "TXPC array parity error", -1, 1 }, +		{ TNPP, "TXNP array parity error", -1, 1 }, +		{ TFTP, "TXFT array parity error", -1, 1 }, +		{ TCAP, "TXCA array parity error", -1, 1 }, +		{ TCIP, "TXCIF array parity error", -1, 1 }, +		{ RCAP, "RXCA array parity error", -1, 1 }, +		{ OTDD, "outbound request TLP discarded", -1, 1 }, +		{ RDPE, "Rx data parity error", -1, 1 }, +		{ TDUE, "Tx uncorrectable data error", -1, 1 }, +		{ 0 } +	}; +	static struct intr_info pcie_intr_info[] = { +		{ MSIADDRLPERR, "MSI AddrL parity error", -1, 1 }, +		{ MSIADDRHPERR, "MSI AddrH parity error", -1, 1 }, +		{ MSIDATAPERR, "MSI data parity error", -1, 1 }, +		{ MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 }, +		{ MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 }, +		{ MSIXDATAPERR, "MSI-X data parity error", -1, 1 }, +		{ MSIXDIPERR, "MSI-X DI parity error", -1, 1 }, +		{ PIOCPLPERR, "PCI PIO completion FIFO parity error", -1, 1 }, +		{ PIOREQPERR, "PCI PIO request FIFO parity error", -1, 1 }, +		{ TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 }, +		{ CCNTPERR, "PCI CMD channel count parity error", -1, 1 }, +		{ CREQPERR, "PCI CMD channel request parity error", -1, 1 }, +		{ CRSPPERR, "PCI CMD channel response parity error", -1, 1 }, +		{ DCNTPERR, "PCI DMA channel count parity error", -1, 1 }, +		{ DREQPERR, "PCI DMA channel request parity error", -1, 1 }, +		{ DRSPPERR, "PCI DMA channel response parity error", -1, 1 }, +		{ HCNTPERR, "PCI HMA channel count parity error", -1, 1 }, +		{ HREQPERR, "PCI HMA channel request parity error", -1, 1 }, +		{ HRSPPERR, "PCI HMA channel response parity error", -1, 1 }, +		{ CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 }, +		{ FIDPERR, "PCI FID parity error", -1, 1 }, +		{ INTXCLRPERR, "PCI INTx clear parity error", -1, 1 }, +		{ MATAGPERR, "PCI MA tag parity error", -1, 1 }, +		{ PIOTAGPERR, "PCI PIO tag parity error", -1, 1 }, +		{ RXCPLPERR, "PCI Rx completion parity error", -1, 1 }, +		{ RXWRPERR, "PCI Rx write parity error", -1, 1 }, +		{ RPLPERR, "PCI replay buffer parity error", -1, 1 }, +		{ PCIESINT, "PCI core secondary fault", -1, 1 }, +		{ PCIEPINT, "PCI core primary fault", -1, 1 }, +		{ UNXSPLCPLERR, "PCI unexpected split completion error", -1, 0 }, +		{ 0 } +	}; + +	int fat; + +	fat = t4_handle_intr_status(adapter, +				    PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS, +				    sysbus_intr_info) + +	      t4_handle_intr_status(adapter, +				    PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS, +				    pcie_port_intr_info) + +	      t4_handle_intr_status(adapter, PCIE_INT_CAUSE, pcie_intr_info); +	if (fat) +		t4_fatal_err(adapter); +} + +/* + * TP interrupt handler. + */ +static void tp_intr_handler(struct adapter *adapter) +{ +	static struct intr_info tp_intr_info[] = { +		{ 0x3fffffff, "TP parity error", -1, 1 }, +		{ FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 }, +		{ 0 } +	}; + +	if (t4_handle_intr_status(adapter, TP_INT_CAUSE, tp_intr_info)) +		t4_fatal_err(adapter); +} + +/* + * SGE interrupt handler. + */ +static void sge_intr_handler(struct adapter *adapter) +{ +	u64 v; + +	static struct intr_info sge_intr_info[] = { +		{ ERR_CPL_EXCEED_IQE_SIZE, +		  "SGE received CPL exceeding IQE size", -1, 1 }, +		{ ERR_INVALID_CIDX_INC, +		  "SGE GTS CIDX increment too large", -1, 0 }, +		{ ERR_CPL_OPCODE_0, "SGE received 0-length CPL", -1, 0 }, +		{ ERR_DROPPED_DB, "SGE doorbell dropped", -1, 0 }, +		{ ERR_DATA_CPL_ON_HIGH_QID1 | ERR_DATA_CPL_ON_HIGH_QID0, +		  "SGE IQID > 1023 received CPL for FL", -1, 0 }, +		{ ERR_BAD_DB_PIDX3, "SGE DBP 3 pidx increment too large", -1, +		  0 }, +		{ ERR_BAD_DB_PIDX2, "SGE DBP 2 pidx increment too large", -1, +		  0 }, +		{ ERR_BAD_DB_PIDX1, "SGE DBP 1 pidx increment too large", -1, +		  0 }, +		{ ERR_BAD_DB_PIDX0, "SGE DBP 0 pidx increment too large", -1, +		  0 }, +		{ ERR_ING_CTXT_PRIO, +		  "SGE too many priority ingress contexts", -1, 0 }, +		{ ERR_EGR_CTXT_PRIO, +		  "SGE too many priority egress contexts", -1, 0 }, +		{ INGRESS_SIZE_ERR, "SGE illegal ingress QID", -1, 0 }, +		{ EGRESS_SIZE_ERR, "SGE illegal egress QID", -1, 0 }, +		{ 0 } +	}; + +	v = (u64)t4_read_reg(adapter, SGE_INT_CAUSE1) | +	    ((u64)t4_read_reg(adapter, SGE_INT_CAUSE2) << 32); +	if (v) { +		dev_alert(adapter->pdev_dev, "SGE parity error (%#llx)\n", +			 (unsigned long long)v); +		t4_write_reg(adapter, SGE_INT_CAUSE1, v); +		t4_write_reg(adapter, SGE_INT_CAUSE2, v >> 32); +	} + +	if (t4_handle_intr_status(adapter, SGE_INT_CAUSE3, sge_intr_info) || +	    v != 0) +		t4_fatal_err(adapter); +} + +/* + * CIM interrupt handler. + */ +static void cim_intr_handler(struct adapter *adapter) +{ +	static struct intr_info cim_intr_info[] = { +		{ PREFDROPINT, "CIM control register prefetch drop", -1, 1 }, +		{ OBQPARERR, "CIM OBQ parity error", -1, 1 }, +		{ IBQPARERR, "CIM IBQ parity error", -1, 1 }, +		{ MBUPPARERR, "CIM mailbox uP parity error", -1, 1 }, +		{ MBHOSTPARERR, "CIM mailbox host parity error", -1, 1 }, +		{ TIEQINPARERRINT, "CIM TIEQ outgoing parity error", -1, 1 }, +		{ TIEQOUTPARERRINT, "CIM TIEQ incoming parity error", -1, 1 }, +		{ 0 } +	}; +	static struct intr_info cim_upintr_info[] = { +		{ RSVDSPACEINT, "CIM reserved space access", -1, 1 }, +		{ ILLTRANSINT, "CIM illegal transaction", -1, 1 }, +		{ ILLWRINT, "CIM illegal write", -1, 1 }, +		{ ILLRDINT, "CIM illegal read", -1, 1 }, +		{ ILLRDBEINT, "CIM illegal read BE", -1, 1 }, +		{ ILLWRBEINT, "CIM illegal write BE", -1, 1 }, +		{ SGLRDBOOTINT, "CIM single read from boot space", -1, 1 }, +		{ SGLWRBOOTINT, "CIM single write to boot space", -1, 1 }, +		{ BLKWRBOOTINT, "CIM block write to boot space", -1, 1 }, +		{ SGLRDFLASHINT, "CIM single read from flash space", -1, 1 }, +		{ SGLWRFLASHINT, "CIM single write to flash space", -1, 1 }, +		{ BLKWRFLASHINT, "CIM block write to flash space", -1, 1 }, +		{ SGLRDEEPROMINT, "CIM single EEPROM read", -1, 1 }, +		{ SGLWREEPROMINT, "CIM single EEPROM write", -1, 1 }, +		{ BLKRDEEPROMINT, "CIM block EEPROM read", -1, 1 }, +		{ BLKWREEPROMINT, "CIM block EEPROM write", -1, 1 }, +		{ SGLRDCTLINT , "CIM single read from CTL space", -1, 1 }, +		{ SGLWRCTLINT , "CIM single write to CTL space", -1, 1 }, +		{ BLKRDCTLINT , "CIM block read from CTL space", -1, 1 }, +		{ BLKWRCTLINT , "CIM block write to CTL space", -1, 1 }, +		{ SGLRDPLINT , "CIM single read from PL space", -1, 1 }, +		{ SGLWRPLINT , "CIM single write to PL space", -1, 1 }, +		{ BLKRDPLINT , "CIM block read from PL space", -1, 1 }, +		{ BLKWRPLINT , "CIM block write to PL space", -1, 1 }, +		{ REQOVRLOOKUPINT , "CIM request FIFO overwrite", -1, 1 }, +		{ RSPOVRLOOKUPINT , "CIM response FIFO overwrite", -1, 1 }, +		{ TIMEOUTINT , "CIM PIF timeout", -1, 1 }, +		{ TIMEOUTMAINT , "CIM PIF MA timeout", -1, 1 }, +		{ 0 } +	}; + +	int fat; + +	fat = t4_handle_intr_status(adapter, CIM_HOST_INT_CAUSE, +				    cim_intr_info) + +	      t4_handle_intr_status(adapter, CIM_HOST_UPACC_INT_CAUSE, +				    cim_upintr_info); +	if (fat) +		t4_fatal_err(adapter); +} + +/* + * ULP RX interrupt handler. + */ +static void ulprx_intr_handler(struct adapter *adapter) +{ +	static struct intr_info ulprx_intr_info[] = { +		{ 0x7fffff, "ULPRX parity error", -1, 1 }, +		{ 0 } +	}; + +	if (t4_handle_intr_status(adapter, ULP_RX_INT_CAUSE, ulprx_intr_info)) +		t4_fatal_err(adapter); +} + +/* + * ULP TX interrupt handler. + */ +static void ulptx_intr_handler(struct adapter *adapter) +{ +	static struct intr_info ulptx_intr_info[] = { +		{ PBL_BOUND_ERR_CH3, "ULPTX channel 3 PBL out of bounds", -1, +		  0 }, +		{ PBL_BOUND_ERR_CH2, "ULPTX channel 2 PBL out of bounds", -1, +		  0 }, +		{ PBL_BOUND_ERR_CH1, "ULPTX channel 1 PBL out of bounds", -1, +		  0 }, +		{ PBL_BOUND_ERR_CH0, "ULPTX channel 0 PBL out of bounds", -1, +		  0 }, +		{ 0xfffffff, "ULPTX parity error", -1, 1 }, +		{ 0 } +	}; + +	if (t4_handle_intr_status(adapter, ULP_TX_INT_CAUSE, ulptx_intr_info)) +		t4_fatal_err(adapter); +} + +/* + * PM TX interrupt handler. + */ +static void pmtx_intr_handler(struct adapter *adapter) +{ +	static struct intr_info pmtx_intr_info[] = { +		{ PCMD_LEN_OVFL0, "PMTX channel 0 pcmd too large", -1, 1 }, +		{ PCMD_LEN_OVFL1, "PMTX channel 1 pcmd too large", -1, 1 }, +		{ PCMD_LEN_OVFL2, "PMTX channel 2 pcmd too large", -1, 1 }, +		{ ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1 }, +		{ PMTX_FRAMING_ERROR, "PMTX framing error", -1, 1 }, +		{ OESPI_PAR_ERROR, "PMTX oespi parity error", -1, 1 }, +		{ DB_OPTIONS_PAR_ERROR, "PMTX db_options parity error", -1, 1 }, +		{ ICSPI_PAR_ERROR, "PMTX icspi parity error", -1, 1 }, +		{ C_PCMD_PAR_ERROR, "PMTX c_pcmd parity error", -1, 1}, +		{ 0 } +	}; + +	if (t4_handle_intr_status(adapter, PM_TX_INT_CAUSE, pmtx_intr_info)) +		t4_fatal_err(adapter); +} + +/* + * PM RX interrupt handler. + */ +static void pmrx_intr_handler(struct adapter *adapter) +{ +	static struct intr_info pmrx_intr_info[] = { +		{ ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1 }, +		{ PMRX_FRAMING_ERROR, "PMRX framing error", -1, 1 }, +		{ OCSPI_PAR_ERROR, "PMRX ocspi parity error", -1, 1 }, +		{ DB_OPTIONS_PAR_ERROR, "PMRX db_options parity error", -1, 1 }, +		{ IESPI_PAR_ERROR, "PMRX iespi parity error", -1, 1 }, +		{ E_PCMD_PAR_ERROR, "PMRX e_pcmd parity error", -1, 1}, +		{ 0 } +	}; + +	if (t4_handle_intr_status(adapter, PM_RX_INT_CAUSE, pmrx_intr_info)) +		t4_fatal_err(adapter); +} + +/* + * CPL switch interrupt handler. + */ +static void cplsw_intr_handler(struct adapter *adapter) +{ +	static struct intr_info cplsw_intr_info[] = { +		{ CIM_OP_MAP_PERR, "CPLSW CIM op_map parity error", -1, 1 }, +		{ CIM_OVFL_ERROR, "CPLSW CIM overflow", -1, 1 }, +		{ TP_FRAMING_ERROR, "CPLSW TP framing error", -1, 1 }, +		{ SGE_FRAMING_ERROR, "CPLSW SGE framing error", -1, 1 }, +		{ CIM_FRAMING_ERROR, "CPLSW CIM framing error", -1, 1 }, +		{ ZERO_SWITCH_ERROR, "CPLSW no-switch error", -1, 1 }, +		{ 0 } +	}; + +	if (t4_handle_intr_status(adapter, CPL_INTR_CAUSE, cplsw_intr_info)) +		t4_fatal_err(adapter); +} + +/* + * LE interrupt handler. + */ +static void le_intr_handler(struct adapter *adap) +{ +	static struct intr_info le_intr_info[] = { +		{ LIPMISS, "LE LIP miss", -1, 0 }, +		{ LIP0, "LE 0 LIP error", -1, 0 }, +		{ PARITYERR, "LE parity error", -1, 1 }, +		{ UNKNOWNCMD, "LE unknown command", -1, 1 }, +		{ REQQPARERR, "LE request queue parity error", -1, 1 }, +		{ 0 } +	}; + +	if (t4_handle_intr_status(adap, LE_DB_INT_CAUSE, le_intr_info)) +		t4_fatal_err(adap); +} + +/* + * MPS interrupt handler. + */ +static void mps_intr_handler(struct adapter *adapter) +{ +	static struct intr_info mps_rx_intr_info[] = { +		{ 0xffffff, "MPS Rx parity error", -1, 1 }, +		{ 0 } +	}; +	static struct intr_info mps_tx_intr_info[] = { +		{ TPFIFO, "MPS Tx TP FIFO parity error", -1, 1 }, +		{ NCSIFIFO, "MPS Tx NC-SI FIFO parity error", -1, 1 }, +		{ TXDATAFIFO, "MPS Tx data FIFO parity error", -1, 1 }, +		{ TXDESCFIFO, "MPS Tx desc FIFO parity error", -1, 1 }, +		{ BUBBLE, "MPS Tx underflow", -1, 1 }, +		{ SECNTERR, "MPS Tx SOP/EOP error", -1, 1 }, +		{ FRMERR, "MPS Tx framing error", -1, 1 }, +		{ 0 } +	}; +	static struct intr_info mps_trc_intr_info[] = { +		{ FILTMEM, "MPS TRC filter parity error", -1, 1 }, +		{ PKTFIFO, "MPS TRC packet FIFO parity error", -1, 1 }, +		{ MISCPERR, "MPS TRC misc parity error", -1, 1 }, +		{ 0 } +	}; +	static struct intr_info mps_stat_sram_intr_info[] = { +		{ 0x1fffff, "MPS statistics SRAM parity error", -1, 1 }, +		{ 0 } +	}; +	static struct intr_info mps_stat_tx_intr_info[] = { +		{ 0xfffff, "MPS statistics Tx FIFO parity error", -1, 1 }, +		{ 0 } +	}; +	static struct intr_info mps_stat_rx_intr_info[] = { +		{ 0xffffff, "MPS statistics Rx FIFO parity error", -1, 1 }, +		{ 0 } +	}; +	static struct intr_info mps_cls_intr_info[] = { +		{ MATCHSRAM, "MPS match SRAM parity error", -1, 1 }, +		{ MATCHTCAM, "MPS match TCAM parity error", -1, 1 }, +		{ HASHSRAM, "MPS hash SRAM parity error", -1, 1 }, +		{ 0 } +	}; + +	int fat; + +	fat = t4_handle_intr_status(adapter, MPS_RX_PERR_INT_CAUSE, +				    mps_rx_intr_info) + +	      t4_handle_intr_status(adapter, MPS_TX_INT_CAUSE, +				    mps_tx_intr_info) + +	      t4_handle_intr_status(adapter, MPS_TRC_INT_CAUSE, +				    mps_trc_intr_info) + +	      t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_SRAM, +				    mps_stat_sram_intr_info) + +	      t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_TX_FIFO, +				    mps_stat_tx_intr_info) + +	      t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_RX_FIFO, +				    mps_stat_rx_intr_info) + +	      t4_handle_intr_status(adapter, MPS_CLS_INT_CAUSE, +				    mps_cls_intr_info); + +	t4_write_reg(adapter, MPS_INT_CAUSE, CLSINT | TRCINT | +		     RXINT | TXINT | STATINT); +	t4_read_reg(adapter, MPS_INT_CAUSE);                    /* flush */ +	if (fat) +		t4_fatal_err(adapter); +} + +#define MEM_INT_MASK (PERR_INT_CAUSE | ECC_CE_INT_CAUSE | ECC_UE_INT_CAUSE) + +/* + * EDC/MC interrupt handler. + */ +static void mem_intr_handler(struct adapter *adapter, int idx) +{ +	static const char name[3][5] = { "EDC0", "EDC1", "MC" }; + +	unsigned int addr, cnt_addr, v; + +	if (idx <= MEM_EDC1) { +		addr = EDC_REG(EDC_INT_CAUSE, idx); +		cnt_addr = EDC_REG(EDC_ECC_STATUS, idx); +	} else { +		addr = MC_INT_CAUSE; +		cnt_addr = MC_ECC_STATUS; +	} + +	v = t4_read_reg(adapter, addr) & MEM_INT_MASK; +	if (v & PERR_INT_CAUSE) +		dev_alert(adapter->pdev_dev, "%s FIFO parity error\n", +			  name[idx]); +	if (v & ECC_CE_INT_CAUSE) { +		u32 cnt = ECC_CECNT_GET(t4_read_reg(adapter, cnt_addr)); + +		t4_write_reg(adapter, cnt_addr, ECC_CECNT_MASK); +		if (printk_ratelimit()) +			dev_warn(adapter->pdev_dev, +				 "%u %s correctable ECC data error%s\n", +				 cnt, name[idx], cnt > 1 ? "s" : ""); +	} +	if (v & ECC_UE_INT_CAUSE) +		dev_alert(adapter->pdev_dev, +			  "%s uncorrectable ECC data error\n", name[idx]); + +	t4_write_reg(adapter, addr, v); +	if (v & (PERR_INT_CAUSE | ECC_UE_INT_CAUSE)) +		t4_fatal_err(adapter); +} + +/* + * MA interrupt handler. + */ +static void ma_intr_handler(struct adapter *adap) +{ +	u32 v, status = t4_read_reg(adap, MA_INT_CAUSE); + +	if (status & MEM_PERR_INT_CAUSE) +		dev_alert(adap->pdev_dev, +			  "MA parity error, parity status %#x\n", +			  t4_read_reg(adap, MA_PARITY_ERROR_STATUS)); +	if (status & MEM_WRAP_INT_CAUSE) { +		v = t4_read_reg(adap, MA_INT_WRAP_STATUS); +		dev_alert(adap->pdev_dev, "MA address wrap-around error by " +			  "client %u to address %#x\n", +			  MEM_WRAP_CLIENT_NUM_GET(v), +			  MEM_WRAP_ADDRESS_GET(v) << 4); +	} +	t4_write_reg(adap, MA_INT_CAUSE, status); +	t4_fatal_err(adap); +} + +/* + * SMB interrupt handler. + */ +static void smb_intr_handler(struct adapter *adap) +{ +	static struct intr_info smb_intr_info[] = { +		{ MSTTXFIFOPARINT, "SMB master Tx FIFO parity error", -1, 1 }, +		{ MSTRXFIFOPARINT, "SMB master Rx FIFO parity error", -1, 1 }, +		{ SLVFIFOPARINT, "SMB slave FIFO parity error", -1, 1 }, +		{ 0 } +	}; + +	if (t4_handle_intr_status(adap, SMB_INT_CAUSE, smb_intr_info)) +		t4_fatal_err(adap); +} + +/* + * NC-SI interrupt handler. + */ +static void ncsi_intr_handler(struct adapter *adap) +{ +	static struct intr_info ncsi_intr_info[] = { +		{ CIM_DM_PRTY_ERR, "NC-SI CIM parity error", -1, 1 }, +		{ MPS_DM_PRTY_ERR, "NC-SI MPS parity error", -1, 1 }, +		{ TXFIFO_PRTY_ERR, "NC-SI Tx FIFO parity error", -1, 1 }, +		{ RXFIFO_PRTY_ERR, "NC-SI Rx FIFO parity error", -1, 1 }, +		{ 0 } +	}; + +	if (t4_handle_intr_status(adap, NCSI_INT_CAUSE, ncsi_intr_info)) +		t4_fatal_err(adap); +} + +/* + * XGMAC interrupt handler. + */ +static void xgmac_intr_handler(struct adapter *adap, int port) +{ +	u32 v = t4_read_reg(adap, PORT_REG(port, XGMAC_PORT_INT_CAUSE)); + +	v &= TXFIFO_PRTY_ERR | RXFIFO_PRTY_ERR; +	if (!v) +		return; + +	if (v & TXFIFO_PRTY_ERR) +		dev_alert(adap->pdev_dev, "XGMAC %d Tx FIFO parity error\n", +			  port); +	if (v & RXFIFO_PRTY_ERR) +		dev_alert(adap->pdev_dev, "XGMAC %d Rx FIFO parity error\n", +			  port); +	t4_write_reg(adap, PORT_REG(port, XGMAC_PORT_INT_CAUSE), v); +	t4_fatal_err(adap); +} + +/* + * PL interrupt handler. + */ +static void pl_intr_handler(struct adapter *adap) +{ +	static struct intr_info pl_intr_info[] = { +		{ FATALPERR, "T4 fatal parity error", -1, 1 }, +		{ PERRVFID, "PL VFID_MAP parity error", -1, 1 }, +		{ 0 } +	}; + +	if (t4_handle_intr_status(adap, PL_PL_INT_CAUSE, pl_intr_info)) +		t4_fatal_err(adap); +} + +#define PF_INTR_MASK (PFSW | PFCIM) +#define GLBL_INTR_MASK (CIM | MPS | PL | PCIE | MC | EDC0 | \ +		EDC1 | LE | TP | MA | PM_TX | PM_RX | ULP_RX | \ +		CPL_SWITCH | SGE | ULP_TX) + +/** + *	t4_slow_intr_handler - control path interrupt handler + *	@adapter: the adapter + * + *	T4 interrupt handler for non-data global interrupt events, e.g., errors. + *	The designation 'slow' is because it involves register reads, while + *	data interrupts typically don't involve any MMIOs. + */ +int t4_slow_intr_handler(struct adapter *adapter) +{ +	u32 cause = t4_read_reg(adapter, PL_INT_CAUSE); + +	if (!(cause & GLBL_INTR_MASK)) +		return 0; +	if (cause & CIM) +		cim_intr_handler(adapter); +	if (cause & MPS) +		mps_intr_handler(adapter); +	if (cause & NCSI) +		ncsi_intr_handler(adapter); +	if (cause & PL) +		pl_intr_handler(adapter); +	if (cause & SMB) +		smb_intr_handler(adapter); +	if (cause & XGMAC0) +		xgmac_intr_handler(adapter, 0); +	if (cause & XGMAC1) +		xgmac_intr_handler(adapter, 1); +	if (cause & XGMAC_KR0) +		xgmac_intr_handler(adapter, 2); +	if (cause & XGMAC_KR1) +		xgmac_intr_handler(adapter, 3); +	if (cause & PCIE) +		pcie_intr_handler(adapter); +	if (cause & MC) +		mem_intr_handler(adapter, MEM_MC); +	if (cause & EDC0) +		mem_intr_handler(adapter, MEM_EDC0); +	if (cause & EDC1) +		mem_intr_handler(adapter, MEM_EDC1); +	if (cause & LE) +		le_intr_handler(adapter); +	if (cause & TP) +		tp_intr_handler(adapter); +	if (cause & MA) +		ma_intr_handler(adapter); +	if (cause & PM_TX) +		pmtx_intr_handler(adapter); +	if (cause & PM_RX) +		pmrx_intr_handler(adapter); +	if (cause & ULP_RX) +		ulprx_intr_handler(adapter); +	if (cause & CPL_SWITCH) +		cplsw_intr_handler(adapter); +	if (cause & SGE) +		sge_intr_handler(adapter); +	if (cause & ULP_TX) +		ulptx_intr_handler(adapter); + +	/* Clear the interrupts just processed for which we are the master. */ +	t4_write_reg(adapter, PL_INT_CAUSE, cause & GLBL_INTR_MASK); +	(void) t4_read_reg(adapter, PL_INT_CAUSE); /* flush */ +	return 1; +} + +/** + *	t4_intr_enable - enable interrupts + *	@adapter: the adapter whose interrupts should be enabled + * + *	Enable PF-specific interrupts for the calling function and the top-level + *	interrupt concentrator for global interrupts.  Interrupts are already + *	enabled at each module,	here we just enable the roots of the interrupt + *	hierarchies. + * + *	Note: this function should be called only when the driver manages + *	non PF-specific interrupts from the various HW modules.  Only one PCI + *	function at a time should be doing this. + */ +void t4_intr_enable(struct adapter *adapter) +{ +	u32 pf = SOURCEPF_GET(t4_read_reg(adapter, PL_WHOAMI)); + +	t4_write_reg(adapter, SGE_INT_ENABLE3, ERR_CPL_EXCEED_IQE_SIZE | +		     ERR_INVALID_CIDX_INC | ERR_CPL_OPCODE_0 | +		     ERR_DROPPED_DB | ERR_DATA_CPL_ON_HIGH_QID1 | +		     ERR_DATA_CPL_ON_HIGH_QID0 | ERR_BAD_DB_PIDX3 | +		     ERR_BAD_DB_PIDX2 | ERR_BAD_DB_PIDX1 | +		     ERR_BAD_DB_PIDX0 | ERR_ING_CTXT_PRIO | +		     ERR_EGR_CTXT_PRIO | INGRESS_SIZE_ERR | +		     EGRESS_SIZE_ERR); +	t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE), PF_INTR_MASK); +	t4_set_reg_field(adapter, PL_INT_MAP0, 0, 1 << pf); +} + +/** + *	t4_intr_disable - disable interrupts + *	@adapter: the adapter whose interrupts should be disabled + * + *	Disable interrupts.  We only disable the top-level interrupt + *	concentrators.  The caller must be a PCI function managing global + *	interrupts. + */ +void t4_intr_disable(struct adapter *adapter) +{ +	u32 pf = SOURCEPF_GET(t4_read_reg(adapter, PL_WHOAMI)); + +	t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE), 0); +	t4_set_reg_field(adapter, PL_INT_MAP0, 1 << pf, 0); +} + +/** + *	t4_intr_clear - clear all interrupts + *	@adapter: the adapter whose interrupts should be cleared + * + *	Clears all interrupts.  The caller must be a PCI function managing + *	global interrupts. + */ +void t4_intr_clear(struct adapter *adapter) +{ +	static const unsigned int cause_reg[] = { +		SGE_INT_CAUSE1, SGE_INT_CAUSE2, SGE_INT_CAUSE3, +		PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS, +		PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS, +		PCIE_NONFAT_ERR, PCIE_INT_CAUSE, +		MC_INT_CAUSE, +		MA_INT_WRAP_STATUS, MA_PARITY_ERROR_STATUS, MA_INT_CAUSE, +		EDC_INT_CAUSE, EDC_REG(EDC_INT_CAUSE, 1), +		CIM_HOST_INT_CAUSE, CIM_HOST_UPACC_INT_CAUSE, +		MYPF_REG(CIM_PF_HOST_INT_CAUSE), +		TP_INT_CAUSE, +		ULP_RX_INT_CAUSE, ULP_TX_INT_CAUSE, +		PM_RX_INT_CAUSE, PM_TX_INT_CAUSE, +		MPS_RX_PERR_INT_CAUSE, +		CPL_INTR_CAUSE, +		MYPF_REG(PL_PF_INT_CAUSE), +		PL_PL_INT_CAUSE, +		LE_DB_INT_CAUSE, +	}; + +	unsigned int i; + +	for (i = 0; i < ARRAY_SIZE(cause_reg); ++i) +		t4_write_reg(adapter, cause_reg[i], 0xffffffff); + +	t4_write_reg(adapter, PL_INT_CAUSE, GLBL_INTR_MASK); +	(void) t4_read_reg(adapter, PL_INT_CAUSE);          /* flush */ +} + +/** + *	hash_mac_addr - return the hash value of a MAC address + *	@addr: the 48-bit Ethernet MAC address + * + *	Hashes a MAC address according to the hash function used by HW inexact + *	(hash) address matching. + */ +static int hash_mac_addr(const u8 *addr) +{ +	u32 a = ((u32)addr[0] << 16) | ((u32)addr[1] << 8) | addr[2]; +	u32 b = ((u32)addr[3] << 16) | ((u32)addr[4] << 8) | addr[5]; +	a ^= b; +	a ^= (a >> 12); +	a ^= (a >> 6); +	return a & 0x3f; +} + +/** + *	t4_config_rss_range - configure a portion of the RSS mapping table + *	@adapter: the adapter + *	@mbox: mbox to use for the FW command + *	@viid: virtual interface whose RSS subtable is to be written + *	@start: start entry in the table to write + *	@n: how many table entries to write + *	@rspq: values for the response queue lookup table + *	@nrspq: number of values in @rspq + * + *	Programs the selected part of the VI's RSS mapping table with the + *	provided values.  If @nrspq < @n the supplied values are used repeatedly + *	until the full table range is populated. + * + *	The caller must ensure the values in @rspq are in the range allowed for + *	@viid. + */ +int t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid, +			int start, int n, const u16 *rspq, unsigned int nrspq) +{ +	int ret; +	const u16 *rsp = rspq; +	const u16 *rsp_end = rspq + nrspq; +	struct fw_rss_ind_tbl_cmd cmd; + +	memset(&cmd, 0, sizeof(cmd)); +	cmd.op_to_viid = htonl(FW_CMD_OP(FW_RSS_IND_TBL_CMD) | +			       FW_CMD_REQUEST | FW_CMD_WRITE | +			       FW_RSS_IND_TBL_CMD_VIID(viid)); +	cmd.retval_len16 = htonl(FW_LEN16(cmd)); + +	/* each fw_rss_ind_tbl_cmd takes up to 32 entries */ +	while (n > 0) { +		int nq = min(n, 32); +		__be32 *qp = &cmd.iq0_to_iq2; + +		cmd.niqid = htons(nq); +		cmd.startidx = htons(start); + +		start += nq; +		n -= nq; + +		while (nq > 0) { +			unsigned int v; + +			v = FW_RSS_IND_TBL_CMD_IQ0(*rsp); +			if (++rsp >= rsp_end) +				rsp = rspq; +			v |= FW_RSS_IND_TBL_CMD_IQ1(*rsp); +			if (++rsp >= rsp_end) +				rsp = rspq; +			v |= FW_RSS_IND_TBL_CMD_IQ2(*rsp); +			if (++rsp >= rsp_end) +				rsp = rspq; + +			*qp++ = htonl(v); +			nq -= 3; +		} + +		ret = t4_wr_mbox(adapter, mbox, &cmd, sizeof(cmd), NULL); +		if (ret) +			return ret; +	} +	return 0; +} + +/** + *	t4_config_glbl_rss - configure the global RSS mode + *	@adapter: the adapter + *	@mbox: mbox to use for the FW command + *	@mode: global RSS mode + *	@flags: mode-specific flags + * + *	Sets the global RSS mode. + */ +int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode, +		       unsigned int flags) +{ +	struct fw_rss_glb_config_cmd c; + +	memset(&c, 0, sizeof(c)); +	c.op_to_write = htonl(FW_CMD_OP(FW_RSS_GLB_CONFIG_CMD) | +			      FW_CMD_REQUEST | FW_CMD_WRITE); +	c.retval_len16 = htonl(FW_LEN16(c)); +	if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_MANUAL) { +		c.u.manual.mode_pkd = htonl(FW_RSS_GLB_CONFIG_CMD_MODE(mode)); +	} else if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL) { +		c.u.basicvirtual.mode_pkd = +			htonl(FW_RSS_GLB_CONFIG_CMD_MODE(mode)); +		c.u.basicvirtual.synmapen_to_hashtoeplitz = htonl(flags); +	} else +		return -EINVAL; +	return t4_wr_mbox(adapter, mbox, &c, sizeof(c), NULL); +} + +/* Read an RSS table row */ +static int rd_rss_row(struct adapter *adap, int row, u32 *val) +{ +	t4_write_reg(adap, TP_RSS_LKP_TABLE, 0xfff00000 | row); +	return t4_wait_op_done_val(adap, TP_RSS_LKP_TABLE, LKPTBLROWVLD, 1, +				   5, 0, val); +} + +/** + *	t4_read_rss - read the contents of the RSS mapping table + *	@adapter: the adapter + *	@map: holds the contents of the RSS mapping table + * + *	Reads the contents of the RSS hash->queue mapping table. + */ +int t4_read_rss(struct adapter *adapter, u16 *map) +{ +	u32 val; +	int i, ret; + +	for (i = 0; i < RSS_NENTRIES / 2; ++i) { +		ret = rd_rss_row(adapter, i, &val); +		if (ret) +			return ret; +		*map++ = LKPTBLQUEUE0_GET(val); +		*map++ = LKPTBLQUEUE1_GET(val); +	} +	return 0; +} + +/** + *	t4_tp_get_tcp_stats - read TP's TCP MIB counters + *	@adap: the adapter + *	@v4: holds the TCP/IP counter values + *	@v6: holds the TCP/IPv6 counter values + * + *	Returns the values of TP's TCP/IP and TCP/IPv6 MIB counters. + *	Either @v4 or @v6 may be %NULL to skip the corresponding stats. + */ +void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4, +			 struct tp_tcp_stats *v6) +{ +	u32 val[TP_MIB_TCP_RXT_SEG_LO - TP_MIB_TCP_OUT_RST + 1]; + +#define STAT_IDX(x) ((TP_MIB_TCP_##x) - TP_MIB_TCP_OUT_RST) +#define STAT(x)     val[STAT_IDX(x)] +#define STAT64(x)   (((u64)STAT(x##_HI) << 32) | STAT(x##_LO)) + +	if (v4) { +		t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, val, +				 ARRAY_SIZE(val), TP_MIB_TCP_OUT_RST); +		v4->tcpOutRsts = STAT(OUT_RST); +		v4->tcpInSegs  = STAT64(IN_SEG); +		v4->tcpOutSegs = STAT64(OUT_SEG); +		v4->tcpRetransSegs = STAT64(RXT_SEG); +	} +	if (v6) { +		t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, val, +				 ARRAY_SIZE(val), TP_MIB_TCP_V6OUT_RST); +		v6->tcpOutRsts = STAT(OUT_RST); +		v6->tcpInSegs  = STAT64(IN_SEG); +		v6->tcpOutSegs = STAT64(OUT_SEG); +		v6->tcpRetransSegs = STAT64(RXT_SEG); +	} +#undef STAT64 +#undef STAT +#undef STAT_IDX +} + +/** + *	t4_tp_get_err_stats - read TP's error MIB counters + *	@adap: the adapter + *	@st: holds the counter values + * + *	Returns the values of TP's error counters. + */ +void t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st) +{ +	t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, st->macInErrs, +			 12, TP_MIB_MAC_IN_ERR_0); +	t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, st->tnlCongDrops, +			 8, TP_MIB_TNL_CNG_DROP_0); +	t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, st->tnlTxDrops, +			 4, TP_MIB_TNL_DROP_0); +	t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, st->ofldVlanDrops, +			 4, TP_MIB_OFD_VLN_DROP_0); +	t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, st->tcp6InErrs, +			 4, TP_MIB_TCP_V6IN_ERR_0); +	t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, &st->ofldNoNeigh, +			 2, TP_MIB_OFD_ARP_DROP); +} + +/** + *	t4_read_mtu_tbl - returns the values in the HW path MTU table + *	@adap: the adapter + *	@mtus: where to store the MTU values + *	@mtu_log: where to store the MTU base-2 log (may be %NULL) + * + *	Reads the HW path MTU table. + */ +void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log) +{ +	u32 v; +	int i; + +	for (i = 0; i < NMTUS; ++i) { +		t4_write_reg(adap, TP_MTU_TABLE, +			     MTUINDEX(0xff) | MTUVALUE(i)); +		v = t4_read_reg(adap, TP_MTU_TABLE); +		mtus[i] = MTUVALUE_GET(v); +		if (mtu_log) +			mtu_log[i] = MTUWIDTH_GET(v); +	} +} + +/** + *	init_cong_ctrl - initialize congestion control parameters + *	@a: the alpha values for congestion control + *	@b: the beta values for congestion control + * + *	Initialize the congestion control parameters. + */ +static void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b) +{ +	a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1; +	a[9] = 2; +	a[10] = 3; +	a[11] = 4; +	a[12] = 5; +	a[13] = 6; +	a[14] = 7; +	a[15] = 8; +	a[16] = 9; +	a[17] = 10; +	a[18] = 14; +	a[19] = 17; +	a[20] = 21; +	a[21] = 25; +	a[22] = 30; +	a[23] = 35; +	a[24] = 45; +	a[25] = 60; +	a[26] = 80; +	a[27] = 100; +	a[28] = 200; +	a[29] = 300; +	a[30] = 400; +	a[31] = 500; + +	b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0; +	b[9] = b[10] = 1; +	b[11] = b[12] = 2; +	b[13] = b[14] = b[15] = b[16] = 3; +	b[17] = b[18] = b[19] = b[20] = b[21] = 4; +	b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5; +	b[28] = b[29] = 6; +	b[30] = b[31] = 7; +} + +/* The minimum additive increment value for the congestion control table */ +#define CC_MIN_INCR 2U + +/** + *	t4_load_mtus - write the MTU and congestion control HW tables + *	@adap: the adapter + *	@mtus: the values for the MTU table + *	@alpha: the values for the congestion control alpha parameter + *	@beta: the values for the congestion control beta parameter + * + *	Write the HW MTU table with the supplied MTUs and the high-speed + *	congestion control table with the supplied alpha, beta, and MTUs. + *	We write the two tables together because the additive increments + *	depend on the MTUs. + */ +void t4_load_mtus(struct adapter *adap, const unsigned short *mtus, +		  const unsigned short *alpha, const unsigned short *beta) +{ +	static const unsigned int avg_pkts[NCCTRL_WIN] = { +		2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640, +		896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480, +		28672, 40960, 57344, 81920, 114688, 163840, 229376 +	}; + +	unsigned int i, w; + +	for (i = 0; i < NMTUS; ++i) { +		unsigned int mtu = mtus[i]; +		unsigned int log2 = fls(mtu); + +		if (!(mtu & ((1 << log2) >> 2)))     /* round */ +			log2--; +		t4_write_reg(adap, TP_MTU_TABLE, MTUINDEX(i) | +			     MTUWIDTH(log2) | MTUVALUE(mtu)); + +		for (w = 0; w < NCCTRL_WIN; ++w) { +			unsigned int inc; + +			inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w], +				  CC_MIN_INCR); + +			t4_write_reg(adap, TP_CCTRL_TABLE, (i << 21) | +				     (w << 16) | (beta[w] << 13) | inc); +		} +	} +} + +/** + *	t4_set_trace_filter - configure one of the tracing filters + *	@adap: the adapter + *	@tp: the desired trace filter parameters + *	@idx: which filter to configure + *	@enable: whether to enable or disable the filter + * + *	Configures one of the tracing filters available in HW.  If @enable is + *	%0 @tp is not examined and may be %NULL. + */ +int t4_set_trace_filter(struct adapter *adap, const struct trace_params *tp, +			int idx, int enable) +{ +	int i, ofst = idx * 4; +	u32 data_reg, mask_reg, cfg; +	u32 multitrc = TRCMULTIFILTER; + +	if (!enable) { +		t4_write_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A + ofst, 0); +		goto out; +	} + +	if (tp->port > 11 || tp->invert > 1 || tp->skip_len > 0x1f || +	    tp->skip_ofst > 0x1f || tp->min_len > 0x1ff || +	    tp->snap_len > 9600 || (idx && tp->snap_len > 256)) +		return -EINVAL; + +	if (tp->snap_len > 256) {            /* must be tracer 0 */ +		if ((t4_read_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A + 4) | +		     t4_read_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A + 8) | +		     t4_read_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A + 12)) & TFEN) +			return -EINVAL;  /* other tracers are enabled */ +		multitrc = 0; +	} else if (idx) { +		i = t4_read_reg(adap, MPS_TRC_FILTER_MATCH_CTL_B); +		if (TFCAPTUREMAX_GET(i) > 256 && +		    (t4_read_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A) & TFEN)) +			return -EINVAL; +	} + +	/* stop the tracer we'll be changing */ +	t4_write_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A + ofst, 0); + +	/* disable tracing globally if running in the wrong single/multi mode */ +	cfg = t4_read_reg(adap, MPS_TRC_CFG); +	if ((cfg & TRCEN) && multitrc != (cfg & TRCMULTIFILTER)) { +		t4_write_reg(adap, MPS_TRC_CFG, cfg ^ TRCEN); +		t4_read_reg(adap, MPS_TRC_CFG);                  /* flush */ +		msleep(1); +		if (!(t4_read_reg(adap, MPS_TRC_CFG) & TRCFIFOEMPTY)) +			return -ETIMEDOUT; +	} +	/* +	 * At this point either the tracing is enabled and in the right mode or +	 * disabled. +	 */ + +	idx *= (MPS_TRC_FILTER1_MATCH - MPS_TRC_FILTER0_MATCH); +	data_reg = MPS_TRC_FILTER0_MATCH + idx; +	mask_reg = MPS_TRC_FILTER0_DONT_CARE + idx; + +	for (i = 0; i < TRACE_LEN / 4; i++, data_reg += 4, mask_reg += 4) { +		t4_write_reg(adap, data_reg, tp->data[i]); +		t4_write_reg(adap, mask_reg, ~tp->mask[i]); +	} +	t4_write_reg(adap, MPS_TRC_FILTER_MATCH_CTL_B + ofst, +		     TFCAPTUREMAX(tp->snap_len) | +		     TFMINPKTSIZE(tp->min_len)); +	t4_write_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A + ofst, +		     TFOFFSET(tp->skip_ofst) | TFLENGTH(tp->skip_len) | +		     TFPORT(tp->port) | TFEN | +		     (tp->invert ? TFINVERTMATCH : 0)); + +	cfg &= ~TRCMULTIFILTER; +	t4_write_reg(adap, MPS_TRC_CFG, cfg | TRCEN | multitrc); +out:	t4_read_reg(adap, MPS_TRC_CFG);  /* flush */ +	return 0; +} + +/** + *	t4_get_trace_filter - query one of the tracing filters + *	@adap: the adapter + *	@tp: the current trace filter parameters + *	@idx: which trace filter to query + *	@enabled: non-zero if the filter is enabled + * + *	Returns the current settings of one of the HW tracing filters. + */ +void t4_get_trace_filter(struct adapter *adap, struct trace_params *tp, int idx, +			 int *enabled) +{ +	u32 ctla, ctlb; +	int i, ofst = idx * 4; +	u32 data_reg, mask_reg; + +	ctla = t4_read_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A + ofst); +	ctlb = t4_read_reg(adap, MPS_TRC_FILTER_MATCH_CTL_B + ofst); + +	*enabled = !!(ctla & TFEN); +	tp->snap_len = TFCAPTUREMAX_GET(ctlb); +	tp->min_len = TFMINPKTSIZE_GET(ctlb); +	tp->skip_ofst = TFOFFSET_GET(ctla); +	tp->skip_len = TFLENGTH_GET(ctla); +	tp->invert = !!(ctla & TFINVERTMATCH); +	tp->port = TFPORT_GET(ctla); + +	ofst = (MPS_TRC_FILTER1_MATCH - MPS_TRC_FILTER0_MATCH) * idx; +	data_reg = MPS_TRC_FILTER0_MATCH + ofst; +	mask_reg = MPS_TRC_FILTER0_DONT_CARE + ofst; + +	for (i = 0; i < TRACE_LEN / 4; i++, data_reg += 4, mask_reg += 4) { +		tp->mask[i] = ~t4_read_reg(adap, mask_reg); +		tp->data[i] = t4_read_reg(adap, data_reg) & tp->mask[i]; +	} +} + +/** + *	get_mps_bg_map - return the buffer groups associated with a port + *	@adap: the adapter + *	@idx: the port index + * + *	Returns a bitmap indicating which MPS buffer groups are associated + *	with the given port.  Bit i is set if buffer group i is used by the + *	port. + */ +static unsigned int get_mps_bg_map(struct adapter *adap, int idx) +{ +	u32 n = NUMPORTS_GET(t4_read_reg(adap, MPS_CMN_CTL)); + +	if (n == 0) +		return idx == 0 ? 0xf : 0; +	if (n == 1) +		return idx < 2 ? (3 << (2 * idx)) : 0; +	return 1 << idx; +} + +/** + *	t4_get_port_stats - collect port statistics + *	@adap: the adapter + *	@idx: the port index + *	@p: the stats structure to fill + * + *	Collect statistics related to the given port from HW. + */ +void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p) +{ +	u32 bgmap = get_mps_bg_map(adap, idx); + +#define GET_STAT(name) \ +	t4_read_reg64(adap, PORT_REG(idx, MPS_PORT_STAT_##name##_L)) +#define GET_STAT_COM(name) t4_read_reg64(adap, MPS_STAT_##name##_L) + +	p->tx_octets           = GET_STAT(TX_PORT_BYTES); +	p->tx_frames           = GET_STAT(TX_PORT_FRAMES); +	p->tx_bcast_frames     = GET_STAT(TX_PORT_BCAST); +	p->tx_mcast_frames     = GET_STAT(TX_PORT_MCAST); +	p->tx_ucast_frames     = GET_STAT(TX_PORT_UCAST); +	p->tx_error_frames     = GET_STAT(TX_PORT_ERROR); +	p->tx_frames_64        = GET_STAT(TX_PORT_64B); +	p->tx_frames_65_127    = GET_STAT(TX_PORT_65B_127B); +	p->tx_frames_128_255   = GET_STAT(TX_PORT_128B_255B); +	p->tx_frames_256_511   = GET_STAT(TX_PORT_256B_511B); +	p->tx_frames_512_1023  = GET_STAT(TX_PORT_512B_1023B); +	p->tx_frames_1024_1518 = GET_STAT(TX_PORT_1024B_1518B); +	p->tx_frames_1519_max  = GET_STAT(TX_PORT_1519B_MAX); +	p->tx_drop             = GET_STAT(TX_PORT_DROP); +	p->tx_pause            = GET_STAT(TX_PORT_PAUSE); +	p->tx_ppp0             = GET_STAT(TX_PORT_PPP0); +	p->tx_ppp1             = GET_STAT(TX_PORT_PPP1); +	p->tx_ppp2             = GET_STAT(TX_PORT_PPP2); +	p->tx_ppp3             = GET_STAT(TX_PORT_PPP3); +	p->tx_ppp4             = GET_STAT(TX_PORT_PPP4); +	p->tx_ppp5             = GET_STAT(TX_PORT_PPP5); +	p->tx_ppp6             = GET_STAT(TX_PORT_PPP6); +	p->tx_ppp7             = GET_STAT(TX_PORT_PPP7); + +	p->rx_octets           = GET_STAT(RX_PORT_BYTES); +	p->rx_frames           = GET_STAT(RX_PORT_FRAMES); +	p->rx_bcast_frames     = GET_STAT(RX_PORT_BCAST); +	p->rx_mcast_frames     = GET_STAT(RX_PORT_MCAST); +	p->rx_ucast_frames     = GET_STAT(RX_PORT_UCAST); +	p->rx_too_long         = GET_STAT(RX_PORT_MTU_ERROR); +	p->rx_jabber           = GET_STAT(RX_PORT_MTU_CRC_ERROR); +	p->rx_fcs_err          = GET_STAT(RX_PORT_CRC_ERROR); +	p->rx_len_err          = GET_STAT(RX_PORT_LEN_ERROR); +	p->rx_symbol_err       = GET_STAT(RX_PORT_SYM_ERROR); +	p->rx_runt             = GET_STAT(RX_PORT_LESS_64B); +	p->rx_frames_64        = GET_STAT(RX_PORT_64B); +	p->rx_frames_65_127    = GET_STAT(RX_PORT_65B_127B); +	p->rx_frames_128_255   = GET_STAT(RX_PORT_128B_255B); +	p->rx_frames_256_511   = GET_STAT(RX_PORT_256B_511B); +	p->rx_frames_512_1023  = GET_STAT(RX_PORT_512B_1023B); +	p->rx_frames_1024_1518 = GET_STAT(RX_PORT_1024B_1518B); +	p->rx_frames_1519_max  = GET_STAT(RX_PORT_1519B_MAX); +	p->rx_pause            = GET_STAT(RX_PORT_PAUSE); +	p->rx_ppp0             = GET_STAT(RX_PORT_PPP0); +	p->rx_ppp1             = GET_STAT(RX_PORT_PPP1); +	p->rx_ppp2             = GET_STAT(RX_PORT_PPP2); +	p->rx_ppp3             = GET_STAT(RX_PORT_PPP3); +	p->rx_ppp4             = GET_STAT(RX_PORT_PPP4); +	p->rx_ppp5             = GET_STAT(RX_PORT_PPP5); +	p->rx_ppp6             = GET_STAT(RX_PORT_PPP6); +	p->rx_ppp7             = GET_STAT(RX_PORT_PPP7); + +	p->rx_ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_MAC_DROP_FRAME) : 0; +	p->rx_ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_MAC_DROP_FRAME) : 0; +	p->rx_ovflow2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_MAC_DROP_FRAME) : 0; +	p->rx_ovflow3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_MAC_DROP_FRAME) : 0; +	p->rx_trunc0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_MAC_TRUNC_FRAME) : 0; +	p->rx_trunc1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_MAC_TRUNC_FRAME) : 0; +	p->rx_trunc2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_MAC_TRUNC_FRAME) : 0; +	p->rx_trunc3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_MAC_TRUNC_FRAME) : 0; + +#undef GET_STAT +#undef GET_STAT_COM +} + +/** + *	t4_get_lb_stats - collect loopback port statistics + *	@adap: the adapter + *	@idx: the loopback port index + *	@p: the stats structure to fill + * + *	Return HW statistics for the given loopback port. + */ +void t4_get_lb_stats(struct adapter *adap, int idx, struct lb_port_stats *p) +{ +	u32 bgmap = get_mps_bg_map(adap, idx); + +#define GET_STAT(name) \ +	t4_read_reg64(adap, PORT_REG(idx, MPS_PORT_STAT_LB_PORT_##name##_L)) +#define GET_STAT_COM(name) t4_read_reg64(adap, MPS_STAT_##name##_L) + +	p->octets           = GET_STAT(BYTES); +	p->frames           = GET_STAT(FRAMES); +	p->bcast_frames     = GET_STAT(BCAST); +	p->mcast_frames     = GET_STAT(MCAST); +	p->ucast_frames     = GET_STAT(UCAST); +	p->error_frames     = GET_STAT(ERROR); + +	p->frames_64        = GET_STAT(64B); +	p->frames_65_127    = GET_STAT(65B_127B); +	p->frames_128_255   = GET_STAT(128B_255B); +	p->frames_256_511   = GET_STAT(256B_511B); +	p->frames_512_1023  = GET_STAT(512B_1023B); +	p->frames_1024_1518 = GET_STAT(1024B_1518B); +	p->frames_1519_max  = GET_STAT(1519B_MAX); +	p->drop             = t4_read_reg(adap, PORT_REG(idx, +					  MPS_PORT_STAT_LB_PORT_DROP_FRAMES)); + +	p->ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_LB_DROP_FRAME) : 0; +	p->ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_LB_DROP_FRAME) : 0; +	p->ovflow2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_LB_DROP_FRAME) : 0; +	p->ovflow3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_LB_DROP_FRAME) : 0; +	p->trunc0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_LB_TRUNC_FRAME) : 0; +	p->trunc1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_LB_TRUNC_FRAME) : 0; +	p->trunc2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_LB_TRUNC_FRAME) : 0; +	p->trunc3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_LB_TRUNC_FRAME) : 0; + +#undef GET_STAT +#undef GET_STAT_COM +} + +/** + *	t4_wol_magic_enable - enable/disable magic packet WoL + *	@adap: the adapter + *	@port: the physical port index + *	@addr: MAC address expected in magic packets, %NULL to disable + * + *	Enables/disables magic packet wake-on-LAN for the selected port. + */ +void t4_wol_magic_enable(struct adapter *adap, unsigned int port, +			 const u8 *addr) +{ +	if (addr) { +		t4_write_reg(adap, PORT_REG(port, XGMAC_PORT_MAGIC_MACID_LO), +			     (addr[2] << 24) | (addr[3] << 16) | +			     (addr[4] << 8) | addr[5]); +		t4_write_reg(adap, PORT_REG(port, XGMAC_PORT_MAGIC_MACID_HI), +			     (addr[0] << 8) | addr[1]); +	} +	t4_set_reg_field(adap, PORT_REG(port, XGMAC_PORT_CFG2), MAGICEN, +			 addr ? MAGICEN : 0); +} + +/** + *	t4_wol_pat_enable - enable/disable pattern-based WoL + *	@adap: the adapter + *	@port: the physical port index + *	@map: bitmap of which HW pattern filters to set + *	@mask0: byte mask for bytes 0-63 of a packet + *	@mask1: byte mask for bytes 64-127 of a packet + *	@crc: Ethernet CRC for selected bytes + *	@enable: enable/disable switch + * + *	Sets the pattern filters indicated in @map to mask out the bytes + *	specified in @mask0/@mask1 in received packets and compare the CRC of + *	the resulting packet against @crc.  If @enable is %true pattern-based + *	WoL is enabled, otherwise disabled. + */ +int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map, +		      u64 mask0, u64 mask1, unsigned int crc, bool enable) +{ +	int i; + +	if (!enable) { +		t4_set_reg_field(adap, PORT_REG(port, XGMAC_PORT_CFG2), +				 PATEN, 0); +		return 0; +	} +	if (map > 0xff) +		return -EINVAL; + +#define EPIO_REG(name) PORT_REG(port, XGMAC_PORT_EPIO_##name) + +	t4_write_reg(adap, EPIO_REG(DATA1), mask0 >> 32); +	t4_write_reg(adap, EPIO_REG(DATA2), mask1); +	t4_write_reg(adap, EPIO_REG(DATA3), mask1 >> 32); + +	for (i = 0; i < NWOL_PAT; i++, map >>= 1) { +		if (!(map & 1)) +			continue; + +		/* write byte masks */ +		t4_write_reg(adap, EPIO_REG(DATA0), mask0); +		t4_write_reg(adap, EPIO_REG(OP), ADDRESS(i) | EPIOWR); +		t4_read_reg(adap, EPIO_REG(OP));                /* flush */ +		if (t4_read_reg(adap, EPIO_REG(OP)) & BUSY) +			return -ETIMEDOUT; + +		/* write CRC */ +		t4_write_reg(adap, EPIO_REG(DATA0), crc); +		t4_write_reg(adap, EPIO_REG(OP), ADDRESS(i + 32) | EPIOWR); +		t4_read_reg(adap, EPIO_REG(OP));                /* flush */ +		if (t4_read_reg(adap, EPIO_REG(OP)) & BUSY) +			return -ETIMEDOUT; +	} +#undef EPIO_REG + +	t4_set_reg_field(adap, PORT_REG(port, XGMAC_PORT_CFG2), 0, PATEN); +	return 0; +} + +#define INIT_CMD(var, cmd, rd_wr) do { \ +	(var).op_to_write = htonl(FW_CMD_OP(FW_##cmd##_CMD) | \ +				  FW_CMD_REQUEST | FW_CMD_##rd_wr); \ +	(var).retval_len16 = htonl(FW_LEN16(var)); \ +} while (0) + +/** + *	t4_mdio_rd - read a PHY register through MDIO + *	@adap: the adapter + *	@mbox: mailbox to use for the FW command + *	@phy_addr: the PHY address + *	@mmd: the PHY MMD to access (0 for clause 22 PHYs) + *	@reg: the register to read + *	@valp: where to store the value + * + *	Issues a FW command through the given mailbox to read a PHY register. + */ +int t4_mdio_rd(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, +	       unsigned int mmd, unsigned int reg, u16 *valp) +{ +	int ret; +	struct fw_ldst_cmd c; + +	memset(&c, 0, sizeof(c)); +	c.op_to_addrspace = htonl(FW_CMD_OP(FW_LDST_CMD) | FW_CMD_REQUEST | +		FW_CMD_READ | FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO)); +	c.cycles_to_len16 = htonl(FW_LEN16(c)); +	c.u.mdio.paddr_mmd = htons(FW_LDST_CMD_PADDR(phy_addr) | +				   FW_LDST_CMD_MMD(mmd)); +	c.u.mdio.raddr = htons(reg); + +	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); +	if (ret == 0) +		*valp = ntohs(c.u.mdio.rval); +	return ret; +} + +/** + *	t4_mdio_wr - write a PHY register through MDIO + *	@adap: the adapter + *	@mbox: mailbox to use for the FW command + *	@phy_addr: the PHY address + *	@mmd: the PHY MMD to access (0 for clause 22 PHYs) + *	@reg: the register to write + *	@valp: value to write + * + *	Issues a FW command through the given mailbox to write a PHY register. + */ +int t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, +	       unsigned int mmd, unsigned int reg, u16 val) +{ +	struct fw_ldst_cmd c; + +	memset(&c, 0, sizeof(c)); +	c.op_to_addrspace = htonl(FW_CMD_OP(FW_LDST_CMD) | FW_CMD_REQUEST | +		FW_CMD_WRITE | FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO)); +	c.cycles_to_len16 = htonl(FW_LEN16(c)); +	c.u.mdio.paddr_mmd = htons(FW_LDST_CMD_PADDR(phy_addr) | +				   FW_LDST_CMD_MMD(mmd)); +	c.u.mdio.raddr = htons(reg); +	c.u.mdio.rval = htons(val); + +	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + *	t4_fw_hello - establish communication with FW + *	@adap: the adapter + *	@mbox: mailbox to use for the FW command + *	@evt_mbox: mailbox to receive async FW events + *	@master: specifies the caller's willingness to be the device master + *	@state: returns the current device state + * + *	Issues a command to establish communication with FW. + */ +int t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox, +		enum dev_master master, enum dev_state *state) +{ +	int ret; +	struct fw_hello_cmd c; + +	INIT_CMD(c, HELLO, WRITE); +	c.err_to_mbasyncnot = htonl( +		FW_HELLO_CMD_MASTERDIS(master == MASTER_CANT) | +		FW_HELLO_CMD_MASTERFORCE(master == MASTER_MUST) | +		FW_HELLO_CMD_MBMASTER(master == MASTER_MUST ? mbox : 0xff) | +		FW_HELLO_CMD_MBASYNCNOT(evt_mbox)); + +	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); +	if (ret == 0 && state) { +		u32 v = ntohl(c.err_to_mbasyncnot); +		if (v & FW_HELLO_CMD_INIT) +			*state = DEV_STATE_INIT; +		else if (v & FW_HELLO_CMD_ERR) +			*state = DEV_STATE_ERR; +		else +			*state = DEV_STATE_UNINIT; +	} +	return ret; +} + +/** + *	t4_fw_bye - end communication with FW + *	@adap: the adapter + *	@mbox: mailbox to use for the FW command + * + *	Issues a command to terminate communication with FW. + */ +int t4_fw_bye(struct adapter *adap, unsigned int mbox) +{ +	struct fw_bye_cmd c; + +	INIT_CMD(c, BYE, WRITE); +	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + *	t4_init_cmd - ask FW to initialize the device + *	@adap: the adapter + *	@mbox: mailbox to use for the FW command + * + *	Issues a command to FW to partially initialize the device.  This + *	performs initialization that generally doesn't depend on user input. + */ +int t4_early_init(struct adapter *adap, unsigned int mbox) +{ +	struct fw_initialize_cmd c; + +	INIT_CMD(c, INITIALIZE, WRITE); +	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + *	t4_fw_reset - issue a reset to FW + *	@adap: the adapter + *	@mbox: mailbox to use for the FW command + *	@reset: specifies the type of reset to perform + * + *	Issues a reset command of the specified type to FW. + */ +int t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset) +{ +	struct fw_reset_cmd c; + +	INIT_CMD(c, RESET, WRITE); +	c.val = htonl(reset); +	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + *	t4_query_params - query FW or device parameters + *	@adap: the adapter + *	@mbox: mailbox to use for the FW command + *	@pf: the PF + *	@vf: the VF + *	@nparams: the number of parameters + *	@params: the parameter names + *	@val: the parameter values + * + *	Reads the value of FW or device parameters.  Up to 7 parameters can be + *	queried at once. + */ +int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf, +		    unsigned int vf, unsigned int nparams, const u32 *params, +		    u32 *val) +{ +	int i, ret; +	struct fw_params_cmd c; +	__be32 *p = &c.param[0].mnem; + +	if (nparams > 7) +		return -EINVAL; + +	memset(&c, 0, sizeof(c)); +	c.op_to_vfn = htonl(FW_CMD_OP(FW_PARAMS_CMD) | FW_CMD_REQUEST | +			    FW_CMD_READ | FW_PARAMS_CMD_PFN(pf) | +			    FW_PARAMS_CMD_VFN(vf)); +	c.retval_len16 = htonl(FW_LEN16(c)); +	for (i = 0; i < nparams; i++, p += 2) +		*p = htonl(*params++); + +	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); +	if (ret == 0) +		for (i = 0, p = &c.param[0].val; i < nparams; i++, p += 2) +			*val++ = ntohl(*p); +	return ret; +} + +/** + *	t4_set_params - sets FW or device parameters + *	@adap: the adapter + *	@mbox: mailbox to use for the FW command + *	@pf: the PF + *	@vf: the VF + *	@nparams: the number of parameters + *	@params: the parameter names + *	@val: the parameter values + * + *	Sets the value of FW or device parameters.  Up to 7 parameters can be + *	specified at once. + */ +int t4_set_params(struct adapter *adap, unsigned int mbox, unsigned int pf, +		  unsigned int vf, unsigned int nparams, const u32 *params, +		  const u32 *val) +{ +	struct fw_params_cmd c; +	__be32 *p = &c.param[0].mnem; + +	if (nparams > 7) +		return -EINVAL; + +	memset(&c, 0, sizeof(c)); +	c.op_to_vfn = htonl(FW_CMD_OP(FW_PARAMS_CMD) | FW_CMD_REQUEST | +			    FW_CMD_WRITE | FW_PARAMS_CMD_PFN(pf) | +			    FW_PARAMS_CMD_VFN(vf)); +	c.retval_len16 = htonl(FW_LEN16(c)); +	while (nparams--) { +		*p++ = htonl(*params++); +		*p++ = htonl(*val++); +	} + +	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + *	t4_cfg_pfvf - configure PF/VF resource limits + *	@adap: the adapter + *	@mbox: mailbox to use for the FW command + *	@pf: the PF being configured + *	@vf: the VF being configured + *	@txq: the max number of egress queues + *	@txq_eth_ctrl: the max number of egress Ethernet or control queues + *	@rxqi: the max number of interrupt-capable ingress queues + *	@rxq: the max number of interruptless ingress queues + *	@tc: the PCI traffic class + *	@vi: the max number of virtual interfaces + *	@cmask: the channel access rights mask for the PF/VF + *	@pmask: the port access rights mask for the PF/VF + *	@nexact: the maximum number of exact MPS filters + *	@rcaps: read capabilities + *	@wxcaps: write/execute capabilities + * + *	Configures resource limits and capabilities for a physical or virtual + *	function. + */ +int t4_cfg_pfvf(struct adapter *adap, unsigned int mbox, unsigned int pf, +		unsigned int vf, unsigned int txq, unsigned int txq_eth_ctrl, +		unsigned int rxqi, unsigned int rxq, unsigned int tc, +		unsigned int vi, unsigned int cmask, unsigned int pmask, +		unsigned int nexact, unsigned int rcaps, unsigned int wxcaps) +{ +	struct fw_pfvf_cmd c; + +	memset(&c, 0, sizeof(c)); +	c.op_to_vfn = htonl(FW_CMD_OP(FW_PFVF_CMD) | FW_CMD_REQUEST | +			    FW_CMD_WRITE | FW_PFVF_CMD_PFN(pf) | +			    FW_PFVF_CMD_VFN(vf)); +	c.retval_len16 = htonl(FW_LEN16(c)); +	c.niqflint_niq = htonl(FW_PFVF_CMD_NIQFLINT(rxqi) | +			       FW_PFVF_CMD_NIQ(rxq)); +	c.cmask_to_neq = htonl(FW_PFVF_CMD_CMASK(cmask) | +			       FW_PFVF_CMD_PMASK(pmask) | +			       FW_PFVF_CMD_NEQ(txq)); +	c.tc_to_nexactf = htonl(FW_PFVF_CMD_TC(tc) | FW_PFVF_CMD_NVI(vi) | +				FW_PFVF_CMD_NEXACTF(nexact)); +	c.r_caps_to_nethctrl = htonl(FW_PFVF_CMD_R_CAPS(rcaps) | +				     FW_PFVF_CMD_WX_CAPS(wxcaps) | +				     FW_PFVF_CMD_NETHCTRL(txq_eth_ctrl)); +	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + *	t4_alloc_vi - allocate a virtual interface + *	@adap: the adapter + *	@mbox: mailbox to use for the FW command + *	@port: physical port associated with the VI + *	@pf: the PF owning the VI + *	@vf: the VF owning the VI + *	@nmac: number of MAC addresses needed (1 to 5) + *	@mac: the MAC addresses of the VI + *	@rss_size: size of RSS table slice associated with this VI + * + *	Allocates a virtual interface for the given physical port.  If @mac is + *	not %NULL it contains the MAC addresses of the VI as assigned by FW. + *	@mac should be large enough to hold @nmac Ethernet addresses, they are + *	stored consecutively so the space needed is @nmac * 6 bytes. + *	Returns a negative error number or the non-negative VI id. + */ +int t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port, +		unsigned int pf, unsigned int vf, unsigned int nmac, u8 *mac, +		unsigned int *rss_size) +{ +	int ret; +	struct fw_vi_cmd c; + +	memset(&c, 0, sizeof(c)); +	c.op_to_vfn = htonl(FW_CMD_OP(FW_VI_CMD) | FW_CMD_REQUEST | +			    FW_CMD_WRITE | FW_CMD_EXEC | +			    FW_VI_CMD_PFN(pf) | FW_VI_CMD_VFN(vf)); +	c.alloc_to_len16 = htonl(FW_VI_CMD_ALLOC | FW_LEN16(c)); +	c.portid_pkd = FW_VI_CMD_PORTID(port); +	c.nmac = nmac - 1; + +	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); +	if (ret) +		return ret; + +	if (mac) { +		memcpy(mac, c.mac, sizeof(c.mac)); +		switch (nmac) { +		case 5: +			memcpy(mac + 24, c.nmac3, sizeof(c.nmac3)); +		case 4: +			memcpy(mac + 18, c.nmac2, sizeof(c.nmac2)); +		case 3: +			memcpy(mac + 12, c.nmac1, sizeof(c.nmac1)); +		case 2: +			memcpy(mac + 6,  c.nmac0, sizeof(c.nmac0)); +		} +	} +	if (rss_size) +		*rss_size = FW_VI_CMD_RSSSIZE_GET(ntohs(c.rsssize_pkd)); +	return ntohs(c.viid_pkd); +} + +/** + *	t4_free_vi - free a virtual interface + *	@adap: the adapter + *	@mbox: mailbox to use for the FW command + *	@pf: the PF owning the VI + *	@vf: the VF owning the VI + *	@viid: virtual interface identifiler + * + *	Free a previously allocated virtual interface. + */ +int t4_free_vi(struct adapter *adap, unsigned int mbox, unsigned int pf, +	       unsigned int vf, unsigned int viid) +{ +	struct fw_vi_cmd c; + +	memset(&c, 0, sizeof(c)); +	c.op_to_vfn = htonl(FW_CMD_OP(FW_VI_CMD) | FW_CMD_REQUEST | +			    FW_CMD_EXEC | FW_VI_CMD_PFN(pf) | +			    FW_VI_CMD_VFN(vf)); +	c.alloc_to_len16 = htonl(FW_VI_CMD_FREE | FW_LEN16(c)); +	c.viid_pkd = htons(FW_VI_CMD_VIID(viid)); +	return t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); +} + +/** + *	t4_set_rxmode - set Rx properties of a virtual interface + *	@adap: the adapter + *	@mbox: mailbox to use for the FW command + *	@viid: the VI id + *	@mtu: the new MTU or -1 + *	@promisc: 1 to enable promiscuous mode, 0 to disable it, -1 no change + *	@all_multi: 1 to enable all-multi mode, 0 to disable it, -1 no change + *	@bcast: 1 to enable broadcast Rx, 0 to disable it, -1 no change + *	@sleep_ok: if true we may sleep while awaiting command completion + * + *	Sets Rx properties of a virtual interface. + */ +int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid, +		  int mtu, int promisc, int all_multi, int bcast, bool sleep_ok) +{ +	struct fw_vi_rxmode_cmd c; + +	/* convert to FW values */ +	if (mtu < 0) +		mtu = FW_RXMODE_MTU_NO_CHG; +	if (promisc < 0) +		promisc = FW_VI_RXMODE_CMD_PROMISCEN_MASK; +	if (all_multi < 0) +		all_multi = FW_VI_RXMODE_CMD_ALLMULTIEN_MASK; +	if (bcast < 0) +		bcast = FW_VI_RXMODE_CMD_BROADCASTEN_MASK; + +	memset(&c, 0, sizeof(c)); +	c.op_to_viid = htonl(FW_CMD_OP(FW_VI_RXMODE_CMD) | FW_CMD_REQUEST | +			     FW_CMD_WRITE | FW_VI_RXMODE_CMD_VIID(viid)); +	c.retval_len16 = htonl(FW_LEN16(c)); +	c.mtu_to_broadcasten = htonl(FW_VI_RXMODE_CMD_MTU(mtu) | +				     FW_VI_RXMODE_CMD_PROMISCEN(promisc) | +				     FW_VI_RXMODE_CMD_ALLMULTIEN(all_multi) | +				     FW_VI_RXMODE_CMD_BROADCASTEN(bcast)); +	return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok); +} + +/** + *	t4_alloc_mac_filt - allocates exact-match filters for MAC addresses + *	@adap: the adapter + *	@mbox: mailbox to use for the FW command + *	@viid: the VI id + *	@free: if true any existing filters for this VI id are first removed + *	@naddr: the number of MAC addresses to allocate filters for (up to 7) + *	@addr: the MAC address(es) + *	@idx: where to store the index of each allocated filter + *	@hash: pointer to hash address filter bitmap + *	@sleep_ok: call is allowed to sleep + * + *	Allocates an exact-match filter for each of the supplied addresses and + *	sets it to the corresponding address.  If @idx is not %NULL it should + *	have at least @naddr entries, each of which will be set to the index of + *	the filter allocated for the corresponding MAC address.  If a filter + *	could not be allocated for an address its index is set to 0xffff. + *	If @hash is not %NULL addresses that fail to allocate an exact filter + *	are hashed and update the hash filter bitmap pointed at by @hash. + * + *	Returns a negative error number or the number of filters allocated. + */ +int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox, +		      unsigned int viid, bool free, unsigned int naddr, +		      const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok) +{ +	int i, ret; +	struct fw_vi_mac_cmd c; +	struct fw_vi_mac_exact *p; + +	if (naddr > 7) +		return -EINVAL; + +	memset(&c, 0, sizeof(c)); +	c.op_to_viid = htonl(FW_CMD_OP(FW_VI_MAC_CMD) | FW_CMD_REQUEST | +			     FW_CMD_WRITE | (free ? FW_CMD_EXEC : 0) | +			     FW_VI_MAC_CMD_VIID(viid)); +	c.freemacs_to_len16 = htonl(FW_VI_MAC_CMD_FREEMACS(free) | +				    FW_CMD_LEN16((naddr + 2) / 2)); + +	for (i = 0, p = c.u.exact; i < naddr; i++, p++) { +		p->valid_to_idx = htons(FW_VI_MAC_CMD_VALID | +				      FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC)); +		memcpy(p->macaddr, addr[i], sizeof(p->macaddr)); +	} + +	ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok); +	if (ret) +		return ret; + +	for (i = 0, p = c.u.exact; i < naddr; i++, p++) { +		u16 index = FW_VI_MAC_CMD_IDX_GET(ntohs(p->valid_to_idx)); + +		if (idx) +			idx[i] = index >= NEXACT_MAC ? 0xffff : index; +		if (index < NEXACT_MAC) +			ret++; +		else if (hash) +			*hash |= (1 << hash_mac_addr(addr[i])); +	} +	return ret; +} + +/** + *	t4_change_mac - modifies the exact-match filter for a MAC address + *	@adap: the adapter + *	@mbox: mailbox to use for the FW command + *	@viid: the VI id + *	@idx: index of existing filter for old value of MAC address, or -1 + *	@addr: the new MAC address value + *	@persist: whether a new MAC allocation should be persistent + *	@add_smt: if true also add the address to the HW SMT + * + *	Modifies an exact-match filter and sets it to the new MAC address. + *	Note that in general it is not possible to modify the value of a given + *	filter so the generic way to modify an address filter is to free the one + *	being used by the old address value and allocate a new filter for the + *	new address value.  @idx can be -1 if the address is a new addition. + * + *	Returns a negative error number or the index of the filter with the new + *	MAC value. + */ +int t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid, +		  int idx, const u8 *addr, bool persist, bool add_smt) +{ +	int ret, mode; +	struct fw_vi_mac_cmd c; +	struct fw_vi_mac_exact *p = c.u.exact; + +	if (idx < 0)                             /* new allocation */ +		idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC; +	mode = add_smt ? FW_VI_MAC_SMT_AND_MPSTCAM : FW_VI_MAC_MPS_TCAM_ENTRY; + +	memset(&c, 0, sizeof(c)); +	c.op_to_viid = htonl(FW_CMD_OP(FW_VI_MAC_CMD) | FW_CMD_REQUEST | +			     FW_CMD_WRITE | FW_VI_MAC_CMD_VIID(viid)); +	c.freemacs_to_len16 = htonl(FW_CMD_LEN16(1)); +	p->valid_to_idx = htons(FW_VI_MAC_CMD_VALID | +				FW_VI_MAC_CMD_SMAC_RESULT(mode) | +				FW_VI_MAC_CMD_IDX(idx)); +	memcpy(p->macaddr, addr, sizeof(p->macaddr)); + +	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); +	if (ret == 0) { +		ret = FW_VI_MAC_CMD_IDX_GET(ntohs(p->valid_to_idx)); +		if (ret >= NEXACT_MAC) +			ret = -ENOMEM; +	} +	return ret; +} + +/** + *	t4_set_addr_hash - program the MAC inexact-match hash filter + *	@adap: the adapter + *	@mbox: mailbox to use for the FW command + *	@viid: the VI id + *	@ucast: whether the hash filter should also match unicast addresses + *	@vec: the value to be written to the hash filter + *	@sleep_ok: call is allowed to sleep + * + *	Sets the 64-bit inexact-match hash filter for a virtual interface. + */ +int t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid, +		     bool ucast, u64 vec, bool sleep_ok) +{ +	struct fw_vi_mac_cmd c; + +	memset(&c, 0, sizeof(c)); +	c.op_to_viid = htonl(FW_CMD_OP(FW_VI_MAC_CMD) | FW_CMD_REQUEST | +			     FW_CMD_WRITE | FW_VI_ENABLE_CMD_VIID(viid)); +	c.freemacs_to_len16 = htonl(FW_VI_MAC_CMD_HASHVECEN | +				    FW_VI_MAC_CMD_HASHUNIEN(ucast) | +				    FW_CMD_LEN16(1)); +	c.u.hash.hashvec = cpu_to_be64(vec); +	return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok); +} + +/** + *	t4_enable_vi - enable/disable a virtual interface + *	@adap: the adapter + *	@mbox: mailbox to use for the FW command + *	@viid: the VI id + *	@rx_en: 1=enable Rx, 0=disable Rx + *	@tx_en: 1=enable Tx, 0=disable Tx + * + *	Enables/disables a virtual interface. + */ +int t4_enable_vi(struct adapter *adap, unsigned int mbox, unsigned int viid, +		 bool rx_en, bool tx_en) +{ +	struct fw_vi_enable_cmd c; + +	memset(&c, 0, sizeof(c)); +	c.op_to_viid = htonl(FW_CMD_OP(FW_VI_ENABLE_CMD) | FW_CMD_REQUEST | +			     FW_CMD_EXEC | FW_VI_ENABLE_CMD_VIID(viid)); +	c.ien_to_len16 = htonl(FW_VI_ENABLE_CMD_IEN(rx_en) | +			       FW_VI_ENABLE_CMD_EEN(tx_en) | FW_LEN16(c)); +	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + *	t4_identify_port - identify a VI's port by blinking its LED + *	@adap: the adapter + *	@mbox: mailbox to use for the FW command + *	@viid: the VI id + *	@nblinks: how many times to blink LED at 2.5 Hz + * + *	Identifies a VI's port by blinking its LED. + */ +int t4_identify_port(struct adapter *adap, unsigned int mbox, unsigned int viid, +		     unsigned int nblinks) +{ +	struct fw_vi_enable_cmd c; + +	c.op_to_viid = htonl(FW_CMD_OP(FW_VI_ENABLE_CMD) | FW_CMD_REQUEST | +			     FW_CMD_EXEC | FW_VI_ENABLE_CMD_VIID(viid)); +	c.ien_to_len16 = htonl(FW_VI_ENABLE_CMD_LED | FW_LEN16(c)); +	c.blinkdur = htons(nblinks); +	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + *	t4_iq_start_stop - enable/disable an ingress queue and its FLs + *	@adap: the adapter + *	@mbox: mailbox to use for the FW command + *	@start: %true to enable the queues, %false to disable them + *	@pf: the PF owning the queues + *	@vf: the VF owning the queues + *	@iqid: ingress queue id + *	@fl0id: FL0 queue id or 0xffff if no attached FL0 + *	@fl1id: FL1 queue id or 0xffff if no attached FL1 + * + *	Starts or stops an ingress queue and its associated FLs, if any. + */ +int t4_iq_start_stop(struct adapter *adap, unsigned int mbox, bool start, +		     unsigned int pf, unsigned int vf, unsigned int iqid, +		     unsigned int fl0id, unsigned int fl1id) +{ +	struct fw_iq_cmd c; + +	memset(&c, 0, sizeof(c)); +	c.op_to_vfn = htonl(FW_CMD_OP(FW_IQ_CMD) | FW_CMD_REQUEST | +			    FW_CMD_EXEC | FW_IQ_CMD_PFN(pf) | +			    FW_IQ_CMD_VFN(vf)); +	c.alloc_to_len16 = htonl(FW_IQ_CMD_IQSTART(start) | +				 FW_IQ_CMD_IQSTOP(!start) | FW_LEN16(c)); +	c.iqid = htons(iqid); +	c.fl0id = htons(fl0id); +	c.fl1id = htons(fl1id); +	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + *	t4_iq_free - free an ingress queue and its FLs + *	@adap: the adapter + *	@mbox: mailbox to use for the FW command + *	@pf: the PF owning the queues + *	@vf: the VF owning the queues + *	@iqtype: the ingress queue type + *	@iqid: ingress queue id + *	@fl0id: FL0 queue id or 0xffff if no attached FL0 + *	@fl1id: FL1 queue id or 0xffff if no attached FL1 + * + *	Frees an ingress queue and its associated FLs, if any. + */ +int t4_iq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, +	       unsigned int vf, unsigned int iqtype, unsigned int iqid, +	       unsigned int fl0id, unsigned int fl1id) +{ +	struct fw_iq_cmd c; + +	memset(&c, 0, sizeof(c)); +	c.op_to_vfn = htonl(FW_CMD_OP(FW_IQ_CMD) | FW_CMD_REQUEST | +			    FW_CMD_EXEC | FW_IQ_CMD_PFN(pf) | +			    FW_IQ_CMD_VFN(vf)); +	c.alloc_to_len16 = htonl(FW_IQ_CMD_FREE | FW_LEN16(c)); +	c.type_to_iqandstindex = htonl(FW_IQ_CMD_TYPE(iqtype)); +	c.iqid = htons(iqid); +	c.fl0id = htons(fl0id); +	c.fl1id = htons(fl1id); +	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + *	t4_eth_eq_free - free an Ethernet egress queue + *	@adap: the adapter + *	@mbox: mailbox to use for the FW command + *	@pf: the PF owning the queue + *	@vf: the VF owning the queue + *	@eqid: egress queue id + * + *	Frees an Ethernet egress queue. + */ +int t4_eth_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, +		   unsigned int vf, unsigned int eqid) +{ +	struct fw_eq_eth_cmd c; + +	memset(&c, 0, sizeof(c)); +	c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_ETH_CMD) | FW_CMD_REQUEST | +			    FW_CMD_EXEC | FW_EQ_ETH_CMD_PFN(pf) | +			    FW_EQ_ETH_CMD_VFN(vf)); +	c.alloc_to_len16 = htonl(FW_EQ_ETH_CMD_FREE | FW_LEN16(c)); +	c.eqid_pkd = htonl(FW_EQ_ETH_CMD_EQID(eqid)); +	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + *	t4_ctrl_eq_free - free a control egress queue + *	@adap: the adapter + *	@mbox: mailbox to use for the FW command + *	@pf: the PF owning the queue + *	@vf: the VF owning the queue + *	@eqid: egress queue id + * + *	Frees a control egress queue. + */ +int t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, +		    unsigned int vf, unsigned int eqid) +{ +	struct fw_eq_ctrl_cmd c; + +	memset(&c, 0, sizeof(c)); +	c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_CTRL_CMD) | FW_CMD_REQUEST | +			    FW_CMD_EXEC | FW_EQ_CTRL_CMD_PFN(pf) | +			    FW_EQ_CTRL_CMD_VFN(vf)); +	c.alloc_to_len16 = htonl(FW_EQ_CTRL_CMD_FREE | FW_LEN16(c)); +	c.cmpliqid_eqid = htonl(FW_EQ_CTRL_CMD_EQID(eqid)); +	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + *	t4_ofld_eq_free - free an offload egress queue + *	@adap: the adapter + *	@mbox: mailbox to use for the FW command + *	@pf: the PF owning the queue + *	@vf: the VF owning the queue + *	@eqid: egress queue id + * + *	Frees a control egress queue. + */ +int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, +		    unsigned int vf, unsigned int eqid) +{ +	struct fw_eq_ofld_cmd c; + +	memset(&c, 0, sizeof(c)); +	c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_OFLD_CMD) | FW_CMD_REQUEST | +			    FW_CMD_EXEC | FW_EQ_OFLD_CMD_PFN(pf) | +			    FW_EQ_OFLD_CMD_VFN(vf)); +	c.alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_FREE | FW_LEN16(c)); +	c.eqid_pkd = htonl(FW_EQ_OFLD_CMD_EQID(eqid)); +	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + *	t4_handle_fw_rpl - process a FW reply message + *	@adap: the adapter + *	@rpl: start of the FW message + * + *	Processes a FW message, such as link state change messages. + */ +int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl) +{ +	u8 opcode = *(const u8 *)rpl; + +	if (opcode == FW_PORT_CMD) {    /* link/module state change message */ +		int speed = 0, fc = 0; +		const struct fw_port_cmd *p = (void *)rpl; +		int chan = FW_PORT_CMD_PORTID_GET(ntohl(p->op_to_portid)); +		int port = adap->chan_map[chan]; +		struct port_info *pi = adap2pinfo(adap, port); +		struct link_config *lc = &pi->link_cfg; +		u32 stat = ntohl(p->u.info.lstatus_to_modtype); +		int link_ok = (stat & FW_PORT_CMD_LSTATUS) != 0; +		u32 mod = FW_PORT_CMD_MODTYPE_GET(stat); + +		if (stat & FW_PORT_CMD_RXPAUSE) +			fc |= PAUSE_RX; +		if (stat & FW_PORT_CMD_TXPAUSE) +			fc |= PAUSE_TX; +		if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M)) +			speed = SPEED_100; +		else if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G)) +			speed = SPEED_1000; +		else if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G)) +			speed = SPEED_10000; + +		if (link_ok != lc->link_ok || speed != lc->speed || +		    fc != lc->fc) {                    /* something changed */ +			lc->link_ok = link_ok; +			lc->speed = speed; +			lc->fc = fc; +			t4_os_link_changed(adap, port, link_ok); +		} +		if (mod != pi->mod_type) { +			pi->mod_type = mod; +			t4_os_portmod_changed(adap, port); +		} +	} +	return 0; +} + +static void __devinit get_pci_mode(struct adapter *adapter, +				   struct pci_params *p) +{ +	u16 val; +	u32 pcie_cap = pci_pcie_cap(adapter->pdev); + +	if (pcie_cap) { +		pci_read_config_word(adapter->pdev, pcie_cap + PCI_EXP_LNKSTA, +				     &val); +		p->speed = val & PCI_EXP_LNKSTA_CLS; +		p->width = (val & PCI_EXP_LNKSTA_NLW) >> 4; +	} +} + +/** + *	init_link_config - initialize a link's SW state + *	@lc: structure holding the link state + *	@caps: link capabilities + * + *	Initializes the SW state maintained for each link, including the link's + *	capabilities and default speed/flow-control/autonegotiation settings. + */ +static void __devinit init_link_config(struct link_config *lc, +				       unsigned int caps) +{ +	lc->supported = caps; +	lc->requested_speed = 0; +	lc->speed = 0; +	lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX; +	if (lc->supported & FW_PORT_CAP_ANEG) { +		lc->advertising = lc->supported & ADVERT_MASK; +		lc->autoneg = AUTONEG_ENABLE; +		lc->requested_fc |= PAUSE_AUTONEG; +	} else { +		lc->advertising = 0; +		lc->autoneg = AUTONEG_DISABLE; +	} +} + +static int __devinit wait_dev_ready(struct adapter *adap) +{ +	if (t4_read_reg(adap, PL_WHOAMI) != 0xffffffff) +		return 0; +	msleep(500); +	return t4_read_reg(adap, PL_WHOAMI) != 0xffffffff ? 0 : -EIO; +} + +/** + *	t4_prep_adapter - prepare SW and HW for operation + *	@adapter: the adapter + *	@reset: if true perform a HW reset + * + *	Initialize adapter SW state for the various HW modules, set initial + *	values for some adapter tunables, take PHYs out of reset, and + *	initialize the MDIO interface. + */ +int __devinit t4_prep_adapter(struct adapter *adapter) +{ +	int ret; + +	ret = wait_dev_ready(adapter); +	if (ret < 0) +		return ret; + +	get_pci_mode(adapter, &adapter->params.pci); +	adapter->params.rev = t4_read_reg(adapter, PL_REV); + +	ret = get_vpd_params(adapter, &adapter->params.vpd); +	if (ret < 0) +		return ret; + +	init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd); + +	/* +	 * Default port for debugging in case we can't reach FW. +	 */ +	adapter->params.nports = 1; +	adapter->params.portvec = 1; +	return 0; +} + +int __devinit t4_port_init(struct adapter *adap, int mbox, int pf, int vf) +{ +	u8 addr[6]; +	int ret, i, j = 0; +	struct fw_port_cmd c; + +	memset(&c, 0, sizeof(c)); + +	for_each_port(adap, i) { +		unsigned int rss_size; +		struct port_info *p = adap2pinfo(adap, i); + +		while ((adap->params.portvec & (1 << j)) == 0) +			j++; + +		c.op_to_portid = htonl(FW_CMD_OP(FW_PORT_CMD) | +				       FW_CMD_REQUEST | FW_CMD_READ | +				       FW_PORT_CMD_PORTID(j)); +		c.action_to_len16 = htonl( +			FW_PORT_CMD_ACTION(FW_PORT_ACTION_GET_PORT_INFO) | +			FW_LEN16(c)); +		ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); +		if (ret) +			return ret; + +		ret = t4_alloc_vi(adap, mbox, j, pf, vf, 1, addr, &rss_size); +		if (ret < 0) +			return ret; + +		p->viid = ret; +		p->tx_chan = j; +		p->lport = j; +		p->rss_size = rss_size; +		memcpy(adap->port[i]->dev_addr, addr, ETH_ALEN); +		memcpy(adap->port[i]->perm_addr, addr, ETH_ALEN); + +		ret = ntohl(c.u.info.lstatus_to_modtype); +		p->mdio_addr = (ret & FW_PORT_CMD_MDIOCAP) ? +			FW_PORT_CMD_MDIOADDR_GET(ret) : -1; +		p->port_type = FW_PORT_CMD_PTYPE_GET(ret); +		p->mod_type = FW_PORT_CMD_MODTYPE_GET(ret); + +		init_link_config(&p->link_cfg, ntohs(c.u.info.pcap)); +		j++; +	} +	return 0; +} diff --git a/drivers/net/cxgb4/t4_hw.h b/drivers/net/cxgb4/t4_hw.h new file mode 100644 index 00000000000..025623285c9 --- /dev/null +++ b/drivers/net/cxgb4/t4_hw.h @@ -0,0 +1,100 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses.  You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + *     Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *      - Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + * + *      - Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __T4_HW_H +#define __T4_HW_H + +#include <linux/types.h> + +enum { +	NCHAN          = 4,     /* # of HW channels */ +	MAX_MTU        = 9600,  /* max MAC MTU, excluding header + FCS */ +	EEPROMSIZE     = 17408, /* Serial EEPROM physical size */ +	EEPROMVSIZE    = 32768, /* Serial EEPROM virtual address space size */ +	RSS_NENTRIES   = 2048,  /* # of entries in RSS mapping table */ +	TCB_SIZE       = 128,   /* TCB size */ +	NMTUS          = 16,    /* size of MTU table */ +	NCCTRL_WIN     = 32,    /* # of congestion control windows */ +	NEXACT_MAC     = 336,   /* # of exact MAC address filters */ +	L2T_SIZE       = 4096,  /* # of L2T entries */ +	MBOX_LEN       = 64,    /* mailbox size in bytes */ +	TRACE_LEN      = 112,   /* length of trace data and mask */ +	FILTER_OPT_LEN = 36,    /* filter tuple width for optional components */ +	NWOL_PAT       = 8,     /* # of WoL patterns */ +	WOL_PAT_LEN    = 128,   /* length of WoL patterns */ +}; + +enum { +	SF_PAGE_SIZE = 256,           /* serial flash page size */ +	SF_SEC_SIZE = 64 * 1024,      /* serial flash sector size */ +	SF_SIZE = SF_SEC_SIZE * 16,   /* serial flash size */ +}; + +enum { RSP_TYPE_FLBUF, RSP_TYPE_CPL, RSP_TYPE_INTR }; /* response entry types */ + +enum { MBOX_OWNER_NONE, MBOX_OWNER_FW, MBOX_OWNER_DRV };    /* mailbox owners */ + +enum { +	SGE_MAX_WR_LEN = 512,     /* max WR size in bytes */ +	SGE_NTIMERS = 6,          /* # of interrupt holdoff timer values */ +	SGE_NCOUNTERS = 4,        /* # of interrupt packet counter values */ +}; + +struct sge_qstat {                /* data written to SGE queue status entries */ +	__be32 qid; +	__be16 cidx; +	__be16 pidx; +}; + +/* + * Structure for last 128 bits of response descriptors + */ +struct rsp_ctrl { +	__be32 hdrbuflen_pidx; +	__be32 pldbuflen_qid; +	union { +		u8 type_gen; +		__be64 last_flit; +	}; +}; + +#define RSPD_NEWBUF 0x80000000U +#define RSPD_LEN    0x7fffffffU + +#define RSPD_GEN(x)  ((x) >> 7) +#define RSPD_TYPE(x) (((x) >> 4) & 3) + +#define QINTR_CNT_EN       0x1 +#define QINTR_TIMER_IDX(x) ((x) << 1) +#endif /* __T4_HW_H */ diff --git a/drivers/net/cxgb4/t4_msg.h b/drivers/net/cxgb4/t4_msg.h new file mode 100644 index 00000000000..fdb11744314 --- /dev/null +++ b/drivers/net/cxgb4/t4_msg.h @@ -0,0 +1,664 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses.  You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + *     Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *      - Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + * + *      - Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __T4_MSG_H +#define __T4_MSG_H + +#include <linux/types.h> + +enum { +	CPL_PASS_OPEN_REQ     = 0x1, +	CPL_PASS_ACCEPT_RPL   = 0x2, +	CPL_ACT_OPEN_REQ      = 0x3, +	CPL_SET_TCB_FIELD     = 0x5, +	CPL_GET_TCB           = 0x6, +	CPL_CLOSE_CON_REQ     = 0x8, +	CPL_CLOSE_LISTSRV_REQ = 0x9, +	CPL_ABORT_REQ         = 0xA, +	CPL_ABORT_RPL         = 0xB, +	CPL_RX_DATA_ACK       = 0xD, +	CPL_TX_PKT            = 0xE, +	CPL_L2T_WRITE_REQ     = 0x12, +	CPL_TID_RELEASE       = 0x1A, + +	CPL_CLOSE_LISTSRV_RPL = 0x20, +	CPL_L2T_WRITE_RPL     = 0x23, +	CPL_PASS_OPEN_RPL     = 0x24, +	CPL_ACT_OPEN_RPL      = 0x25, +	CPL_PEER_CLOSE        = 0x26, +	CPL_ABORT_REQ_RSS     = 0x2B, +	CPL_ABORT_RPL_RSS     = 0x2D, + +	CPL_CLOSE_CON_RPL     = 0x32, +	CPL_ISCSI_HDR         = 0x33, +	CPL_RDMA_CQE          = 0x35, +	CPL_RDMA_CQE_READ_RSP = 0x36, +	CPL_RDMA_CQE_ERR      = 0x37, +	CPL_RX_DATA           = 0x39, +	CPL_SET_TCB_RPL       = 0x3A, +	CPL_RX_PKT            = 0x3B, +	CPL_RX_DDP_COMPLETE   = 0x3F, + +	CPL_ACT_ESTABLISH     = 0x40, +	CPL_PASS_ESTABLISH    = 0x41, +	CPL_RX_DATA_DDP       = 0x42, +	CPL_PASS_ACCEPT_REQ   = 0x44, + +	CPL_RDMA_READ_REQ     = 0x60, + +	CPL_PASS_OPEN_REQ6    = 0x81, +	CPL_ACT_OPEN_REQ6     = 0x83, + +	CPL_RDMA_TERMINATE    = 0xA2, +	CPL_RDMA_WRITE        = 0xA4, +	CPL_SGE_EGR_UPDATE    = 0xA5, + +	CPL_TRACE_PKT         = 0xB0, + +	CPL_FW4_MSG           = 0xC0, +	CPL_FW4_PLD           = 0xC1, +	CPL_FW4_ACK           = 0xC3, + +	CPL_FW6_MSG           = 0xE0, +	CPL_FW6_PLD           = 0xE1, +	CPL_TX_PKT_LSO        = 0xED, +	CPL_TX_PKT_XT         = 0xEE, + +	NUM_CPL_CMDS +}; + +enum CPL_error { +	CPL_ERR_NONE               = 0, +	CPL_ERR_TCAM_FULL          = 3, +	CPL_ERR_BAD_LENGTH         = 15, +	CPL_ERR_BAD_ROUTE          = 18, +	CPL_ERR_CONN_RESET         = 20, +	CPL_ERR_CONN_EXIST_SYNRECV = 21, +	CPL_ERR_CONN_EXIST         = 22, +	CPL_ERR_ARP_MISS           = 23, +	CPL_ERR_BAD_SYN            = 24, +	CPL_ERR_CONN_TIMEDOUT      = 30, +	CPL_ERR_XMIT_TIMEDOUT      = 31, +	CPL_ERR_PERSIST_TIMEDOUT   = 32, +	CPL_ERR_FINWAIT2_TIMEDOUT  = 33, +	CPL_ERR_KEEPALIVE_TIMEDOUT = 34, +	CPL_ERR_RTX_NEG_ADVICE     = 35, +	CPL_ERR_PERSIST_NEG_ADVICE = 36, +	CPL_ERR_ABORT_FAILED       = 42, +	CPL_ERR_IWARP_FLM          = 50, +}; + +enum { +	ULP_MODE_NONE          = 0, +	ULP_MODE_ISCSI         = 2, +	ULP_MODE_RDMA          = 4, +	ULP_MODE_FCOE          = 6, +}; + +enum { +	ULP_CRC_HEADER = 1 << 0, +	ULP_CRC_DATA   = 1 << 1 +}; + +enum { +	CPL_ABORT_SEND_RST = 0, +	CPL_ABORT_NO_RST, +}; + +enum {                     /* TX_PKT_XT checksum types */ +	TX_CSUM_TCP    = 0, +	TX_CSUM_UDP    = 1, +	TX_CSUM_CRC16  = 4, +	TX_CSUM_CRC32  = 5, +	TX_CSUM_CRC32C = 6, +	TX_CSUM_FCOE   = 7, +	TX_CSUM_TCPIP  = 8, +	TX_CSUM_UDPIP  = 9, +	TX_CSUM_TCPIP6 = 10, +	TX_CSUM_UDPIP6 = 11, +	TX_CSUM_IP     = 12, +}; + +union opcode_tid { +	__be32 opcode_tid; +	u8 opcode; +}; + +#define CPL_OPCODE(x) ((x) << 24) +#define MK_OPCODE_TID(opcode, tid) (CPL_OPCODE(opcode) | (tid)) +#define OPCODE_TID(cmd) ((cmd)->ot.opcode_tid) +#define GET_TID(cmd) (ntohl(OPCODE_TID(cmd)) & 0xFFFFFF) + +/* partitioning of TID fields that also carry a queue id */ +#define GET_TID_TID(x) ((x) & 0x3fff) +#define GET_TID_QID(x) (((x) >> 14) & 0x3ff) +#define TID_QID(x)     ((x) << 14) + +struct rss_header { +	u8 opcode; +#if defined(__LITTLE_ENDIAN_BITFIELD) +	u8 channel:2; +	u8 filter_hit:1; +	u8 filter_tid:1; +	u8 hash_type:2; +	u8 ipv6:1; +	u8 send2fw:1; +#else +	u8 send2fw:1; +	u8 ipv6:1; +	u8 hash_type:2; +	u8 filter_tid:1; +	u8 filter_hit:1; +	u8 channel:2; +#endif +	__be16 qid; +	__be32 hash_val; +}; + +struct work_request_hdr { +	__be32 wr_hi; +	__be32 wr_mid; +	__be64 wr_lo; +}; + +#define WR_HDR struct work_request_hdr wr + +struct cpl_pass_open_req { +	WR_HDR; +	union opcode_tid ot; +	__be16 local_port; +	__be16 peer_port; +	__be32 local_ip; +	__be32 peer_ip; +	__be64 opt0; +#define TX_CHAN(x)    ((x) << 2) +#define DELACK(x)     ((x) << 5) +#define ULP_MODE(x)   ((x) << 8) +#define RCV_BUFSIZ(x) ((x) << 12) +#define DSCP(x)       ((x) << 22) +#define SMAC_SEL(x)   ((u64)(x) << 28) +#define L2T_IDX(x)    ((u64)(x) << 36) +#define NAGLE(x)      ((u64)(x) << 49) +#define WND_SCALE(x)  ((u64)(x) << 50) +#define KEEP_ALIVE(x) ((u64)(x) << 54) +#define MSS_IDX(x)    ((u64)(x) << 60) +	__be64 opt1; +#define SYN_RSS_ENABLE   (1 << 0) +#define SYN_RSS_QUEUE(x) ((x) << 2) +#define CONN_POLICY_ASK  (1 << 22) +}; + +struct cpl_pass_open_req6 { +	WR_HDR; +	union opcode_tid ot; +	__be16 local_port; +	__be16 peer_port; +	__be64 local_ip_hi; +	__be64 local_ip_lo; +	__be64 peer_ip_hi; +	__be64 peer_ip_lo; +	__be64 opt0; +	__be64 opt1; +}; + +struct cpl_pass_open_rpl { +	union opcode_tid ot; +	u8 rsvd[3]; +	u8 status; +}; + +struct cpl_pass_accept_rpl { +	WR_HDR; +	union opcode_tid ot; +	__be32 opt2; +#define RSS_QUEUE(x)         ((x) << 0) +#define RSS_QUEUE_VALID      (1 << 10) +#define RX_COALESCE_VALID(x) ((x) << 11) +#define RX_COALESCE(x)       ((x) << 12) +#define TX_QUEUE(x)          ((x) << 23) +#define RX_CHANNEL(x)        ((x) << 26) +#define WND_SCALE_EN(x)      ((x) << 28) +#define TSTAMPS_EN(x)        ((x) << 29) +#define SACK_EN(x)           ((x) << 30) +	__be64 opt0; +}; + +struct cpl_act_open_req { +	WR_HDR; +	union opcode_tid ot; +	__be16 local_port; +	__be16 peer_port; +	__be32 local_ip; +	__be32 peer_ip; +	__be64 opt0; +	__be32 params; +	__be32 opt2; +}; + +struct cpl_act_open_req6 { +	WR_HDR; +	union opcode_tid ot; +	__be16 local_port; +	__be16 peer_port; +	__be64 local_ip_hi; +	__be64 local_ip_lo; +	__be64 peer_ip_hi; +	__be64 peer_ip_lo; +	__be64 opt0; +	__be32 params; +	__be32 opt2; +}; + +struct cpl_act_open_rpl { +	union opcode_tid ot; +	__be32 atid_status; +#define GET_AOPEN_STATUS(x) ((x) & 0xff) +#define GET_AOPEN_ATID(x)   (((x) >> 8) & 0xffffff) +}; + +struct cpl_pass_establish { +	union opcode_tid ot; +	__be32 rsvd; +	__be32 tos_stid; +#define GET_POPEN_TID(x) ((x) & 0xffffff) +#define GET_POPEN_TOS(x) (((x) >> 24) & 0xff) +	__be16 mac_idx; +	__be16 tcp_opt; +#define GET_TCPOPT_WSCALE_OK(x)  (((x) >> 5) & 1) +#define GET_TCPOPT_SACK(x)       (((x) >> 6) & 1) +#define GET_TCPOPT_TSTAMP(x)     (((x) >> 7) & 1) +#define GET_TCPOPT_SND_WSCALE(x) (((x) >> 8) & 0xf) +#define GET_TCPOPT_MSS(x)        (((x) >> 12) & 0xf) +	__be32 snd_isn; +	__be32 rcv_isn; +}; + +struct cpl_act_establish { +	union opcode_tid ot; +	__be32 rsvd; +	__be32 tos_atid; +	__be16 mac_idx; +	__be16 tcp_opt; +	__be32 snd_isn; +	__be32 rcv_isn; +}; + +struct cpl_get_tcb { +	WR_HDR; +	union opcode_tid ot; +	__be16 reply_ctrl; +#define QUEUENO(x)    ((x) << 0) +#define REPLY_CHAN(x) ((x) << 14) +#define NO_REPLY(x)   ((x) << 15) +	__be16 cookie; +}; + +struct cpl_set_tcb_field { +	WR_HDR; +	union opcode_tid ot; +	__be16 reply_ctrl; +	__be16 word_cookie; +#define TCB_WORD(x)   ((x) << 0) +#define TCB_COOKIE(x) ((x) << 5) +	__be64 mask; +	__be64 val; +}; + +struct cpl_set_tcb_rpl { +	union opcode_tid ot; +	__be16 rsvd; +	u8 cookie; +	u8 status; +	__be64 oldval; +}; + +struct cpl_close_con_req { +	WR_HDR; +	union opcode_tid ot; +	__be32 rsvd; +}; + +struct cpl_close_con_rpl { +	union opcode_tid ot; +	u8 rsvd[3]; +	u8 status; +	__be32 snd_nxt; +	__be32 rcv_nxt; +}; + +struct cpl_close_listsvr_req { +	WR_HDR; +	union opcode_tid ot; +	__be16 reply_ctrl; +#define LISTSVR_IPV6 (1 << 14) +	__be16 rsvd; +}; + +struct cpl_close_listsvr_rpl { +	union opcode_tid ot; +	u8 rsvd[3]; +	u8 status; +}; + +struct cpl_abort_req_rss { +	union opcode_tid ot; +	u8 rsvd[3]; +	u8 status; +}; + +struct cpl_abort_req { +	WR_HDR; +	union opcode_tid ot; +	__be32 rsvd0; +	u8 rsvd1; +	u8 cmd; +	u8 rsvd2[6]; +}; + +struct cpl_abort_rpl_rss { +	union opcode_tid ot; +	u8 rsvd[3]; +	u8 status; +}; + +struct cpl_abort_rpl { +	WR_HDR; +	union opcode_tid ot; +	__be32 rsvd0; +	u8 rsvd1; +	u8 cmd; +	u8 rsvd2[6]; +}; + +struct cpl_peer_close { +	union opcode_tid ot; +	__be32 rcv_nxt; +}; + +struct cpl_tid_release { +	WR_HDR; +	union opcode_tid ot; +	__be32 rsvd; +}; + +struct cpl_tx_pkt_core { +	__be32 ctrl0; +#define TXPKT_VF(x)        ((x) << 0) +#define TXPKT_PF(x)        ((x) << 8) +#define TXPKT_VF_VLD       (1 << 11) +#define TXPKT_OVLAN_IDX(x) ((x) << 12) +#define TXPKT_INTF(x)      ((x) << 16) +#define TXPKT_INS_OVLAN    (1 << 21) +#define TXPKT_OPCODE(x)    ((x) << 24) +	__be16 pack; +	__be16 len; +	__be64 ctrl1; +#define TXPKT_CSUM_END(x)   ((x) << 12) +#define TXPKT_CSUM_START(x) ((x) << 20) +#define TXPKT_IPHDR_LEN(x)  ((u64)(x) << 20) +#define TXPKT_CSUM_LOC(x)   ((u64)(x) << 30) +#define TXPKT_ETHHDR_LEN(x) ((u64)(x) << 34) +#define TXPKT_CSUM_TYPE(x)  ((u64)(x) << 40) +#define TXPKT_VLAN(x)       ((u64)(x) << 44) +#define TXPKT_VLAN_VLD      (1ULL << 60) +#define TXPKT_IPCSUM_DIS    (1ULL << 62) +#define TXPKT_L4CSUM_DIS    (1ULL << 63) +}; + +struct cpl_tx_pkt { +	WR_HDR; +	struct cpl_tx_pkt_core c; +}; + +#define cpl_tx_pkt_xt cpl_tx_pkt + +struct cpl_tx_pkt_lso { +	WR_HDR; +	__be32 lso_ctrl; +#define LSO_TCPHDR_LEN(x) ((x) << 0) +#define LSO_IPHDR_LEN(x)  ((x) << 4) +#define LSO_ETHHDR_LEN(x) ((x) << 16) +#define LSO_IPV6(x)       ((x) << 20) +#define LSO_LAST_SLICE    (1 << 22) +#define LSO_FIRST_SLICE   (1 << 23) +#define LSO_OPCODE(x)     ((x) << 24) +	__be16 ipid_ofst; +	__be16 mss; +	__be32 seqno_offset; +	__be32 len; +	/* encapsulated CPL (TX_PKT, TX_PKT_XT or TX_DATA) follows here */ +}; + +struct cpl_iscsi_hdr { +	union opcode_tid ot; +	__be16 pdu_len_ddp; +#define ISCSI_PDU_LEN(x) ((x) & 0x7FFF) +#define ISCSI_DDP        (1 << 15) +	__be16 len; +	__be32 seq; +	__be16 urg; +	u8 rsvd; +	u8 status; +}; + +struct cpl_rx_data { +	union opcode_tid ot; +	__be16 rsvd; +	__be16 len; +	__be32 seq; +	__be16 urg; +#if defined(__LITTLE_ENDIAN_BITFIELD) +	u8 dack_mode:2; +	u8 psh:1; +	u8 heartbeat:1; +	u8 ddp_off:1; +	u8 :3; +#else +	u8 :3; +	u8 ddp_off:1; +	u8 heartbeat:1; +	u8 psh:1; +	u8 dack_mode:2; +#endif +	u8 status; +}; + +struct cpl_rx_data_ack { +	WR_HDR; +	union opcode_tid ot; +	__be32 credit_dack; +#define RX_CREDITS(x)   ((x) << 0) +#define RX_FORCE_ACK(x) ((x) << 28) +}; + +struct cpl_rx_pkt { +	u8 opcode; +#if defined(__LITTLE_ENDIAN_BITFIELD) +	u8 iff:4; +	u8 csum_calc:1; +	u8 ipmi_pkt:1; +	u8 vlan_ex:1; +	u8 ip_frag:1; +#else +	u8 ip_frag:1; +	u8 vlan_ex:1; +	u8 ipmi_pkt:1; +	u8 csum_calc:1; +	u8 iff:4; +#endif +	__be16 csum; +	__be16 vlan; +	__be16 len; +	__be32 l2info; +#define RXF_UDP (1 << 22) +#define RXF_TCP (1 << 23) +	__be16 hdr_len; +	__be16 err_vec; +}; + +struct cpl_trace_pkt { +	u8 opcode; +	u8 intf; +#if defined(__LITTLE_ENDIAN_BITFIELD) +	u8 runt:4; +	u8 filter_hit:4; +	u8 :6; +	u8 err:1; +	u8 trunc:1; +#else +	u8 filter_hit:4; +	u8 runt:4; +	u8 trunc:1; +	u8 err:1; +	u8 :6; +#endif +	__be16 rsvd; +	__be16 len; +	__be64 tstamp; +}; + +struct cpl_l2t_write_req { +	WR_HDR; +	union opcode_tid ot; +	__be16 params; +#define L2T_W_INFO(x)    ((x) << 2) +#define L2T_W_PORT(x)    ((x) << 8) +#define L2T_W_NOREPLY(x) ((x) << 15) +	__be16 l2t_idx; +	__be16 vlan; +	u8 dst_mac[6]; +}; + +struct cpl_l2t_write_rpl { +	union opcode_tid ot; +	u8 status; +	u8 rsvd[3]; +}; + +struct cpl_rdma_terminate { +	union opcode_tid ot; +	__be16 rsvd; +	__be16 len; +}; + +struct cpl_sge_egr_update { +	__be32 opcode_qid; +#define EGR_QID(x) ((x) & 0x1FFFF) +	__be16 cidx; +	__be16 pidx; +}; + +struct cpl_fw4_pld { +	u8 opcode; +	u8 rsvd0[3]; +	u8 type; +	u8 rsvd1; +	__be16 len; +	__be64 data; +	__be64 rsvd2; +}; + +struct cpl_fw6_pld { +	u8 opcode; +	u8 rsvd[5]; +	__be16 len; +	__be64 data[4]; +}; + +struct cpl_fw4_msg { +	u8 opcode; +	u8 type; +	__be16 rsvd0; +	__be32 rsvd1; +	__be64 data[2]; +}; + +struct cpl_fw4_ack { +	union opcode_tid ot; +	u8 credits; +	u8 rsvd0[2]; +	u8 seq_vld; +	__be32 snd_nxt; +	__be32 snd_una; +	__be64 rsvd1; +}; + +struct cpl_fw6_msg { +	u8 opcode; +	u8 type; +	__be16 rsvd0; +	__be32 rsvd1; +	__be64 data[4]; +}; + +enum { +	ULP_TX_MEM_READ = 2, +	ULP_TX_MEM_WRITE = 3, +	ULP_TX_PKT = 4 +}; + +enum { +	ULP_TX_SC_NOOP = 0x80, +	ULP_TX_SC_IMM  = 0x81, +	ULP_TX_SC_DSGL = 0x82, +	ULP_TX_SC_ISGL = 0x83 +}; + +struct ulptx_sge_pair { +	__be32 len[2]; +	__be64 addr[2]; +}; + +struct ulptx_sgl { +	__be32 cmd_nsge; +#define ULPTX_CMD(x) ((x) << 24) +#define ULPTX_NSGE(x) ((x) << 0) +	__be32 len0; +	__be64 addr0; +	struct ulptx_sge_pair sge[0]; +}; + +struct ulp_mem_io { +	WR_HDR; +	__be32 cmd; +#define ULP_MEMIO_ORDER(x) ((x) << 23) +	__be32 len16;             /* command length */ +	__be32 dlen;              /* data length in 32-byte units */ +#define ULP_MEMIO_DATA_LEN(x) ((x) << 0) +	__be32 lock_addr; +#define ULP_MEMIO_ADDR(x) ((x) << 0) +#define ULP_MEMIO_LOCK(x) ((x) << 31) +}; + +#endif  /* __T4_MSG_H */ diff --git a/drivers/net/cxgb4/t4_regs.h b/drivers/net/cxgb4/t4_regs.h new file mode 100644 index 00000000000..5ed56483cbc --- /dev/null +++ b/drivers/net/cxgb4/t4_regs.h @@ -0,0 +1,878 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses.  You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + *     Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *      - Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + * + *      - Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __T4_REGS_H +#define __T4_REGS_H + +#define MYPF_BASE 0x1b000 +#define MYPF_REG(reg_addr) (MYPF_BASE + (reg_addr)) + +#define PF0_BASE 0x1e000 +#define PF0_REG(reg_addr) (PF0_BASE + (reg_addr)) + +#define PF_STRIDE 0x400 +#define PF_BASE(idx) (PF0_BASE + (idx) * PF_STRIDE) +#define PF_REG(idx, reg) (PF_BASE(idx) + (reg)) + +#define MYPORT_BASE 0x1c000 +#define MYPORT_REG(reg_addr) (MYPORT_BASE + (reg_addr)) + +#define PORT0_BASE 0x20000 +#define PORT0_REG(reg_addr) (PORT0_BASE + (reg_addr)) + +#define PORT_STRIDE 0x2000 +#define PORT_BASE(idx) (PORT0_BASE + (idx) * PORT_STRIDE) +#define PORT_REG(idx, reg) (PORT_BASE(idx) + (reg)) + +#define EDC_STRIDE (EDC_1_BASE_ADDR - EDC_0_BASE_ADDR) +#define EDC_REG(reg, idx) (reg + EDC_STRIDE * idx) + +#define PCIE_MEM_ACCESS_REG(reg_addr, idx) ((reg_addr) + (idx) * 8) +#define PCIE_MAILBOX_REG(reg_addr, idx) ((reg_addr) + (idx) * 8) +#define MC_BIST_STATUS_REG(reg_addr, idx) ((reg_addr) + (idx) * 4) +#define EDC_BIST_STATUS_REG(reg_addr, idx) ((reg_addr) + (idx) * 4) + +#define SGE_PF_KDOORBELL 0x0 +#define  QID_MASK    0xffff8000U +#define  QID_SHIFT   15 +#define  QID(x)      ((x) << QID_SHIFT) +#define  DBPRIO      0x00004000U +#define  PIDX_MASK   0x00003fffU +#define  PIDX_SHIFT  0 +#define  PIDX(x)     ((x) << PIDX_SHIFT) + +#define SGE_PF_GTS 0x4 +#define  INGRESSQID_MASK   0xffff0000U +#define  INGRESSQID_SHIFT  16 +#define  INGRESSQID(x)     ((x) << INGRESSQID_SHIFT) +#define  TIMERREG_MASK     0x0000e000U +#define  TIMERREG_SHIFT    13 +#define  TIMERREG(x)       ((x) << TIMERREG_SHIFT) +#define  SEINTARM_MASK     0x00001000U +#define  SEINTARM_SHIFT    12 +#define  SEINTARM(x)       ((x) << SEINTARM_SHIFT) +#define  CIDXINC_MASK      0x00000fffU +#define  CIDXINC_SHIFT     0 +#define  CIDXINC(x)        ((x) << CIDXINC_SHIFT) + +#define SGE_CONTROL 0x1008 +#define  DCASYSTYPE             0x00080000U +#define  RXPKTCPLMODE           0x00040000U +#define  EGRSTATUSPAGESIZE      0x00020000U +#define  PKTSHIFT_MASK          0x00001c00U +#define  PKTSHIFT_SHIFT         10 +#define  PKTSHIFT(x)            ((x) << PKTSHIFT_SHIFT) +#define  INGPCIEBOUNDARY_MASK   0x00000380U +#define  INGPCIEBOUNDARY_SHIFT  7 +#define  INGPCIEBOUNDARY(x)     ((x) << INGPCIEBOUNDARY_SHIFT) +#define  INGPADBOUNDARY_MASK    0x00000070U +#define  INGPADBOUNDARY_SHIFT   4 +#define  INGPADBOUNDARY(x)      ((x) << INGPADBOUNDARY_SHIFT) +#define  EGRPCIEBOUNDARY_MASK   0x0000000eU +#define  EGRPCIEBOUNDARY_SHIFT  1 +#define  EGRPCIEBOUNDARY(x)     ((x) << EGRPCIEBOUNDARY_SHIFT) +#define  GLOBALENABLE           0x00000001U + +#define SGE_HOST_PAGE_SIZE 0x100c +#define  HOSTPAGESIZEPF0_MASK   0x0000000fU +#define  HOSTPAGESIZEPF0_SHIFT  0 +#define  HOSTPAGESIZEPF0(x)     ((x) << HOSTPAGESIZEPF0_SHIFT) + +#define SGE_EGRESS_QUEUES_PER_PAGE_PF 0x1010 +#define  QUEUESPERPAGEPF0_MASK   0x0000000fU +#define  QUEUESPERPAGEPF0_GET(x) ((x) & QUEUESPERPAGEPF0_MASK) + +#define SGE_INT_CAUSE1 0x1024 +#define SGE_INT_CAUSE2 0x1030 +#define SGE_INT_CAUSE3 0x103c +#define  ERR_FLM_DBP               0x80000000U +#define  ERR_FLM_IDMA1             0x40000000U +#define  ERR_FLM_IDMA0             0x20000000U +#define  ERR_FLM_HINT              0x10000000U +#define  ERR_PCIE_ERROR3           0x08000000U +#define  ERR_PCIE_ERROR2           0x04000000U +#define  ERR_PCIE_ERROR1           0x02000000U +#define  ERR_PCIE_ERROR0           0x01000000U +#define  ERR_TIMER_ABOVE_MAX_QID   0x00800000U +#define  ERR_CPL_EXCEED_IQE_SIZE   0x00400000U +#define  ERR_INVALID_CIDX_INC      0x00200000U +#define  ERR_ITP_TIME_PAUSED       0x00100000U +#define  ERR_CPL_OPCODE_0          0x00080000U +#define  ERR_DROPPED_DB            0x00040000U +#define  ERR_DATA_CPL_ON_HIGH_QID1 0x00020000U +#define  ERR_DATA_CPL_ON_HIGH_QID0 0x00010000U +#define  ERR_BAD_DB_PIDX3          0x00008000U +#define  ERR_BAD_DB_PIDX2          0x00004000U +#define  ERR_BAD_DB_PIDX1          0x00002000U +#define  ERR_BAD_DB_PIDX0          0x00001000U +#define  ERR_ING_PCIE_CHAN         0x00000800U +#define  ERR_ING_CTXT_PRIO         0x00000400U +#define  ERR_EGR_CTXT_PRIO         0x00000200U +#define  DBFIFO_HP_INT             0x00000100U +#define  DBFIFO_LP_INT             0x00000080U +#define  REG_ADDRESS_ERR           0x00000040U +#define  INGRESS_SIZE_ERR          0x00000020U +#define  EGRESS_SIZE_ERR           0x00000010U +#define  ERR_INV_CTXT3             0x00000008U +#define  ERR_INV_CTXT2             0x00000004U +#define  ERR_INV_CTXT1             0x00000002U +#define  ERR_INV_CTXT0             0x00000001U + +#define SGE_INT_ENABLE3 0x1040 +#define SGE_FL_BUFFER_SIZE0 0x1044 +#define SGE_FL_BUFFER_SIZE1 0x1048 +#define SGE_INGRESS_RX_THRESHOLD 0x10a0 +#define  THRESHOLD_0_MASK   0x3f000000U +#define  THRESHOLD_0_SHIFT  24 +#define  THRESHOLD_0(x)     ((x) << THRESHOLD_0_SHIFT) +#define  THRESHOLD_0_GET(x) (((x) & THRESHOLD_0_MASK) >> THRESHOLD_0_SHIFT) +#define  THRESHOLD_1_MASK   0x003f0000U +#define  THRESHOLD_1_SHIFT  16 +#define  THRESHOLD_1(x)     ((x) << THRESHOLD_1_SHIFT) +#define  THRESHOLD_1_GET(x) (((x) & THRESHOLD_1_MASK) >> THRESHOLD_1_SHIFT) +#define  THRESHOLD_2_MASK   0x00003f00U +#define  THRESHOLD_2_SHIFT  8 +#define  THRESHOLD_2(x)     ((x) << THRESHOLD_2_SHIFT) +#define  THRESHOLD_2_GET(x) (((x) & THRESHOLD_2_MASK) >> THRESHOLD_2_SHIFT) +#define  THRESHOLD_3_MASK   0x0000003fU +#define  THRESHOLD_3_SHIFT  0 +#define  THRESHOLD_3(x)     ((x) << THRESHOLD_3_SHIFT) +#define  THRESHOLD_3_GET(x) (((x) & THRESHOLD_3_MASK) >> THRESHOLD_3_SHIFT) + +#define SGE_TIMER_VALUE_0_AND_1 0x10b8 +#define  TIMERVALUE0_MASK   0xffff0000U +#define  TIMERVALUE0_SHIFT  16 +#define  TIMERVALUE0(x)     ((x) << TIMERVALUE0_SHIFT) +#define  TIMERVALUE0_GET(x) (((x) & TIMERVALUE0_MASK) >> TIMERVALUE0_SHIFT) +#define  TIMERVALUE1_MASK   0x0000ffffU +#define  TIMERVALUE1_SHIFT  0 +#define  TIMERVALUE1(x)     ((x) << TIMERVALUE1_SHIFT) +#define  TIMERVALUE1_GET(x) (((x) & TIMERVALUE1_MASK) >> TIMERVALUE1_SHIFT) + +#define SGE_TIMER_VALUE_2_AND_3 0x10bc +#define SGE_TIMER_VALUE_4_AND_5 0x10c0 +#define SGE_DEBUG_INDEX 0x10cc +#define SGE_DEBUG_DATA_HIGH 0x10d0 +#define SGE_DEBUG_DATA_LOW 0x10d4 +#define SGE_INGRESS_QUEUES_PER_PAGE_PF 0x10f4 + +#define PCIE_PF_CLI 0x44 +#define PCIE_INT_CAUSE 0x3004 +#define  UNXSPLCPLERR  0x20000000U +#define  PCIEPINT      0x10000000U +#define  PCIESINT      0x08000000U +#define  RPLPERR       0x04000000U +#define  RXWRPERR      0x02000000U +#define  RXCPLPERR     0x01000000U +#define  PIOTAGPERR    0x00800000U +#define  MATAGPERR     0x00400000U +#define  INTXCLRPERR   0x00200000U +#define  FIDPERR       0x00100000U +#define  CFGSNPPERR    0x00080000U +#define  HRSPPERR      0x00040000U +#define  HREQPERR      0x00020000U +#define  HCNTPERR      0x00010000U +#define  DRSPPERR      0x00008000U +#define  DREQPERR      0x00004000U +#define  DCNTPERR      0x00002000U +#define  CRSPPERR      0x00001000U +#define  CREQPERR      0x00000800U +#define  CCNTPERR      0x00000400U +#define  TARTAGPERR    0x00000200U +#define  PIOREQPERR    0x00000100U +#define  PIOCPLPERR    0x00000080U +#define  MSIXDIPERR    0x00000040U +#define  MSIXDATAPERR  0x00000020U +#define  MSIXADDRHPERR 0x00000010U +#define  MSIXADDRLPERR 0x00000008U +#define  MSIDATAPERR   0x00000004U +#define  MSIADDRHPERR  0x00000002U +#define  MSIADDRLPERR  0x00000001U + +#define PCIE_NONFAT_ERR 0x3010 +#define PCIE_MEM_ACCESS_BASE_WIN 0x3068 +#define  PCIEOFST_MASK   0xfffffc00U +#define  BIR_MASK        0x00000300U +#define  BIR_SHIFT       8 +#define  BIR(x)          ((x) << BIR_SHIFT) +#define  WINDOW_MASK     0x000000ffU +#define  WINDOW_SHIFT    0 +#define  WINDOW(x)       ((x) << WINDOW_SHIFT) + +#define PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS 0x5908 +#define  RNPP 0x80000000U +#define  RPCP 0x20000000U +#define  RCIP 0x08000000U +#define  RCCP 0x04000000U +#define  RFTP 0x00800000U +#define  PTRP 0x00100000U + +#define PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS 0x59a4 +#define  TPCP 0x40000000U +#define  TNPP 0x20000000U +#define  TFTP 0x10000000U +#define  TCAP 0x08000000U +#define  TCIP 0x04000000U +#define  RCAP 0x02000000U +#define  PLUP 0x00800000U +#define  PLDN 0x00400000U +#define  OTDD 0x00200000U +#define  GTRP 0x00100000U +#define  RDPE 0x00040000U +#define  TDCE 0x00020000U +#define  TDUE 0x00010000U + +#define MC_INT_CAUSE 0x7518 +#define  ECC_UE_INT_CAUSE 0x00000004U +#define  ECC_CE_INT_CAUSE 0x00000002U +#define  PERR_INT_CAUSE   0x00000001U + +#define MC_ECC_STATUS 0x751c +#define  ECC_CECNT_MASK   0xffff0000U +#define  ECC_CECNT_SHIFT  16 +#define  ECC_CECNT(x)     ((x) << ECC_CECNT_SHIFT) +#define  ECC_CECNT_GET(x) (((x) & ECC_CECNT_MASK) >> ECC_CECNT_SHIFT) +#define  ECC_UECNT_MASK   0x0000ffffU +#define  ECC_UECNT_SHIFT  0 +#define  ECC_UECNT(x)     ((x) << ECC_UECNT_SHIFT) +#define  ECC_UECNT_GET(x) (((x) & ECC_UECNT_MASK) >> ECC_UECNT_SHIFT) + +#define MC_BIST_CMD 0x7600 +#define  START_BIST          0x80000000U +#define  BIST_CMD_GAP_MASK   0x0000ff00U +#define  BIST_CMD_GAP_SHIFT  8 +#define  BIST_CMD_GAP(x)     ((x) << BIST_CMD_GAP_SHIFT) +#define  BIST_OPCODE_MASK    0x00000003U +#define  BIST_OPCODE_SHIFT   0 +#define  BIST_OPCODE(x)      ((x) << BIST_OPCODE_SHIFT) + +#define MC_BIST_CMD_ADDR 0x7604 +#define MC_BIST_CMD_LEN 0x7608 +#define MC_BIST_DATA_PATTERN 0x760c +#define  BIST_DATA_TYPE_MASK   0x0000000fU +#define  BIST_DATA_TYPE_SHIFT  0 +#define  BIST_DATA_TYPE(x)     ((x) << BIST_DATA_TYPE_SHIFT) + +#define MC_BIST_STATUS_RDATA 0x7688 + +#define MA_EXT_MEMORY_BAR 0x77c8 +#define  EXT_MEM_SIZE_MASK   0x00000fffU +#define  EXT_MEM_SIZE_SHIFT  0 +#define  EXT_MEM_SIZE_GET(x) (((x) & EXT_MEM_SIZE_MASK) >> EXT_MEM_SIZE_SHIFT) + +#define MA_TARGET_MEM_ENABLE 0x77d8 +#define  EXT_MEM_ENABLE 0x00000004U +#define  EDRAM1_ENABLE  0x00000002U +#define  EDRAM0_ENABLE  0x00000001U + +#define MA_INT_CAUSE 0x77e0 +#define  MEM_PERR_INT_CAUSE 0x00000002U +#define  MEM_WRAP_INT_CAUSE 0x00000001U + +#define MA_INT_WRAP_STATUS 0x77e4 +#define  MEM_WRAP_ADDRESS_MASK   0xfffffff0U +#define  MEM_WRAP_ADDRESS_SHIFT  4 +#define  MEM_WRAP_ADDRESS_GET(x) (((x) & MEM_WRAP_ADDRESS_MASK) >> MEM_WRAP_ADDRESS_SHIFT) +#define  MEM_WRAP_CLIENT_NUM_MASK   0x0000000fU +#define  MEM_WRAP_CLIENT_NUM_SHIFT  0 +#define  MEM_WRAP_CLIENT_NUM_GET(x) (((x) & MEM_WRAP_CLIENT_NUM_MASK) >> MEM_WRAP_CLIENT_NUM_SHIFT) + +#define MA_PARITY_ERROR_STATUS 0x77f4 + +#define EDC_0_BASE_ADDR 0x7900 + +#define EDC_BIST_CMD 0x7904 +#define EDC_BIST_CMD_ADDR 0x7908 +#define EDC_BIST_CMD_LEN 0x790c +#define EDC_BIST_DATA_PATTERN 0x7910 +#define EDC_BIST_STATUS_RDATA 0x7928 +#define EDC_INT_CAUSE 0x7978 +#define  ECC_UE_PAR     0x00000020U +#define  ECC_CE_PAR     0x00000010U +#define  PERR_PAR_CAUSE 0x00000008U + +#define EDC_ECC_STATUS 0x797c + +#define EDC_1_BASE_ADDR 0x7980 + +#define CIM_PF_MAILBOX_DATA 0x240 +#define CIM_PF_MAILBOX_CTRL 0x280 +#define  MBMSGVALID     0x00000008U +#define  MBINTREQ       0x00000004U +#define  MBOWNER_MASK   0x00000003U +#define  MBOWNER_SHIFT  0 +#define  MBOWNER(x)     ((x) << MBOWNER_SHIFT) +#define  MBOWNER_GET(x) (((x) & MBOWNER_MASK) >> MBOWNER_SHIFT) + +#define CIM_PF_HOST_INT_CAUSE 0x28c +#define  MBMSGRDYINT 0x00080000U + +#define CIM_HOST_INT_CAUSE 0x7b2c +#define  TIEQOUTPARERRINT  0x00100000U +#define  TIEQINPARERRINT   0x00080000U +#define  MBHOSTPARERR      0x00040000U +#define  MBUPPARERR        0x00020000U +#define  IBQPARERR         0x0001f800U +#define  IBQTP0PARERR      0x00010000U +#define  IBQTP1PARERR      0x00008000U +#define  IBQULPPARERR      0x00004000U +#define  IBQSGELOPARERR    0x00002000U +#define  IBQSGEHIPARERR    0x00001000U +#define  IBQNCSIPARERR     0x00000800U +#define  OBQPARERR         0x000007e0U +#define  OBQULP0PARERR     0x00000400U +#define  OBQULP1PARERR     0x00000200U +#define  OBQULP2PARERR     0x00000100U +#define  OBQULP3PARERR     0x00000080U +#define  OBQSGEPARERR      0x00000040U +#define  OBQNCSIPARERR     0x00000020U +#define  PREFDROPINT       0x00000002U +#define  UPACCNONZERO      0x00000001U + +#define CIM_HOST_UPACC_INT_CAUSE 0x7b34 +#define  EEPROMWRINT      0x40000000U +#define  TIMEOUTMAINT     0x20000000U +#define  TIMEOUTINT       0x10000000U +#define  RSPOVRLOOKUPINT  0x08000000U +#define  REQOVRLOOKUPINT  0x04000000U +#define  BLKWRPLINT       0x02000000U +#define  BLKRDPLINT       0x01000000U +#define  SGLWRPLINT       0x00800000U +#define  SGLRDPLINT       0x00400000U +#define  BLKWRCTLINT      0x00200000U +#define  BLKRDCTLINT      0x00100000U +#define  SGLWRCTLINT      0x00080000U +#define  SGLRDCTLINT      0x00040000U +#define  BLKWREEPROMINT   0x00020000U +#define  BLKRDEEPROMINT   0x00010000U +#define  SGLWREEPROMINT   0x00008000U +#define  SGLRDEEPROMINT   0x00004000U +#define  BLKWRFLASHINT    0x00002000U +#define  BLKRDFLASHINT    0x00001000U +#define  SGLWRFLASHINT    0x00000800U +#define  SGLRDFLASHINT    0x00000400U +#define  BLKWRBOOTINT     0x00000200U +#define  BLKRDBOOTINT     0x00000100U +#define  SGLWRBOOTINT     0x00000080U +#define  SGLRDBOOTINT     0x00000040U +#define  ILLWRBEINT       0x00000020U +#define  ILLRDBEINT       0x00000010U +#define  ILLRDINT         0x00000008U +#define  ILLWRINT         0x00000004U +#define  ILLTRANSINT      0x00000002U +#define  RSVDSPACEINT     0x00000001U + +#define TP_OUT_CONFIG 0x7d04 +#define  VLANEXTENABLE_MASK  0x0000f000U +#define  VLANEXTENABLE_SHIFT 12 + +#define TP_PARA_REG2 0x7d68 +#define  MAXRXDATA_MASK    0xffff0000U +#define  MAXRXDATA_SHIFT   16 +#define  MAXRXDATA_GET(x) (((x) & MAXRXDATA_MASK) >> MAXRXDATA_SHIFT) + +#define TP_TIMER_RESOLUTION 0x7d90 +#define  TIMERRESOLUTION_MASK   0x00ff0000U +#define  TIMERRESOLUTION_SHIFT  16 +#define  TIMERRESOLUTION_GET(x) (((x) & TIMERRESOLUTION_MASK) >> TIMERRESOLUTION_SHIFT) + +#define TP_SHIFT_CNT 0x7dc0 + +#define TP_CCTRL_TABLE 0x7ddc +#define TP_MTU_TABLE 0x7de4 +#define  MTUINDEX_MASK   0xff000000U +#define  MTUINDEX_SHIFT  24 +#define  MTUINDEX(x)     ((x) << MTUINDEX_SHIFT) +#define  MTUWIDTH_MASK   0x000f0000U +#define  MTUWIDTH_SHIFT  16 +#define  MTUWIDTH(x)     ((x) << MTUWIDTH_SHIFT) +#define  MTUWIDTH_GET(x) (((x) & MTUWIDTH_MASK) >> MTUWIDTH_SHIFT) +#define  MTUVALUE_MASK   0x00003fffU +#define  MTUVALUE_SHIFT  0 +#define  MTUVALUE(x)     ((x) << MTUVALUE_SHIFT) +#define  MTUVALUE_GET(x) (((x) & MTUVALUE_MASK) >> MTUVALUE_SHIFT) + +#define TP_RSS_LKP_TABLE 0x7dec +#define  LKPTBLROWVLD        0x80000000U +#define  LKPTBLQUEUE1_MASK   0x000ffc00U +#define  LKPTBLQUEUE1_SHIFT  10 +#define  LKPTBLQUEUE1(x)     ((x) << LKPTBLQUEUE1_SHIFT) +#define  LKPTBLQUEUE1_GET(x) (((x) & LKPTBLQUEUE1_MASK) >> LKPTBLQUEUE1_SHIFT) +#define  LKPTBLQUEUE0_MASK   0x000003ffU +#define  LKPTBLQUEUE0_SHIFT  0 +#define  LKPTBLQUEUE0(x)     ((x) << LKPTBLQUEUE0_SHIFT) +#define  LKPTBLQUEUE0_GET(x) (((x) & LKPTBLQUEUE0_MASK) >> LKPTBLQUEUE0_SHIFT) + +#define TP_PIO_ADDR 0x7e40 +#define TP_PIO_DATA 0x7e44 +#define TP_MIB_INDEX 0x7e50 +#define TP_MIB_DATA 0x7e54 +#define TP_INT_CAUSE 0x7e74 +#define  FLMTXFLSTEMPTY 0x40000000U + +#define TP_INGRESS_CONFIG 0x141 +#define  VNIC                0x00000800U +#define  CSUM_HAS_PSEUDO_HDR 0x00000400U +#define  RM_OVLAN            0x00000200U +#define  LOOKUPEVERYPKT      0x00000100U + +#define TP_MIB_MAC_IN_ERR_0 0x0 +#define TP_MIB_TCP_OUT_RST 0xc +#define TP_MIB_TCP_IN_SEG_HI 0x10 +#define TP_MIB_TCP_IN_SEG_LO 0x11 +#define TP_MIB_TCP_OUT_SEG_HI 0x12 +#define TP_MIB_TCP_OUT_SEG_LO 0x13 +#define TP_MIB_TCP_RXT_SEG_HI 0x14 +#define TP_MIB_TCP_RXT_SEG_LO 0x15 +#define TP_MIB_TNL_CNG_DROP_0 0x18 +#define TP_MIB_TCP_V6IN_ERR_0 0x28 +#define TP_MIB_TCP_V6OUT_RST 0x2c +#define TP_MIB_OFD_ARP_DROP 0x36 +#define TP_MIB_TNL_DROP_0 0x44 +#define TP_MIB_OFD_VLN_DROP_0 0x58 + +#define ULP_TX_INT_CAUSE 0x8dcc +#define  PBL_BOUND_ERR_CH3 0x80000000U +#define  PBL_BOUND_ERR_CH2 0x40000000U +#define  PBL_BOUND_ERR_CH1 0x20000000U +#define  PBL_BOUND_ERR_CH0 0x10000000U + +#define PM_RX_INT_CAUSE 0x8fdc +#define  ZERO_E_CMD_ERROR     0x00400000U +#define  PMRX_FRAMING_ERROR   0x003ffff0U +#define  OCSPI_PAR_ERROR      0x00000008U +#define  DB_OPTIONS_PAR_ERROR 0x00000004U +#define  IESPI_PAR_ERROR      0x00000002U +#define  E_PCMD_PAR_ERROR     0x00000001U + +#define PM_TX_INT_CAUSE 0x8ffc +#define  PCMD_LEN_OVFL0     0x80000000U +#define  PCMD_LEN_OVFL1     0x40000000U +#define  PCMD_LEN_OVFL2     0x20000000U +#define  ZERO_C_CMD_ERROR   0x10000000U +#define  PMTX_FRAMING_ERROR 0x0ffffff0U +#define  OESPI_PAR_ERROR    0x00000008U +#define  ICSPI_PAR_ERROR    0x00000002U +#define  C_PCMD_PAR_ERROR   0x00000001U + +#define MPS_PORT_STAT_TX_PORT_BYTES_L 0x400 +#define MPS_PORT_STAT_TX_PORT_BYTES_H 0x404 +#define MPS_PORT_STAT_TX_PORT_FRAMES_L 0x408 +#define MPS_PORT_STAT_TX_PORT_FRAMES_H 0x40c +#define MPS_PORT_STAT_TX_PORT_BCAST_L 0x410 +#define MPS_PORT_STAT_TX_PORT_BCAST_H 0x414 +#define MPS_PORT_STAT_TX_PORT_MCAST_L 0x418 +#define MPS_PORT_STAT_TX_PORT_MCAST_H 0x41c +#define MPS_PORT_STAT_TX_PORT_UCAST_L 0x420 +#define MPS_PORT_STAT_TX_PORT_UCAST_H 0x424 +#define MPS_PORT_STAT_TX_PORT_ERROR_L 0x428 +#define MPS_PORT_STAT_TX_PORT_ERROR_H 0x42c +#define MPS_PORT_STAT_TX_PORT_64B_L 0x430 +#define MPS_PORT_STAT_TX_PORT_64B_H 0x434 +#define MPS_PORT_STAT_TX_PORT_65B_127B_L 0x438 +#define MPS_PORT_STAT_TX_PORT_65B_127B_H 0x43c +#define MPS_PORT_STAT_TX_PORT_128B_255B_L 0x440 +#define MPS_PORT_STAT_TX_PORT_128B_255B_H 0x444 +#define MPS_PORT_STAT_TX_PORT_256B_511B_L 0x448 +#define MPS_PORT_STAT_TX_PORT_256B_511B_H 0x44c +#define MPS_PORT_STAT_TX_PORT_512B_1023B_L 0x450 +#define MPS_PORT_STAT_TX_PORT_512B_1023B_H 0x454 +#define MPS_PORT_STAT_TX_PORT_1024B_1518B_L 0x458 +#define MPS_PORT_STAT_TX_PORT_1024B_1518B_H 0x45c +#define MPS_PORT_STAT_TX_PORT_1519B_MAX_L 0x460 +#define MPS_PORT_STAT_TX_PORT_1519B_MAX_H 0x464 +#define MPS_PORT_STAT_TX_PORT_DROP_L 0x468 +#define MPS_PORT_STAT_TX_PORT_DROP_H 0x46c +#define MPS_PORT_STAT_TX_PORT_PAUSE_L 0x470 +#define MPS_PORT_STAT_TX_PORT_PAUSE_H 0x474 +#define MPS_PORT_STAT_TX_PORT_PPP0_L 0x478 +#define MPS_PORT_STAT_TX_PORT_PPP0_H 0x47c +#define MPS_PORT_STAT_TX_PORT_PPP1_L 0x480 +#define MPS_PORT_STAT_TX_PORT_PPP1_H 0x484 +#define MPS_PORT_STAT_TX_PORT_PPP2_L 0x488 +#define MPS_PORT_STAT_TX_PORT_PPP2_H 0x48c +#define MPS_PORT_STAT_TX_PORT_PPP3_L 0x490 +#define MPS_PORT_STAT_TX_PORT_PPP3_H 0x494 +#define MPS_PORT_STAT_TX_PORT_PPP4_L 0x498 +#define MPS_PORT_STAT_TX_PORT_PPP4_H 0x49c +#define MPS_PORT_STAT_TX_PORT_PPP5_L 0x4a0 +#define MPS_PORT_STAT_TX_PORT_PPP5_H 0x4a4 +#define MPS_PORT_STAT_TX_PORT_PPP6_L 0x4a8 +#define MPS_PORT_STAT_TX_PORT_PPP6_H 0x4ac +#define MPS_PORT_STAT_TX_PORT_PPP7_L 0x4b0 +#define MPS_PORT_STAT_TX_PORT_PPP7_H 0x4b4 +#define MPS_PORT_STAT_LB_PORT_BYTES_L 0x4c0 +#define MPS_PORT_STAT_LB_PORT_BYTES_H 0x4c4 +#define MPS_PORT_STAT_LB_PORT_FRAMES_L 0x4c8 +#define MPS_PORT_STAT_LB_PORT_FRAMES_H 0x4cc +#define MPS_PORT_STAT_LB_PORT_BCAST_L 0x4d0 +#define MPS_PORT_STAT_LB_PORT_BCAST_H 0x4d4 +#define MPS_PORT_STAT_LB_PORT_MCAST_L 0x4d8 +#define MPS_PORT_STAT_LB_PORT_MCAST_H 0x4dc +#define MPS_PORT_STAT_LB_PORT_UCAST_L 0x4e0 +#define MPS_PORT_STAT_LB_PORT_UCAST_H 0x4e4 +#define MPS_PORT_STAT_LB_PORT_ERROR_L 0x4e8 +#define MPS_PORT_STAT_LB_PORT_ERROR_H 0x4ec +#define MPS_PORT_STAT_LB_PORT_64B_L 0x4f0 +#define MPS_PORT_STAT_LB_PORT_64B_H 0x4f4 +#define MPS_PORT_STAT_LB_PORT_65B_127B_L 0x4f8 +#define MPS_PORT_STAT_LB_PORT_65B_127B_H 0x4fc +#define MPS_PORT_STAT_LB_PORT_128B_255B_L 0x500 +#define MPS_PORT_STAT_LB_PORT_128B_255B_H 0x504 +#define MPS_PORT_STAT_LB_PORT_256B_511B_L 0x508 +#define MPS_PORT_STAT_LB_PORT_256B_511B_H 0x50c +#define MPS_PORT_STAT_LB_PORT_512B_1023B_L 0x510 +#define MPS_PORT_STAT_LB_PORT_512B_1023B_H 0x514 +#define MPS_PORT_STAT_LB_PORT_1024B_1518B_L 0x518 +#define MPS_PORT_STAT_LB_PORT_1024B_1518B_H 0x51c +#define MPS_PORT_STAT_LB_PORT_1519B_MAX_L 0x520 +#define MPS_PORT_STAT_LB_PORT_1519B_MAX_H 0x524 +#define MPS_PORT_STAT_LB_PORT_DROP_FRAMES 0x528 +#define MPS_PORT_STAT_RX_PORT_BYTES_L 0x540 +#define MPS_PORT_STAT_RX_PORT_BYTES_H 0x544 +#define MPS_PORT_STAT_RX_PORT_FRAMES_L 0x548 +#define MPS_PORT_STAT_RX_PORT_FRAMES_H 0x54c +#define MPS_PORT_STAT_RX_PORT_BCAST_L 0x550 +#define MPS_PORT_STAT_RX_PORT_BCAST_H 0x554 +#define MPS_PORT_STAT_RX_PORT_MCAST_L 0x558 +#define MPS_PORT_STAT_RX_PORT_MCAST_H 0x55c +#define MPS_PORT_STAT_RX_PORT_UCAST_L 0x560 +#define MPS_PORT_STAT_RX_PORT_UCAST_H 0x564 +#define MPS_PORT_STAT_RX_PORT_MTU_ERROR_L 0x568 +#define MPS_PORT_STAT_RX_PORT_MTU_ERROR_H 0x56c +#define MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_L 0x570 +#define MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_H 0x574 +#define MPS_PORT_STAT_RX_PORT_CRC_ERROR_L 0x578 +#define MPS_PORT_STAT_RX_PORT_CRC_ERROR_H 0x57c +#define MPS_PORT_STAT_RX_PORT_LEN_ERROR_L 0x580 +#define MPS_PORT_STAT_RX_PORT_LEN_ERROR_H 0x584 +#define MPS_PORT_STAT_RX_PORT_SYM_ERROR_L 0x588 +#define MPS_PORT_STAT_RX_PORT_SYM_ERROR_H 0x58c +#define MPS_PORT_STAT_RX_PORT_64B_L 0x590 +#define MPS_PORT_STAT_RX_PORT_64B_H 0x594 +#define MPS_PORT_STAT_RX_PORT_65B_127B_L 0x598 +#define MPS_PORT_STAT_RX_PORT_65B_127B_H 0x59c +#define MPS_PORT_STAT_RX_PORT_128B_255B_L 0x5a0 +#define MPS_PORT_STAT_RX_PORT_128B_255B_H 0x5a4 +#define MPS_PORT_STAT_RX_PORT_256B_511B_L 0x5a8 +#define MPS_PORT_STAT_RX_PORT_256B_511B_H 0x5ac +#define MPS_PORT_STAT_RX_PORT_512B_1023B_L 0x5b0 +#define MPS_PORT_STAT_RX_PORT_512B_1023B_H 0x5b4 +#define MPS_PORT_STAT_RX_PORT_1024B_1518B_L 0x5b8 +#define MPS_PORT_STAT_RX_PORT_1024B_1518B_H 0x5bc +#define MPS_PORT_STAT_RX_PORT_1519B_MAX_L 0x5c0 +#define MPS_PORT_STAT_RX_PORT_1519B_MAX_H 0x5c4 +#define MPS_PORT_STAT_RX_PORT_PAUSE_L 0x5c8 +#define MPS_PORT_STAT_RX_PORT_PAUSE_H 0x5cc +#define MPS_PORT_STAT_RX_PORT_PPP0_L 0x5d0 +#define MPS_PORT_STAT_RX_PORT_PPP0_H 0x5d4 +#define MPS_PORT_STAT_RX_PORT_PPP1_L 0x5d8 +#define MPS_PORT_STAT_RX_PORT_PPP1_H 0x5dc +#define MPS_PORT_STAT_RX_PORT_PPP2_L 0x5e0 +#define MPS_PORT_STAT_RX_PORT_PPP2_H 0x5e4 +#define MPS_PORT_STAT_RX_PORT_PPP3_L 0x5e8 +#define MPS_PORT_STAT_RX_PORT_PPP3_H 0x5ec +#define MPS_PORT_STAT_RX_PORT_PPP4_L 0x5f0 +#define MPS_PORT_STAT_RX_PORT_PPP4_H 0x5f4 +#define MPS_PORT_STAT_RX_PORT_PPP5_L 0x5f8 +#define MPS_PORT_STAT_RX_PORT_PPP5_H 0x5fc +#define MPS_PORT_STAT_RX_PORT_PPP6_L 0x600 +#define MPS_PORT_STAT_RX_PORT_PPP6_H 0x604 +#define MPS_PORT_STAT_RX_PORT_PPP7_L 0x608 +#define MPS_PORT_STAT_RX_PORT_PPP7_H 0x60c +#define MPS_PORT_STAT_RX_PORT_LESS_64B_L 0x610 +#define MPS_PORT_STAT_RX_PORT_LESS_64B_H 0x614 +#define MPS_CMN_CTL 0x9000 +#define  NUMPORTS_MASK   0x00000003U +#define  NUMPORTS_SHIFT  0 +#define  NUMPORTS_GET(x) (((x) & NUMPORTS_MASK) >> NUMPORTS_SHIFT) + +#define MPS_INT_CAUSE 0x9008 +#define  STATINT 0x00000020U +#define  TXINT   0x00000010U +#define  RXINT   0x00000008U +#define  TRCINT  0x00000004U +#define  CLSINT  0x00000002U +#define  PLINT   0x00000001U + +#define MPS_TX_INT_CAUSE 0x9408 +#define  PORTERR    0x00010000U +#define  FRMERR     0x00008000U +#define  SECNTERR   0x00004000U +#define  BUBBLE     0x00002000U +#define  TXDESCFIFO 0x00001e00U +#define  TXDATAFIFO 0x000001e0U +#define  NCSIFIFO   0x00000010U +#define  TPFIFO     0x0000000fU + +#define MPS_STAT_PERR_INT_CAUSE_SRAM 0x9614 +#define MPS_STAT_PERR_INT_CAUSE_TX_FIFO 0x9620 +#define MPS_STAT_PERR_INT_CAUSE_RX_FIFO 0x962c + +#define MPS_STAT_RX_BG_0_MAC_DROP_FRAME_L 0x9640 +#define MPS_STAT_RX_BG_0_MAC_DROP_FRAME_H 0x9644 +#define MPS_STAT_RX_BG_1_MAC_DROP_FRAME_L 0x9648 +#define MPS_STAT_RX_BG_1_MAC_DROP_FRAME_H 0x964c +#define MPS_STAT_RX_BG_2_MAC_DROP_FRAME_L 0x9650 +#define MPS_STAT_RX_BG_2_MAC_DROP_FRAME_H 0x9654 +#define MPS_STAT_RX_BG_3_MAC_DROP_FRAME_L 0x9658 +#define MPS_STAT_RX_BG_3_MAC_DROP_FRAME_H 0x965c +#define MPS_STAT_RX_BG_0_LB_DROP_FRAME_L 0x9660 +#define MPS_STAT_RX_BG_0_LB_DROP_FRAME_H 0x9664 +#define MPS_STAT_RX_BG_1_LB_DROP_FRAME_L 0x9668 +#define MPS_STAT_RX_BG_1_LB_DROP_FRAME_H 0x966c +#define MPS_STAT_RX_BG_2_LB_DROP_FRAME_L 0x9670 +#define MPS_STAT_RX_BG_2_LB_DROP_FRAME_H 0x9674 +#define MPS_STAT_RX_BG_3_LB_DROP_FRAME_L 0x9678 +#define MPS_STAT_RX_BG_3_LB_DROP_FRAME_H 0x967c +#define MPS_STAT_RX_BG_0_MAC_TRUNC_FRAME_L 0x9680 +#define MPS_STAT_RX_BG_0_MAC_TRUNC_FRAME_H 0x9684 +#define MPS_STAT_RX_BG_1_MAC_TRUNC_FRAME_L 0x9688 +#define MPS_STAT_RX_BG_1_MAC_TRUNC_FRAME_H 0x968c +#define MPS_STAT_RX_BG_2_MAC_TRUNC_FRAME_L 0x9690 +#define MPS_STAT_RX_BG_2_MAC_TRUNC_FRAME_H 0x9694 +#define MPS_STAT_RX_BG_3_MAC_TRUNC_FRAME_L 0x9698 +#define MPS_STAT_RX_BG_3_MAC_TRUNC_FRAME_H 0x969c +#define MPS_STAT_RX_BG_0_LB_TRUNC_FRAME_L 0x96a0 +#define MPS_STAT_RX_BG_0_LB_TRUNC_FRAME_H 0x96a4 +#define MPS_STAT_RX_BG_1_LB_TRUNC_FRAME_L 0x96a8 +#define MPS_STAT_RX_BG_1_LB_TRUNC_FRAME_H 0x96ac +#define MPS_STAT_RX_BG_2_LB_TRUNC_FRAME_L 0x96b0 +#define MPS_STAT_RX_BG_2_LB_TRUNC_FRAME_H 0x96b4 +#define MPS_STAT_RX_BG_3_LB_TRUNC_FRAME_L 0x96b8 +#define MPS_STAT_RX_BG_3_LB_TRUNC_FRAME_H 0x96bc +#define MPS_TRC_CFG 0x9800 +#define  TRCFIFOEMPTY       0x00000010U +#define  TRCIGNOREDROPINPUT 0x00000008U +#define  TRCKEEPDUPLICATES  0x00000004U +#define  TRCEN              0x00000002U +#define  TRCMULTIFILTER     0x00000001U + +#define MPS_TRC_RSS_CONTROL 0x9808 +#define  RSSCONTROL_MASK    0x00ff0000U +#define  RSSCONTROL_SHIFT   16 +#define  RSSCONTROL(x)      ((x) << RSSCONTROL_SHIFT) +#define  QUEUENUMBER_MASK   0x0000ffffU +#define  QUEUENUMBER_SHIFT  0 +#define  QUEUENUMBER(x)     ((x) << QUEUENUMBER_SHIFT) + +#define MPS_TRC_FILTER_MATCH_CTL_A 0x9810 +#define  TFINVERTMATCH   0x01000000U +#define  TFPKTTOOLARGE   0x00800000U +#define  TFEN            0x00400000U +#define  TFPORT_MASK     0x003c0000U +#define  TFPORT_SHIFT    18 +#define  TFPORT(x)       ((x) << TFPORT_SHIFT) +#define  TFPORT_GET(x)   (((x) & TFPORT_MASK) >> TFPORT_SHIFT) +#define  TFDROP          0x00020000U +#define  TFSOPEOPERR     0x00010000U +#define  TFLENGTH_MASK   0x00001f00U +#define  TFLENGTH_SHIFT  8 +#define  TFLENGTH(x)     ((x) << TFLENGTH_SHIFT) +#define  TFLENGTH_GET(x) (((x) & TFLENGTH_MASK) >> TFLENGTH_SHIFT) +#define  TFOFFSET_MASK   0x0000001fU +#define  TFOFFSET_SHIFT  0 +#define  TFOFFSET(x)     ((x) << TFOFFSET_SHIFT) +#define  TFOFFSET_GET(x) (((x) & TFOFFSET_MASK) >> TFOFFSET_SHIFT) + +#define MPS_TRC_FILTER_MATCH_CTL_B 0x9820 +#define  TFMINPKTSIZE_MASK   0x01ff0000U +#define  TFMINPKTSIZE_SHIFT  16 +#define  TFMINPKTSIZE(x)     ((x) << TFMINPKTSIZE_SHIFT) +#define  TFMINPKTSIZE_GET(x) (((x) & TFMINPKTSIZE_MASK) >> TFMINPKTSIZE_SHIFT) +#define  TFCAPTUREMAX_MASK   0x00003fffU +#define  TFCAPTUREMAX_SHIFT  0 +#define  TFCAPTUREMAX(x)     ((x) << TFCAPTUREMAX_SHIFT) +#define  TFCAPTUREMAX_GET(x) (((x) & TFCAPTUREMAX_MASK) >> TFCAPTUREMAX_SHIFT) + +#define MPS_TRC_INT_CAUSE 0x985c +#define  MISCPERR 0x00000100U +#define  PKTFIFO  0x000000f0U +#define  FILTMEM  0x0000000fU + +#define MPS_TRC_FILTER0_MATCH 0x9c00 +#define MPS_TRC_FILTER0_DONT_CARE 0x9c80 +#define MPS_TRC_FILTER1_MATCH 0x9d00 +#define MPS_CLS_INT_CAUSE 0xd028 +#define  PLERRENB  0x00000008U +#define  HASHSRAM  0x00000004U +#define  MATCHTCAM 0x00000002U +#define  MATCHSRAM 0x00000001U + +#define MPS_RX_PERR_INT_CAUSE 0x11074 + +#define CPL_INTR_CAUSE 0x19054 +#define  CIM_OP_MAP_PERR   0x00000020U +#define  CIM_OVFL_ERROR    0x00000010U +#define  TP_FRAMING_ERROR  0x00000008U +#define  SGE_FRAMING_ERROR 0x00000004U +#define  CIM_FRAMING_ERROR 0x00000002U +#define  ZERO_SWITCH_ERROR 0x00000001U + +#define SMB_INT_CAUSE 0x19090 +#define  MSTTXFIFOPARINT 0x00200000U +#define  MSTRXFIFOPARINT 0x00100000U +#define  SLVFIFOPARINT   0x00080000U + +#define ULP_RX_INT_CAUSE 0x19158 +#define ULP_RX_ISCSI_TAGMASK 0x19164 +#define ULP_RX_ISCSI_PSZ 0x19168 +#define  HPZ3_MASK   0x0f000000U +#define  HPZ3_SHIFT  24 +#define  HPZ3(x)     ((x) << HPZ3_SHIFT) +#define  HPZ2_MASK   0x000f0000U +#define  HPZ2_SHIFT  16 +#define  HPZ2(x)     ((x) << HPZ2_SHIFT) +#define  HPZ1_MASK   0x00000f00U +#define  HPZ1_SHIFT  8 +#define  HPZ1(x)     ((x) << HPZ1_SHIFT) +#define  HPZ0_MASK   0x0000000fU +#define  HPZ0_SHIFT  0 +#define  HPZ0(x)     ((x) << HPZ0_SHIFT) + +#define ULP_RX_TDDP_PSZ 0x19178 + +#define SF_DATA 0x193f8 +#define SF_OP 0x193fc +#define  BUSY          0x80000000U +#define  SF_LOCK       0x00000010U +#define  SF_CONT       0x00000008U +#define  BYTECNT_MASK  0x00000006U +#define  BYTECNT_SHIFT 1 +#define  BYTECNT(x)    ((x) << BYTECNT_SHIFT) +#define  OP_WR         0x00000001U + +#define PL_PF_INT_CAUSE 0x3c0 +#define  PFSW  0x00000008U +#define  PFSGE 0x00000004U +#define  PFCIM 0x00000002U +#define  PFMPS 0x00000001U + +#define PL_PF_INT_ENABLE 0x3c4 +#define PL_PF_CTL 0x3c8 +#define  SWINT 0x00000001U + +#define PL_WHOAMI 0x19400 +#define  SOURCEPF_MASK   0x00000700U +#define  SOURCEPF_SHIFT  8 +#define  SOURCEPF(x)     ((x) << SOURCEPF_SHIFT) +#define  SOURCEPF_GET(x) (((x) & SOURCEPF_MASK) >> SOURCEPF_SHIFT) +#define  ISVF            0x00000080U +#define  VFID_MASK       0x0000007fU +#define  VFID_SHIFT      0 +#define  VFID(x)         ((x) << VFID_SHIFT) +#define  VFID_GET(x)     (((x) & VFID_MASK) >> VFID_SHIFT) + +#define PL_INT_CAUSE 0x1940c +#define  ULP_TX     0x08000000U +#define  SGE        0x04000000U +#define  HMA        0x02000000U +#define  CPL_SWITCH 0x01000000U +#define  ULP_RX     0x00800000U +#define  PM_RX      0x00400000U +#define  PM_TX      0x00200000U +#define  MA         0x00100000U +#define  TP         0x00080000U +#define  LE         0x00040000U +#define  EDC1       0x00020000U +#define  EDC0       0x00010000U +#define  MC         0x00008000U +#define  PCIE       0x00004000U +#define  PMU        0x00002000U +#define  XGMAC_KR1  0x00001000U +#define  XGMAC_KR0  0x00000800U +#define  XGMAC1     0x00000400U +#define  XGMAC0     0x00000200U +#define  SMB        0x00000100U +#define  SF         0x00000080U +#define  PL         0x00000040U +#define  NCSI       0x00000020U +#define  MPS        0x00000010U +#define  MI         0x00000008U +#define  DBG        0x00000004U +#define  I2CM       0x00000002U +#define  CIM        0x00000001U + +#define PL_INT_MAP0 0x19414 +#define PL_RST 0x19428 +#define  PIORST     0x00000002U +#define  PIORSTMODE 0x00000001U + +#define PL_PL_INT_CAUSE 0x19430 +#define  FATALPERR 0x00000010U +#define  PERRVFID  0x00000001U + +#define PL_REV 0x1943c + +#define LE_DB_CONFIG 0x19c04 +#define  HASHEN 0x00100000U + +#define LE_DB_SERVER_INDEX 0x19c18 +#define LE_DB_ACT_CNT_IPV4 0x19c20 +#define LE_DB_ACT_CNT_IPV6 0x19c24 + +#define LE_DB_INT_CAUSE 0x19c3c +#define  REQQPARERR 0x00010000U +#define  UNKNOWNCMD 0x00008000U +#define  PARITYERR  0x00000040U +#define  LIPMISS    0x00000020U +#define  LIP0       0x00000010U + +#define LE_DB_TID_HASHBASE 0x19df8 + +#define NCSI_INT_CAUSE 0x1a0d8 +#define  CIM_DM_PRTY_ERR 0x00000100U +#define  MPS_DM_PRTY_ERR 0x00000080U +#define  TXFIFO_PRTY_ERR 0x00000002U +#define  RXFIFO_PRTY_ERR 0x00000001U + +#define XGMAC_PORT_CFG2 0x1018 +#define  PATEN   0x00040000U +#define  MAGICEN 0x00020000U + +#define XGMAC_PORT_MAGIC_MACID_LO 0x1024 +#define XGMAC_PORT_MAGIC_MACID_HI 0x1028 + +#define XGMAC_PORT_EPIO_DATA0 0x10c0 +#define XGMAC_PORT_EPIO_DATA1 0x10c4 +#define XGMAC_PORT_EPIO_DATA2 0x10c8 +#define XGMAC_PORT_EPIO_DATA3 0x10cc +#define XGMAC_PORT_EPIO_OP 0x10d0 +#define  EPIOWR         0x00000100U +#define  ADDRESS_MASK   0x000000ffU +#define  ADDRESS_SHIFT  0 +#define  ADDRESS(x)     ((x) << ADDRESS_SHIFT) + +#define XGMAC_PORT_INT_CAUSE 0x10dc +#endif /* __T4_REGS_H */ diff --git a/drivers/net/cxgb4/t4fw_api.h b/drivers/net/cxgb4/t4fw_api.h new file mode 100644 index 00000000000..3393d05a388 --- /dev/null +++ b/drivers/net/cxgb4/t4fw_api.h @@ -0,0 +1,1580 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses.  You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + *     Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *      - Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + * + *      - Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _T4FW_INTERFACE_H_ +#define _T4FW_INTERFACE_H_ + +#define FW_T4VF_SGE_BASE_ADDR      0x0000 +#define FW_T4VF_MPS_BASE_ADDR      0x0100 +#define FW_T4VF_PL_BASE_ADDR       0x0200 +#define FW_T4VF_MBDATA_BASE_ADDR   0x0240 +#define FW_T4VF_CIM_BASE_ADDR      0x0300 + +enum fw_wr_opcodes { +	FW_FILTER_WR                   = 0x02, +	FW_ULPTX_WR                    = 0x04, +	FW_TP_WR                       = 0x05, +	FW_ETH_TX_PKT_WR               = 0x08, +	FW_FLOWC_WR                    = 0x0a, +	FW_OFLD_TX_DATA_WR             = 0x0b, +	FW_CMD_WR                      = 0x10, +	FW_ETH_TX_PKT_VM_WR            = 0x11, +	FW_RI_RES_WR                   = 0x0c, +	FW_RI_INIT_WR                  = 0x0d, +	FW_RI_RDMA_WRITE_WR            = 0x14, +	FW_RI_SEND_WR                  = 0x15, +	FW_RI_RDMA_READ_WR             = 0x16, +	FW_RI_RECV_WR                  = 0x17, +	FW_RI_BIND_MW_WR               = 0x18, +	FW_RI_FR_NSMR_WR               = 0x19, +	FW_RI_INV_LSTAG_WR             = 0x1a, +	FW_LASTC2E_WR                  = 0x40 +}; + +struct fw_wr_hdr { +	__be32 hi; +	__be32 lo; +}; + +#define FW_WR_OP(x)	 ((x) << 24) +#define FW_WR_ATOMIC(x)	 ((x) << 23) +#define FW_WR_FLUSH(x)   ((x) << 22) +#define FW_WR_COMPL(x)   ((x) << 21) +#define FW_WR_IMMDLEN(x) ((x) << 0) + +#define FW_WR_EQUIQ	(1U << 31) +#define FW_WR_EQUEQ	(1U << 30) +#define FW_WR_FLOWID(x)	((x) << 8) +#define FW_WR_LEN16(x)	((x) << 0) + +struct fw_ulptx_wr { +	__be32 op_to_compl; +	__be32 flowid_len16; +	u64 cookie; +}; + +struct fw_tp_wr { +	__be32 op_to_immdlen; +	__be32 flowid_len16; +	u64 cookie; +}; + +struct fw_eth_tx_pkt_wr { +	__be32 op_immdlen; +	__be32 equiq_to_len16; +	__be64 r3; +}; + +enum fw_flowc_mnem { +	FW_FLOWC_MNEM_PFNVFN,		/* PFN [15:8] VFN [7:0] */ +	FW_FLOWC_MNEM_CH, +	FW_FLOWC_MNEM_PORT, +	FW_FLOWC_MNEM_IQID, +	FW_FLOWC_MNEM_SNDNXT, +	FW_FLOWC_MNEM_RCVNXT, +	FW_FLOWC_MNEM_SNDBUF, +	FW_FLOWC_MNEM_MSS, +}; + +struct fw_flowc_mnemval { +	u8 mnemonic; +	u8 r4[3]; +	__be32 val; +}; + +struct fw_flowc_wr { +	__be32 op_to_nparams; +#define FW_FLOWC_WR_NPARAMS(x)	((x) << 0) +	__be32 flowid_len16; +	struct fw_flowc_mnemval mnemval[0]; +}; + +struct fw_ofld_tx_data_wr { +	__be32 op_to_immdlen; +	__be32 flowid_len16; +	__be32 plen; +	__be32 tunnel_to_proxy; +#define FW_OFLD_TX_DATA_WR_TUNNEL(x)	 ((x) << 19) +#define FW_OFLD_TX_DATA_WR_SAVE(x)	 ((x) << 18) +#define FW_OFLD_TX_DATA_WR_FLUSH(x)	 ((x) << 17) +#define FW_OFLD_TX_DATA_WR_URGENT(x)	 ((x) << 16) +#define FW_OFLD_TX_DATA_WR_MORE(x)	 ((x) << 15) +#define FW_OFLD_TX_DATA_WR_SHOVE(x)	 ((x) << 14) +#define FW_OFLD_TX_DATA_WR_ULPMODE(x)	 ((x) << 10) +#define FW_OFLD_TX_DATA_WR_ULPSUBMODE(x) ((x) << 6) +}; + +struct fw_cmd_wr { +	__be32 op_dma; +#define FW_CMD_WR_DMA (1U << 17) +	__be32 len16_pkd; +	__be64 cookie_daddr; +}; + +struct fw_eth_tx_pkt_vm_wr { +	__be32 op_immdlen; +	__be32 equiq_to_len16; +	__be32 r3[2]; +	u8 ethmacdst[6]; +	u8 ethmacsrc[6]; +	__be16 ethtype; +	__be16 vlantci; +}; + +#define FW_CMD_MAX_TIMEOUT 3000 + +enum fw_cmd_opcodes { +	FW_LDST_CMD                    = 0x01, +	FW_RESET_CMD                   = 0x03, +	FW_HELLO_CMD                   = 0x04, +	FW_BYE_CMD                     = 0x05, +	FW_INITIALIZE_CMD              = 0x06, +	FW_CAPS_CONFIG_CMD             = 0x07, +	FW_PARAMS_CMD                  = 0x08, +	FW_PFVF_CMD                    = 0x09, +	FW_IQ_CMD                      = 0x10, +	FW_EQ_MNGT_CMD                 = 0x11, +	FW_EQ_ETH_CMD                  = 0x12, +	FW_EQ_CTRL_CMD                 = 0x13, +	FW_EQ_OFLD_CMD                 = 0x21, +	FW_VI_CMD                      = 0x14, +	FW_VI_MAC_CMD                  = 0x15, +	FW_VI_RXMODE_CMD               = 0x16, +	FW_VI_ENABLE_CMD               = 0x17, +	FW_ACL_MAC_CMD                 = 0x18, +	FW_ACL_VLAN_CMD                = 0x19, +	FW_VI_STATS_CMD                = 0x1a, +	FW_PORT_CMD                    = 0x1b, +	FW_PORT_STATS_CMD              = 0x1c, +	FW_PORT_LB_STATS_CMD           = 0x1d, +	FW_PORT_TRACE_CMD              = 0x1e, +	FW_PORT_TRACE_MMAP_CMD         = 0x1f, +	FW_RSS_IND_TBL_CMD             = 0x20, +	FW_RSS_GLB_CONFIG_CMD          = 0x22, +	FW_RSS_VI_CONFIG_CMD           = 0x23, +	FW_LASTC2E_CMD                 = 0x40, +	FW_ERROR_CMD                   = 0x80, +	FW_DEBUG_CMD                   = 0x81, +}; + +enum fw_cmd_cap { +	FW_CMD_CAP_PF                  = 0x01, +	FW_CMD_CAP_DMAQ                = 0x02, +	FW_CMD_CAP_PORT                = 0x04, +	FW_CMD_CAP_PORTPROMISC         = 0x08, +	FW_CMD_CAP_PORTSTATS           = 0x10, +	FW_CMD_CAP_VF                  = 0x80, +}; + +/* + * Generic command header flit0 + */ +struct fw_cmd_hdr { +	__be32 hi; +	__be32 lo; +}; + +#define FW_CMD_OP(x)		((x) << 24) +#define FW_CMD_OP_GET(x)        (((x) >> 24) & 0xff) +#define FW_CMD_REQUEST          (1U << 23) +#define FW_CMD_READ		(1U << 22) +#define FW_CMD_WRITE		(1U << 21) +#define FW_CMD_EXEC		(1U << 20) +#define FW_CMD_RAMASK(x)	((x) << 20) +#define FW_CMD_RETVAL(x)	((x) << 8) +#define FW_CMD_RETVAL_GET(x)	(((x) >> 8) & 0xff) +#define FW_CMD_LEN16(x)         ((x) << 0) + +enum fw_ldst_addrspc { +	FW_LDST_ADDRSPC_FIRMWARE  = 0x0001, +	FW_LDST_ADDRSPC_SGE_EGRC  = 0x0008, +	FW_LDST_ADDRSPC_SGE_INGC  = 0x0009, +	FW_LDST_ADDRSPC_SGE_FLMC  = 0x000a, +	FW_LDST_ADDRSPC_SGE_CONMC = 0x000b, +	FW_LDST_ADDRSPC_TP_PIO    = 0x0010, +	FW_LDST_ADDRSPC_TP_TM_PIO = 0x0011, +	FW_LDST_ADDRSPC_TP_MIB    = 0x0012, +	FW_LDST_ADDRSPC_MDIO      = 0x0018, +	FW_LDST_ADDRSPC_MPS       = 0x0020, +	FW_LDST_ADDRSPC_FUNC      = 0x0028 +}; + +enum fw_ldst_mps_fid { +	FW_LDST_MPS_ATRB, +	FW_LDST_MPS_RPLC +}; + +enum fw_ldst_func_access_ctl { +	FW_LDST_FUNC_ACC_CTL_VIID, +	FW_LDST_FUNC_ACC_CTL_FID +}; + +enum fw_ldst_func_mod_index { +	FW_LDST_FUNC_MPS +}; + +struct fw_ldst_cmd { +	__be32 op_to_addrspace; +#define FW_LDST_CMD_ADDRSPACE(x) ((x) << 0) +	__be32 cycles_to_len16; +	union fw_ldst { +		struct fw_ldst_addrval { +			__be32 addr; +			__be32 val; +		} addrval; +		struct fw_ldst_idctxt { +			__be32 physid; +			__be32 msg_pkd; +			__be32 ctxt_data7; +			__be32 ctxt_data6; +			__be32 ctxt_data5; +			__be32 ctxt_data4; +			__be32 ctxt_data3; +			__be32 ctxt_data2; +			__be32 ctxt_data1; +			__be32 ctxt_data0; +		} idctxt; +		struct fw_ldst_mdio { +			__be16 paddr_mmd; +			__be16 raddr; +			__be16 vctl; +			__be16 rval; +		} mdio; +		struct fw_ldst_mps { +			__be16 fid_ctl; +			__be16 rplcpf_pkd; +			__be32 rplc127_96; +			__be32 rplc95_64; +			__be32 rplc63_32; +			__be32 rplc31_0; +			__be32 atrb; +			__be16 vlan[16]; +		} mps; +		struct fw_ldst_func { +			u8 access_ctl; +			u8 mod_index; +			__be16 ctl_id; +			__be32 offset; +			__be64 data0; +			__be64 data1; +		} func; +	} u; +}; + +#define FW_LDST_CMD_MSG(x)	((x) << 31) +#define FW_LDST_CMD_PADDR(x)	((x) << 8) +#define FW_LDST_CMD_MMD(x)	((x) << 0) +#define FW_LDST_CMD_FID(x)	((x) << 15) +#define FW_LDST_CMD_CTL(x)	((x) << 0) +#define FW_LDST_CMD_RPLCPF(x)	((x) << 0) + +struct fw_reset_cmd { +	__be32 op_to_write; +	__be32 retval_len16; +	__be32 val; +	__be32 r3; +}; + +struct fw_hello_cmd { +	__be32 op_to_write; +	__be32 retval_len16; +	__be32 err_to_mbasyncnot; +#define FW_HELLO_CMD_ERR	    (1U << 31) +#define FW_HELLO_CMD_INIT	    (1U << 30) +#define FW_HELLO_CMD_MASTERDIS(x)   ((x) << 29) +#define FW_HELLO_CMD_MASTERFORCE(x) ((x) << 28) +#define FW_HELLO_CMD_MBMASTER(x)    ((x) << 24) +#define FW_HELLO_CMD_MBASYNCNOT(x)  ((x) << 20) +	__be32 fwrev; +}; + +struct fw_bye_cmd { +	__be32 op_to_write; +	__be32 retval_len16; +	__be64 r3; +}; + +struct fw_initialize_cmd { +	__be32 op_to_write; +	__be32 retval_len16; +	__be64 r3; +}; + +enum fw_caps_config_hm { +	FW_CAPS_CONFIG_HM_PCIE		= 0x00000001, +	FW_CAPS_CONFIG_HM_PL		= 0x00000002, +	FW_CAPS_CONFIG_HM_SGE		= 0x00000004, +	FW_CAPS_CONFIG_HM_CIM		= 0x00000008, +	FW_CAPS_CONFIG_HM_ULPTX		= 0x00000010, +	FW_CAPS_CONFIG_HM_TP		= 0x00000020, +	FW_CAPS_CONFIG_HM_ULPRX		= 0x00000040, +	FW_CAPS_CONFIG_HM_PMRX		= 0x00000080, +	FW_CAPS_CONFIG_HM_PMTX		= 0x00000100, +	FW_CAPS_CONFIG_HM_MC		= 0x00000200, +	FW_CAPS_CONFIG_HM_LE		= 0x00000400, +	FW_CAPS_CONFIG_HM_MPS		= 0x00000800, +	FW_CAPS_CONFIG_HM_XGMAC		= 0x00001000, +	FW_CAPS_CONFIG_HM_CPLSWITCH	= 0x00002000, +	FW_CAPS_CONFIG_HM_T4DBG		= 0x00004000, +	FW_CAPS_CONFIG_HM_MI		= 0x00008000, +	FW_CAPS_CONFIG_HM_I2CM		= 0x00010000, +	FW_CAPS_CONFIG_HM_NCSI		= 0x00020000, +	FW_CAPS_CONFIG_HM_SMB		= 0x00040000, +	FW_CAPS_CONFIG_HM_MA		= 0x00080000, +	FW_CAPS_CONFIG_HM_EDRAM		= 0x00100000, +	FW_CAPS_CONFIG_HM_PMU		= 0x00200000, +	FW_CAPS_CONFIG_HM_UART		= 0x00400000, +	FW_CAPS_CONFIG_HM_SF		= 0x00800000, +}; + +enum fw_caps_config_nbm { +	FW_CAPS_CONFIG_NBM_IPMI		= 0x00000001, +	FW_CAPS_CONFIG_NBM_NCSI		= 0x00000002, +}; + +enum fw_caps_config_link { +	FW_CAPS_CONFIG_LINK_PPP		= 0x00000001, +	FW_CAPS_CONFIG_LINK_QFC		= 0x00000002, +	FW_CAPS_CONFIG_LINK_DCBX	= 0x00000004, +}; + +enum fw_caps_config_switch { +	FW_CAPS_CONFIG_SWITCH_INGRESS	= 0x00000001, +	FW_CAPS_CONFIG_SWITCH_EGRESS	= 0x00000002, +}; + +enum fw_caps_config_nic { +	FW_CAPS_CONFIG_NIC		= 0x00000001, +	FW_CAPS_CONFIG_NIC_VM		= 0x00000002, +}; + +enum fw_caps_config_ofld { +	FW_CAPS_CONFIG_OFLD		= 0x00000001, +}; + +enum fw_caps_config_rdma { +	FW_CAPS_CONFIG_RDMA_RDDP	= 0x00000001, +	FW_CAPS_CONFIG_RDMA_RDMAC	= 0x00000002, +}; + +enum fw_caps_config_iscsi { +	FW_CAPS_CONFIG_ISCSI_INITIATOR_PDU = 0x00000001, +	FW_CAPS_CONFIG_ISCSI_TARGET_PDU = 0x00000002, +	FW_CAPS_CONFIG_ISCSI_INITIATOR_CNXOFLD = 0x00000004, +	FW_CAPS_CONFIG_ISCSI_TARGET_CNXOFLD = 0x00000008, +}; + +enum fw_caps_config_fcoe { +	FW_CAPS_CONFIG_FCOE_INITIATOR	= 0x00000001, +	FW_CAPS_CONFIG_FCOE_TARGET	= 0x00000002, +}; + +struct fw_caps_config_cmd { +	__be32 op_to_write; +	__be32 retval_len16; +	__be32 r2; +	__be32 hwmbitmap; +	__be16 nbmcaps; +	__be16 linkcaps; +	__be16 switchcaps; +	__be16 r3; +	__be16 niccaps; +	__be16 ofldcaps; +	__be16 rdmacaps; +	__be16 r4; +	__be16 iscsicaps; +	__be16 fcoecaps; +	__be32 r5; +	__be64 r6; +}; + +/* + * params command mnemonics + */ +enum fw_params_mnem { +	FW_PARAMS_MNEM_DEV		= 1,	/* device params */ +	FW_PARAMS_MNEM_PFVF		= 2,	/* function params */ +	FW_PARAMS_MNEM_REG		= 3,	/* limited register access */ +	FW_PARAMS_MNEM_DMAQ		= 4,	/* dma queue params */ +	FW_PARAMS_MNEM_LAST +}; + +/* + * device parameters + */ +enum fw_params_param_dev { +	FW_PARAMS_PARAM_DEV_CCLK	= 0x00, /* chip core clock in khz */ +	FW_PARAMS_PARAM_DEV_PORTVEC	= 0x01, /* the port vector */ +	FW_PARAMS_PARAM_DEV_NTID	= 0x02, /* reads the number of TIDs +						 * allocated by the device's +						 * Lookup Engine +						 */ +	FW_PARAMS_PARAM_DEV_FLOWC_BUFFIFO_SZ = 0x03, +	FW_PARAMS_PARAM_DEV_INTVER_NIC	= 0x04, +	FW_PARAMS_PARAM_DEV_INTVER_VNIC = 0x05, +	FW_PARAMS_PARAM_DEV_INTVER_OFLD = 0x06, +	FW_PARAMS_PARAM_DEV_INTVER_RI	= 0x07, +	FW_PARAMS_PARAM_DEV_INTVER_ISCSIPDU = 0x08, +	FW_PARAMS_PARAM_DEV_INTVER_ISCSI = 0x09, +	FW_PARAMS_PARAM_DEV_INTVER_FCOE = 0x0A +}; + +/* + * physical and virtual function parameters + */ +enum fw_params_param_pfvf { +	FW_PARAMS_PARAM_PFVF_RWXCAPS	= 0x00, +	FW_PARAMS_PARAM_PFVF_ROUTE_START = 0x01, +	FW_PARAMS_PARAM_PFVF_ROUTE_END = 0x02, +	FW_PARAMS_PARAM_PFVF_CLIP_START = 0x03, +	FW_PARAMS_PARAM_PFVF_CLIP_END = 0x04, +	FW_PARAMS_PARAM_PFVF_FILTER_START = 0x05, +	FW_PARAMS_PARAM_PFVF_FILTER_END = 0x06, +	FW_PARAMS_PARAM_PFVF_SERVER_START = 0x07, +	FW_PARAMS_PARAM_PFVF_SERVER_END = 0x08, +	FW_PARAMS_PARAM_PFVF_TDDP_START = 0x09, +	FW_PARAMS_PARAM_PFVF_TDDP_END = 0x0A, +	FW_PARAMS_PARAM_PFVF_ISCSI_START = 0x0B, +	FW_PARAMS_PARAM_PFVF_ISCSI_END = 0x0C, +	FW_PARAMS_PARAM_PFVF_STAG_START = 0x0D, +	FW_PARAMS_PARAM_PFVF_STAG_END = 0x0E, +	FW_PARAMS_PARAM_PFVF_RQ_START = 0x1F, +	FW_PARAMS_PARAM_PFVF_RQ_END	= 0x10, +	FW_PARAMS_PARAM_PFVF_PBL_START = 0x11, +	FW_PARAMS_PARAM_PFVF_PBL_END	= 0x12, +	FW_PARAMS_PARAM_PFVF_L2T_START = 0x13, +	FW_PARAMS_PARAM_PFVF_L2T_END = 0x14, +	FW_PARAMS_PARAM_PFVF_SCHEDCLASS_ETH = 0x20, +}; + +/* + * dma queue parameters + */ +enum fw_params_param_dmaq { +	FW_PARAMS_PARAM_DMAQ_IQ_DCAEN_DCACPU = 0x00, +	FW_PARAMS_PARAM_DMAQ_IQ_INTCNTTHRESH = 0x01, +	FW_PARAMS_PARAM_DMAQ_EQ_CMPLIQID_MNGT = 0x10, +	FW_PARAMS_PARAM_DMAQ_EQ_CMPLIQID_CTRL = 0x11, +	FW_PARAMS_PARAM_DMAQ_EQ_SCHEDCLASS_ETH = 0x12, +}; + +#define FW_PARAMS_MNEM(x)      ((x) << 24) +#define FW_PARAMS_PARAM_X(x)   ((x) << 16) +#define FW_PARAMS_PARAM_Y(x)   ((x) << 8) +#define FW_PARAMS_PARAM_Z(x)   ((x) << 0) +#define FW_PARAMS_PARAM_XYZ(x) ((x) << 0) +#define FW_PARAMS_PARAM_YZ(x)  ((x) << 0) + +struct fw_params_cmd { +	__be32 op_to_vfn; +	__be32 retval_len16; +	struct fw_params_param { +		__be32 mnem; +		__be32 val; +	} param[7]; +}; + +#define FW_PARAMS_CMD_PFN(x) ((x) << 8) +#define FW_PARAMS_CMD_VFN(x) ((x) << 0) + +struct fw_pfvf_cmd { +	__be32 op_to_vfn; +	__be32 retval_len16; +	__be32 niqflint_niq; +	__be32 cmask_to_neq; +	__be32 tc_to_nexactf; +	__be32 r_caps_to_nethctrl; +	__be16 nricq; +	__be16 nriqp; +	__be32 r4; +}; + +#define FW_PFVF_CMD_PFN(x) ((x) << 8) +#define FW_PFVF_CMD_VFN(x) ((x) << 0) + +#define FW_PFVF_CMD_NIQFLINT(x) ((x) << 20) +#define FW_PFVF_CMD_NIQFLINT_GET(x) (((x) >> 20) & 0xfff) + +#define FW_PFVF_CMD_NIQ(x) ((x) << 0) +#define FW_PFVF_CMD_NIQ_GET(x) (((x) >> 0) & 0xfffff) + +#define FW_PFVF_CMD_CMASK(x) ((x) << 24) +#define FW_PFVF_CMD_CMASK_GET(x) (((x) >> 24) & 0xf) + +#define FW_PFVF_CMD_PMASK(x) ((x) << 20) +#define FW_PFVF_CMD_PMASK_GET(x) (((x) >> 20) & 0xf) + +#define FW_PFVF_CMD_NEQ(x) ((x) << 0) +#define FW_PFVF_CMD_NEQ_GET(x) (((x) >> 0) & 0xfffff) + +#define FW_PFVF_CMD_TC(x) ((x) << 24) +#define FW_PFVF_CMD_TC_GET(x) (((x) >> 24) & 0xff) + +#define FW_PFVF_CMD_NVI(x) ((x) << 16) +#define FW_PFVF_CMD_NVI_GET(x) (((x) >> 16) & 0xff) + +#define FW_PFVF_CMD_NEXACTF(x) ((x) << 0) +#define FW_PFVF_CMD_NEXACTF_GET(x) (((x) >> 0) & 0xffff) + +#define FW_PFVF_CMD_R_CAPS(x) ((x) << 24) +#define FW_PFVF_CMD_R_CAPS_GET(x) (((x) >> 24) & 0xff) + +#define FW_PFVF_CMD_WX_CAPS(x) ((x) << 16) +#define FW_PFVF_CMD_WX_CAPS_GET(x) (((x) >> 16) & 0xff) + +#define FW_PFVF_CMD_NETHCTRL(x) ((x) << 0) +#define FW_PFVF_CMD_NETHCTRL_GET(x) (((x) >> 0) & 0xffff) + +enum fw_iq_type { +	FW_IQ_TYPE_FL_INT_CAP, +	FW_IQ_TYPE_NO_FL_INT_CAP +}; + +struct fw_iq_cmd { +	__be32 op_to_vfn; +	__be32 alloc_to_len16; +	__be16 physiqid; +	__be16 iqid; +	__be16 fl0id; +	__be16 fl1id; +	__be32 type_to_iqandstindex; +	__be16 iqdroprss_to_iqesize; +	__be16 iqsize; +	__be64 iqaddr; +	__be32 iqns_to_fl0congen; +	__be16 fl0dcaen_to_fl0cidxfthresh; +	__be16 fl0size; +	__be64 fl0addr; +	__be32 fl1cngchmap_to_fl1congen; +	__be16 fl1dcaen_to_fl1cidxfthresh; +	__be16 fl1size; +	__be64 fl1addr; +}; + +#define FW_IQ_CMD_PFN(x) ((x) << 8) +#define FW_IQ_CMD_VFN(x) ((x) << 0) + +#define FW_IQ_CMD_ALLOC (1U << 31) +#define FW_IQ_CMD_FREE (1U << 30) +#define FW_IQ_CMD_MODIFY (1U << 29) +#define FW_IQ_CMD_IQSTART(x) ((x) << 28) +#define FW_IQ_CMD_IQSTOP(x) ((x) << 27) + +#define FW_IQ_CMD_TYPE(x) ((x) << 29) +#define FW_IQ_CMD_IQASYNCH(x) ((x) << 28) +#define FW_IQ_CMD_VIID(x) ((x) << 16) +#define FW_IQ_CMD_IQANDST(x) ((x) << 15) +#define FW_IQ_CMD_IQANUS(x) ((x) << 14) +#define FW_IQ_CMD_IQANUD(x) ((x) << 12) +#define FW_IQ_CMD_IQANDSTINDEX(x) ((x) << 0) + +#define FW_IQ_CMD_IQDROPRSS (1U << 15) +#define FW_IQ_CMD_IQGTSMODE (1U << 14) +#define FW_IQ_CMD_IQPCIECH(x) ((x) << 12) +#define FW_IQ_CMD_IQDCAEN(x) ((x) << 11) +#define FW_IQ_CMD_IQDCACPU(x) ((x) << 6) +#define FW_IQ_CMD_IQINTCNTTHRESH(x) ((x) << 4) +#define FW_IQ_CMD_IQO (1U << 3) +#define FW_IQ_CMD_IQCPRIO(x) ((x) << 2) +#define FW_IQ_CMD_IQESIZE(x) ((x) << 0) + +#define FW_IQ_CMD_IQNS(x) ((x) << 31) +#define FW_IQ_CMD_IQRO(x) ((x) << 30) +#define FW_IQ_CMD_IQFLINTIQHSEN(x) ((x) << 28) +#define FW_IQ_CMD_IQFLINTCONGEN(x) ((x) << 27) +#define FW_IQ_CMD_IQFLINTISCSIC(x) ((x) << 26) +#define FW_IQ_CMD_FL0CNGCHMAP(x) ((x) << 20) +#define FW_IQ_CMD_FL0CACHELOCK(x) ((x) << 15) +#define FW_IQ_CMD_FL0DBP(x) ((x) << 14) +#define FW_IQ_CMD_FL0DATANS(x) ((x) << 13) +#define FW_IQ_CMD_FL0DATARO(x) ((x) << 12) +#define FW_IQ_CMD_FL0CONGCIF(x) ((x) << 11) +#define FW_IQ_CMD_FL0ONCHIP(x) ((x) << 10) +#define FW_IQ_CMD_FL0STATUSPGNS(x) ((x) << 9) +#define FW_IQ_CMD_FL0STATUSPGRO(x) ((x) << 8) +#define FW_IQ_CMD_FL0FETCHNS(x) ((x) << 7) +#define FW_IQ_CMD_FL0FETCHRO(x) ((x) << 6) +#define FW_IQ_CMD_FL0HOSTFCMODE(x) ((x) << 4) +#define FW_IQ_CMD_FL0CPRIO(x) ((x) << 3) +#define FW_IQ_CMD_FL0PADEN (1U << 2) +#define FW_IQ_CMD_FL0PACKEN (1U << 1) +#define FW_IQ_CMD_FL0CONGEN (1U << 0) + +#define FW_IQ_CMD_FL0DCAEN(x) ((x) << 15) +#define FW_IQ_CMD_FL0DCACPU(x) ((x) << 10) +#define FW_IQ_CMD_FL0FBMIN(x) ((x) << 7) +#define FW_IQ_CMD_FL0FBMAX(x) ((x) << 4) +#define FW_IQ_CMD_FL0CIDXFTHRESHO (1U << 3) +#define FW_IQ_CMD_FL0CIDXFTHRESH(x) ((x) << 0) + +#define FW_IQ_CMD_FL1CNGCHMAP(x) ((x) << 20) +#define FW_IQ_CMD_FL1CACHELOCK(x) ((x) << 15) +#define FW_IQ_CMD_FL1DBP(x) ((x) << 14) +#define FW_IQ_CMD_FL1DATANS(x) ((x) << 13) +#define FW_IQ_CMD_FL1DATARO(x) ((x) << 12) +#define FW_IQ_CMD_FL1CONGCIF(x) ((x) << 11) +#define FW_IQ_CMD_FL1ONCHIP(x) ((x) << 10) +#define FW_IQ_CMD_FL1STATUSPGNS(x) ((x) << 9) +#define FW_IQ_CMD_FL1STATUSPGRO(x) ((x) << 8) +#define FW_IQ_CMD_FL1FETCHNS(x) ((x) << 7) +#define FW_IQ_CMD_FL1FETCHRO(x) ((x) << 6) +#define FW_IQ_CMD_FL1HOSTFCMODE(x) ((x) << 4) +#define FW_IQ_CMD_FL1CPRIO(x) ((x) << 3) +#define FW_IQ_CMD_FL1PADEN (1U << 2) +#define FW_IQ_CMD_FL1PACKEN (1U << 1) +#define FW_IQ_CMD_FL1CONGEN (1U << 0) + +#define FW_IQ_CMD_FL1DCAEN(x) ((x) << 15) +#define FW_IQ_CMD_FL1DCACPU(x) ((x) << 10) +#define FW_IQ_CMD_FL1FBMIN(x) ((x) << 7) +#define FW_IQ_CMD_FL1FBMAX(x) ((x) << 4) +#define FW_IQ_CMD_FL1CIDXFTHRESHO (1U << 3) +#define FW_IQ_CMD_FL1CIDXFTHRESH(x) ((x) << 0) + +struct fw_eq_eth_cmd { +	__be32 op_to_vfn; +	__be32 alloc_to_len16; +	__be32 eqid_pkd; +	__be32 physeqid_pkd; +	__be32 fetchszm_to_iqid; +	__be32 dcaen_to_eqsize; +	__be64 eqaddr; +	__be32 viid_pkd; +	__be32 r8_lo; +	__be64 r9; +}; + +#define FW_EQ_ETH_CMD_PFN(x) ((x) << 8) +#define FW_EQ_ETH_CMD_VFN(x) ((x) << 0) +#define FW_EQ_ETH_CMD_ALLOC (1U << 31) +#define FW_EQ_ETH_CMD_FREE (1U << 30) +#define FW_EQ_ETH_CMD_MODIFY (1U << 29) +#define FW_EQ_ETH_CMD_EQSTART (1U << 28) +#define FW_EQ_ETH_CMD_EQSTOP (1U << 27) + +#define FW_EQ_ETH_CMD_EQID(x) ((x) << 0) +#define FW_EQ_ETH_CMD_EQID_GET(x) (((x) >> 0) & 0xfffff) +#define FW_EQ_ETH_CMD_PHYSEQID(x) ((x) << 0) + +#define FW_EQ_ETH_CMD_FETCHSZM(x) ((x) << 26) +#define FW_EQ_ETH_CMD_STATUSPGNS(x) ((x) << 25) +#define FW_EQ_ETH_CMD_STATUSPGRO(x) ((x) << 24) +#define FW_EQ_ETH_CMD_FETCHNS(x) ((x) << 23) +#define FW_EQ_ETH_CMD_FETCHRO(x) ((x) << 22) +#define FW_EQ_ETH_CMD_HOSTFCMODE(x) ((x) << 20) +#define FW_EQ_ETH_CMD_CPRIO(x) ((x) << 19) +#define FW_EQ_ETH_CMD_ONCHIP(x) ((x) << 18) +#define FW_EQ_ETH_CMD_PCIECHN(x) ((x) << 16) +#define FW_EQ_ETH_CMD_IQID(x) ((x) << 0) + +#define FW_EQ_ETH_CMD_DCAEN(x) ((x) << 31) +#define FW_EQ_ETH_CMD_DCACPU(x) ((x) << 26) +#define FW_EQ_ETH_CMD_FBMIN(x) ((x) << 23) +#define FW_EQ_ETH_CMD_FBMAX(x) ((x) << 20) +#define FW_EQ_ETH_CMD_CIDXFTHRESHO(x) ((x) << 19) +#define FW_EQ_ETH_CMD_CIDXFTHRESH(x) ((x) << 16) +#define FW_EQ_ETH_CMD_EQSIZE(x) ((x) << 0) + +#define FW_EQ_ETH_CMD_VIID(x) ((x) << 16) + +struct fw_eq_ctrl_cmd { +	__be32 op_to_vfn; +	__be32 alloc_to_len16; +	__be32 cmpliqid_eqid; +	__be32 physeqid_pkd; +	__be32 fetchszm_to_iqid; +	__be32 dcaen_to_eqsize; +	__be64 eqaddr; +}; + +#define FW_EQ_CTRL_CMD_PFN(x) ((x) << 8) +#define FW_EQ_CTRL_CMD_VFN(x) ((x) << 0) + +#define FW_EQ_CTRL_CMD_ALLOC (1U << 31) +#define FW_EQ_CTRL_CMD_FREE (1U << 30) +#define FW_EQ_CTRL_CMD_MODIFY (1U << 29) +#define FW_EQ_CTRL_CMD_EQSTART (1U << 28) +#define FW_EQ_CTRL_CMD_EQSTOP (1U << 27) + +#define FW_EQ_CTRL_CMD_CMPLIQID(x) ((x) << 20) +#define FW_EQ_CTRL_CMD_EQID(x) ((x) << 0) +#define FW_EQ_CTRL_CMD_EQID_GET(x) (((x) >> 0) & 0xfffff) +#define FW_EQ_CTRL_CMD_PHYSEQID_GET(x) (((x) >> 0) & 0xfffff) + +#define FW_EQ_CTRL_CMD_FETCHSZM (1U << 26) +#define FW_EQ_CTRL_CMD_STATUSPGNS (1U << 25) +#define FW_EQ_CTRL_CMD_STATUSPGRO (1U << 24) +#define FW_EQ_CTRL_CMD_FETCHNS (1U << 23) +#define FW_EQ_CTRL_CMD_FETCHRO (1U << 22) +#define FW_EQ_CTRL_CMD_HOSTFCMODE(x) ((x) << 20) +#define FW_EQ_CTRL_CMD_CPRIO(x) ((x) << 19) +#define FW_EQ_CTRL_CMD_ONCHIP(x) ((x) << 18) +#define FW_EQ_CTRL_CMD_PCIECHN(x) ((x) << 16) +#define FW_EQ_CTRL_CMD_IQID(x) ((x) << 0) + +#define FW_EQ_CTRL_CMD_DCAEN(x) ((x) << 31) +#define FW_EQ_CTRL_CMD_DCACPU(x) ((x) << 26) +#define FW_EQ_CTRL_CMD_FBMIN(x) ((x) << 23) +#define FW_EQ_CTRL_CMD_FBMAX(x) ((x) << 20) +#define FW_EQ_CTRL_CMD_CIDXFTHRESHO(x) ((x) << 19) +#define FW_EQ_CTRL_CMD_CIDXFTHRESH(x) ((x) << 16) +#define FW_EQ_CTRL_CMD_EQSIZE(x) ((x) << 0) + +struct fw_eq_ofld_cmd { +	__be32 op_to_vfn; +	__be32 alloc_to_len16; +	__be32 eqid_pkd; +	__be32 physeqid_pkd; +	__be32 fetchszm_to_iqid; +	__be32 dcaen_to_eqsize; +	__be64 eqaddr; +}; + +#define FW_EQ_OFLD_CMD_PFN(x) ((x) << 8) +#define FW_EQ_OFLD_CMD_VFN(x) ((x) << 0) + +#define FW_EQ_OFLD_CMD_ALLOC (1U << 31) +#define FW_EQ_OFLD_CMD_FREE (1U << 30) +#define FW_EQ_OFLD_CMD_MODIFY (1U << 29) +#define FW_EQ_OFLD_CMD_EQSTART (1U << 28) +#define FW_EQ_OFLD_CMD_EQSTOP (1U << 27) + +#define FW_EQ_OFLD_CMD_EQID(x) ((x) << 0) +#define FW_EQ_OFLD_CMD_EQID_GET(x) (((x) >> 0) & 0xfffff) +#define FW_EQ_OFLD_CMD_PHYSEQID_GET(x) (((x) >> 0) & 0xfffff) + +#define FW_EQ_OFLD_CMD_FETCHSZM(x) ((x) << 26) +#define FW_EQ_OFLD_CMD_STATUSPGNS(x) ((x) << 25) +#define FW_EQ_OFLD_CMD_STATUSPGRO(x) ((x) << 24) +#define FW_EQ_OFLD_CMD_FETCHNS(x) ((x) << 23) +#define FW_EQ_OFLD_CMD_FETCHRO(x) ((x) << 22) +#define FW_EQ_OFLD_CMD_HOSTFCMODE(x) ((x) << 20) +#define FW_EQ_OFLD_CMD_CPRIO(x) ((x) << 19) +#define FW_EQ_OFLD_CMD_ONCHIP(x) ((x) << 18) +#define FW_EQ_OFLD_CMD_PCIECHN(x) ((x) << 16) +#define FW_EQ_OFLD_CMD_IQID(x) ((x) << 0) + +#define FW_EQ_OFLD_CMD_DCAEN(x) ((x) << 31) +#define FW_EQ_OFLD_CMD_DCACPU(x) ((x) << 26) +#define FW_EQ_OFLD_CMD_FBMIN(x) ((x) << 23) +#define FW_EQ_OFLD_CMD_FBMAX(x) ((x) << 20) +#define FW_EQ_OFLD_CMD_CIDXFTHRESHO(x) ((x) << 19) +#define FW_EQ_OFLD_CMD_CIDXFTHRESH(x) ((x) << 16) +#define FW_EQ_OFLD_CMD_EQSIZE(x) ((x) << 0) + +/* + * Macros for VIID parsing: + * VIID - [10:8] PFN, [7] VI Valid, [6:0] VI number + */ +#define FW_VIID_PFN_GET(x) (((x) >> 8) & 0x7) +#define FW_VIID_VIVLD_GET(x) (((x) >> 7) & 0x1) +#define FW_VIID_VIN_GET(x) (((x) >> 0) & 0x7F) + +struct fw_vi_cmd { +	__be32 op_to_vfn; +	__be32 alloc_to_len16; +	__be16 viid_pkd; +	u8 mac[6]; +	u8 portid_pkd; +	u8 nmac; +	u8 nmac0[6]; +	__be16 rsssize_pkd; +	u8 nmac1[6]; +	__be16 r7; +	u8 nmac2[6]; +	__be16 r8; +	u8 nmac3[6]; +	__be64 r9; +	__be64 r10; +}; + +#define FW_VI_CMD_PFN(x) ((x) << 8) +#define FW_VI_CMD_VFN(x) ((x) << 0) +#define FW_VI_CMD_ALLOC (1U << 31) +#define FW_VI_CMD_FREE (1U << 30) +#define FW_VI_CMD_VIID(x) ((x) << 0) +#define FW_VI_CMD_PORTID(x) ((x) << 4) +#define FW_VI_CMD_RSSSIZE_GET(x) (((x) >> 0) & 0x7ff) + +/* Special VI_MAC command index ids */ +#define FW_VI_MAC_ADD_MAC		0x3FF +#define FW_VI_MAC_ADD_PERSIST_MAC	0x3FE +#define FW_VI_MAC_MAC_BASED_FREE	0x3FD + +enum fw_vi_mac_smac { +	FW_VI_MAC_MPS_TCAM_ENTRY, +	FW_VI_MAC_MPS_TCAM_ONLY, +	FW_VI_MAC_SMT_ONLY, +	FW_VI_MAC_SMT_AND_MPSTCAM +}; + +enum fw_vi_mac_result { +	FW_VI_MAC_R_SUCCESS, +	FW_VI_MAC_R_F_NONEXISTENT_NOMEM, +	FW_VI_MAC_R_SMAC_FAIL, +	FW_VI_MAC_R_F_ACL_CHECK +}; + +struct fw_vi_mac_cmd { +	__be32 op_to_viid; +	__be32 freemacs_to_len16; +	union fw_vi_mac { +		struct fw_vi_mac_exact { +			__be16 valid_to_idx; +			u8 macaddr[6]; +		} exact[7]; +		struct fw_vi_mac_hash { +			__be64 hashvec; +		} hash; +	} u; +}; + +#define FW_VI_MAC_CMD_VIID(x) ((x) << 0) +#define FW_VI_MAC_CMD_FREEMACS(x) ((x) << 31) +#define FW_VI_MAC_CMD_HASHVECEN (1U << 23) +#define FW_VI_MAC_CMD_HASHUNIEN(x) ((x) << 22) +#define FW_VI_MAC_CMD_VALID (1U << 15) +#define FW_VI_MAC_CMD_PRIO(x) ((x) << 12) +#define FW_VI_MAC_CMD_SMAC_RESULT(x) ((x) << 10) +#define FW_VI_MAC_CMD_SMAC_RESULT_GET(x) (((x) >> 10) & 0x3) +#define FW_VI_MAC_CMD_IDX(x) ((x) << 0) +#define FW_VI_MAC_CMD_IDX_GET(x) (((x) >> 0) & 0x3ff) + +#define FW_RXMODE_MTU_NO_CHG	65535 + +struct fw_vi_rxmode_cmd { +	__be32 op_to_viid; +	__be32 retval_len16; +	__be32 mtu_to_broadcasten; +	__be32 r4_lo; +}; + +#define FW_VI_RXMODE_CMD_VIID(x) ((x) << 0) +#define FW_VI_RXMODE_CMD_MTU(x) ((x) << 16) +#define FW_VI_RXMODE_CMD_PROMISCEN_MASK 0x3 +#define FW_VI_RXMODE_CMD_PROMISCEN(x) ((x) << 14) +#define FW_VI_RXMODE_CMD_ALLMULTIEN_MASK 0x3 +#define FW_VI_RXMODE_CMD_ALLMULTIEN(x) ((x) << 12) +#define FW_VI_RXMODE_CMD_BROADCASTEN_MASK 0x3 +#define FW_VI_RXMODE_CMD_BROADCASTEN(x) ((x) << 10) + +struct fw_vi_enable_cmd { +	__be32 op_to_viid; +	__be32 ien_to_len16; +	__be16 blinkdur; +	__be16 r3; +	__be32 r4; +}; + +#define FW_VI_ENABLE_CMD_VIID(x) ((x) << 0) +#define FW_VI_ENABLE_CMD_IEN(x) ((x) << 31) +#define FW_VI_ENABLE_CMD_EEN(x) ((x) << 30) +#define FW_VI_ENABLE_CMD_LED (1U << 29) + +/* VI VF stats offset definitions */ +#define VI_VF_NUM_STATS	16 +enum fw_vi_stats_vf_index { +	FW_VI_VF_STAT_TX_BCAST_BYTES_IX, +	FW_VI_VF_STAT_TX_BCAST_FRAMES_IX, +	FW_VI_VF_STAT_TX_MCAST_BYTES_IX, +	FW_VI_VF_STAT_TX_MCAST_FRAMES_IX, +	FW_VI_VF_STAT_TX_UCAST_BYTES_IX, +	FW_VI_VF_STAT_TX_UCAST_FRAMES_IX, +	FW_VI_VF_STAT_TX_DROP_FRAMES_IX, +	FW_VI_VF_STAT_TX_OFLD_BYTES_IX, +	FW_VI_VF_STAT_TX_OFLD_FRAMES_IX, +	FW_VI_VF_STAT_RX_BCAST_BYTES_IX, +	FW_VI_VF_STAT_RX_BCAST_FRAMES_IX, +	FW_VI_VF_STAT_RX_MCAST_BYTES_IX, +	FW_VI_VF_STAT_RX_MCAST_FRAMES_IX, +	FW_VI_VF_STAT_RX_UCAST_BYTES_IX, +	FW_VI_VF_STAT_RX_UCAST_FRAMES_IX, +	FW_VI_VF_STAT_RX_ERR_FRAMES_IX +}; + +/* VI PF stats offset definitions */ +#define VI_PF_NUM_STATS	17 +enum fw_vi_stats_pf_index { +	FW_VI_PF_STAT_TX_BCAST_BYTES_IX, +	FW_VI_PF_STAT_TX_BCAST_FRAMES_IX, +	FW_VI_PF_STAT_TX_MCAST_BYTES_IX, +	FW_VI_PF_STAT_TX_MCAST_FRAMES_IX, +	FW_VI_PF_STAT_TX_UCAST_BYTES_IX, +	FW_VI_PF_STAT_TX_UCAST_FRAMES_IX, +	FW_VI_PF_STAT_TX_OFLD_BYTES_IX, +	FW_VI_PF_STAT_TX_OFLD_FRAMES_IX, +	FW_VI_PF_STAT_RX_BYTES_IX, +	FW_VI_PF_STAT_RX_FRAMES_IX, +	FW_VI_PF_STAT_RX_BCAST_BYTES_IX, +	FW_VI_PF_STAT_RX_BCAST_FRAMES_IX, +	FW_VI_PF_STAT_RX_MCAST_BYTES_IX, +	FW_VI_PF_STAT_RX_MCAST_FRAMES_IX, +	FW_VI_PF_STAT_RX_UCAST_BYTES_IX, +	FW_VI_PF_STAT_RX_UCAST_FRAMES_IX, +	FW_VI_PF_STAT_RX_ERR_FRAMES_IX +}; + +struct fw_vi_stats_cmd { +	__be32 op_to_viid; +	__be32 retval_len16; +	union fw_vi_stats { +		struct fw_vi_stats_ctl { +			__be16 nstats_ix; +			__be16 r6; +			__be32 r7; +			__be64 stat0; +			__be64 stat1; +			__be64 stat2; +			__be64 stat3; +			__be64 stat4; +			__be64 stat5; +		} ctl; +		struct fw_vi_stats_pf { +			__be64 tx_bcast_bytes; +			__be64 tx_bcast_frames; +			__be64 tx_mcast_bytes; +			__be64 tx_mcast_frames; +			__be64 tx_ucast_bytes; +			__be64 tx_ucast_frames; +			__be64 tx_offload_bytes; +			__be64 tx_offload_frames; +			__be64 rx_pf_bytes; +			__be64 rx_pf_frames; +			__be64 rx_bcast_bytes; +			__be64 rx_bcast_frames; +			__be64 rx_mcast_bytes; +			__be64 rx_mcast_frames; +			__be64 rx_ucast_bytes; +			__be64 rx_ucast_frames; +			__be64 rx_err_frames; +		} pf; +		struct fw_vi_stats_vf { +			__be64 tx_bcast_bytes; +			__be64 tx_bcast_frames; +			__be64 tx_mcast_bytes; +			__be64 tx_mcast_frames; +			__be64 tx_ucast_bytes; +			__be64 tx_ucast_frames; +			__be64 tx_drop_frames; +			__be64 tx_offload_bytes; +			__be64 tx_offload_frames; +			__be64 rx_bcast_bytes; +			__be64 rx_bcast_frames; +			__be64 rx_mcast_bytes; +			__be64 rx_mcast_frames; +			__be64 rx_ucast_bytes; +			__be64 rx_ucast_frames; +			__be64 rx_err_frames; +		} vf; +	} u; +}; + +#define FW_VI_STATS_CMD_VIID(x) ((x) << 0) +#define FW_VI_STATS_CMD_NSTATS(x) ((x) << 12) +#define FW_VI_STATS_CMD_IX(x) ((x) << 0) + +struct fw_acl_mac_cmd { +	__be32 op_to_vfn; +	__be32 en_to_len16; +	u8 nmac; +	u8 r3[7]; +	__be16 r4; +	u8 macaddr0[6]; +	__be16 r5; +	u8 macaddr1[6]; +	__be16 r6; +	u8 macaddr2[6]; +	__be16 r7; +	u8 macaddr3[6]; +}; + +#define FW_ACL_MAC_CMD_PFN(x) ((x) << 8) +#define FW_ACL_MAC_CMD_VFN(x) ((x) << 0) +#define FW_ACL_MAC_CMD_EN(x) ((x) << 31) + +struct fw_acl_vlan_cmd { +	__be32 op_to_vfn; +	__be32 en_to_len16; +	u8 nvlan; +	u8 dropnovlan_fm; +	u8 r3_lo[6]; +	__be16 vlanid[16]; +}; + +#define FW_ACL_VLAN_CMD_PFN(x) ((x) << 8) +#define FW_ACL_VLAN_CMD_VFN(x) ((x) << 0) +#define FW_ACL_VLAN_CMD_EN(x) ((x) << 31) +#define FW_ACL_VLAN_CMD_DROPNOVLAN(x) ((x) << 7) +#define FW_ACL_VLAN_CMD_FM(x) ((x) << 6) + +enum fw_port_cap { +	FW_PORT_CAP_SPEED_100M		= 0x0001, +	FW_PORT_CAP_SPEED_1G		= 0x0002, +	FW_PORT_CAP_SPEED_2_5G		= 0x0004, +	FW_PORT_CAP_SPEED_10G		= 0x0008, +	FW_PORT_CAP_SPEED_40G		= 0x0010, +	FW_PORT_CAP_SPEED_100G		= 0x0020, +	FW_PORT_CAP_FC_RX		= 0x0040, +	FW_PORT_CAP_FC_TX		= 0x0080, +	FW_PORT_CAP_ANEG		= 0x0100, +	FW_PORT_CAP_MDI_0		= 0x0200, +	FW_PORT_CAP_MDI_1		= 0x0400, +	FW_PORT_CAP_BEAN		= 0x0800, +	FW_PORT_CAP_PMA_LPBK		= 0x1000, +	FW_PORT_CAP_PCS_LPBK		= 0x2000, +	FW_PORT_CAP_PHYXS_LPBK		= 0x4000, +	FW_PORT_CAP_FAR_END_LPBK	= 0x8000, +}; + +enum fw_port_mdi { +	FW_PORT_MDI_UNCHANGED, +	FW_PORT_MDI_AUTO, +	FW_PORT_MDI_F_STRAIGHT, +	FW_PORT_MDI_F_CROSSOVER +}; + +#define FW_PORT_MDI(x) ((x) << 9) + +enum fw_port_action { +	FW_PORT_ACTION_L1_CFG		= 0x0001, +	FW_PORT_ACTION_L2_CFG		= 0x0002, +	FW_PORT_ACTION_GET_PORT_INFO	= 0x0003, +	FW_PORT_ACTION_L2_PPP_CFG	= 0x0004, +	FW_PORT_ACTION_L2_DCB_CFG	= 0x0005, +	FW_PORT_ACTION_LOW_PWR_TO_NORMAL = 0x0010, +	FW_PORT_ACTION_L1_LOW_PWR_EN	= 0x0011, +	FW_PORT_ACTION_L2_WOL_MODE_EN	= 0x0012, +	FW_PORT_ACTION_LPBK_TO_NORMAL	= 0x0020, +	FW_PORT_ACTION_L1_LPBK		= 0x0021, +	FW_PORT_ACTION_L1_PMA_LPBK	= 0x0022, +	FW_PORT_ACTION_L1_PCS_LPBK	= 0x0023, +	FW_PORT_ACTION_L1_PHYXS_CSIDE_LPBK = 0x0024, +	FW_PORT_ACTION_L1_PHYXS_ESIDE_LPBK = 0x0025, +	FW_PORT_ACTION_PHY_RESET	= 0x0040, +	FW_PORT_ACTION_PMA_RESET	= 0x0041, +	FW_PORT_ACTION_PCS_RESET	= 0x0042, +	FW_PORT_ACTION_PHYXS_RESET	= 0x0043, +	FW_PORT_ACTION_DTEXS_REEST	= 0x0044, +	FW_PORT_ACTION_AN_RESET		= 0x0045 +}; + +enum fw_port_l2cfg_ctlbf { +	FW_PORT_L2_CTLBF_OVLAN0	= 0x01, +	FW_PORT_L2_CTLBF_OVLAN1	= 0x02, +	FW_PORT_L2_CTLBF_OVLAN2	= 0x04, +	FW_PORT_L2_CTLBF_OVLAN3	= 0x08, +	FW_PORT_L2_CTLBF_IVLAN	= 0x10, +	FW_PORT_L2_CTLBF_TXIPG	= 0x20 +}; + +enum fw_port_dcb_cfg { +	FW_PORT_DCB_CFG_PG	= 0x01, +	FW_PORT_DCB_CFG_PFC	= 0x02, +	FW_PORT_DCB_CFG_APPL	= 0x04 +}; + +enum fw_port_dcb_cfg_rc { +	FW_PORT_DCB_CFG_SUCCESS	= 0x0, +	FW_PORT_DCB_CFG_ERROR	= 0x1 +}; + +struct fw_port_cmd { +	__be32 op_to_portid; +	__be32 action_to_len16; +	union fw_port { +		struct fw_port_l1cfg { +			__be32 rcap; +			__be32 r; +		} l1cfg; +		struct fw_port_l2cfg { +			__be16 ctlbf_to_ivlan0; +			__be16 ivlantype; +			__be32 txipg_pkd; +			__be16 ovlan0mask; +			__be16 ovlan0type; +			__be16 ovlan1mask; +			__be16 ovlan1type; +			__be16 ovlan2mask; +			__be16 ovlan2type; +			__be16 ovlan3mask; +			__be16 ovlan3type; +		} l2cfg; +		struct fw_port_info { +			__be32 lstatus_to_modtype; +			__be16 pcap; +			__be16 acap; +		} info; +		struct fw_port_ppp { +			__be32 pppen_to_ncsich; +			__be32 r11; +		} ppp; +		struct fw_port_dcb { +			__be16 cfg; +			u8 up_map; +			u8 sf_cfgrc; +			__be16 prot_ix; +			u8 pe7_to_pe0; +			u8 numTCPFCs; +			__be32 pgid0_to_pgid7; +			__be32 numTCs_oui; +			u8 pgpc[8]; +		} dcb; +	} u; +}; + +#define FW_PORT_CMD_READ (1U << 22) + +#define FW_PORT_CMD_PORTID(x) ((x) << 0) +#define FW_PORT_CMD_PORTID_GET(x) (((x) >> 0) & 0xf) + +#define FW_PORT_CMD_ACTION(x) ((x) << 16) + +#define FW_PORT_CMD_CTLBF(x) ((x) << 10) +#define FW_PORT_CMD_OVLAN3(x) ((x) << 7) +#define FW_PORT_CMD_OVLAN2(x) ((x) << 6) +#define FW_PORT_CMD_OVLAN1(x) ((x) << 5) +#define FW_PORT_CMD_OVLAN0(x) ((x) << 4) +#define FW_PORT_CMD_IVLAN0(x) ((x) << 3) + +#define FW_PORT_CMD_TXIPG(x) ((x) << 19) + +#define FW_PORT_CMD_LSTATUS (1U << 31) +#define FW_PORT_CMD_LSPEED(x) ((x) << 24) +#define FW_PORT_CMD_LSPEED_GET(x) (((x) >> 24) & 0x3f) +#define FW_PORT_CMD_TXPAUSE (1U << 23) +#define FW_PORT_CMD_RXPAUSE (1U << 22) +#define FW_PORT_CMD_MDIOCAP (1U << 21) +#define FW_PORT_CMD_MDIOADDR_GET(x) (((x) >> 16) & 0x1f) +#define FW_PORT_CMD_LPTXPAUSE (1U << 15) +#define FW_PORT_CMD_LPRXPAUSE (1U << 14) +#define FW_PORT_CMD_PTYPE_MASK 0x1f +#define FW_PORT_CMD_PTYPE_GET(x) (((x) >> 8) & FW_PORT_CMD_PTYPE_MASK) +#define FW_PORT_CMD_MODTYPE_MASK 0x1f +#define FW_PORT_CMD_MODTYPE_GET(x) (((x) >> 0) & FW_PORT_CMD_MODTYPE_MASK) + +#define FW_PORT_CMD_PPPEN(x) ((x) << 31) +#define FW_PORT_CMD_TPSRC(x) ((x) << 28) +#define FW_PORT_CMD_NCSISRC(x) ((x) << 24) + +#define FW_PORT_CMD_CH0(x) ((x) << 20) +#define FW_PORT_CMD_CH1(x) ((x) << 16) +#define FW_PORT_CMD_CH2(x) ((x) << 12) +#define FW_PORT_CMD_CH3(x) ((x) << 8) +#define FW_PORT_CMD_NCSICH(x) ((x) << 4) + +enum fw_port_type { +	FW_PORT_TYPE_FIBER, +	FW_PORT_TYPE_KX4, +	FW_PORT_TYPE_BT_SGMII, +	FW_PORT_TYPE_KX, +	FW_PORT_TYPE_BT_XAUI, +	FW_PORT_TYPE_KR, +	FW_PORT_TYPE_CX4, +	FW_PORT_TYPE_TWINAX, + +	FW_PORT_TYPE_NONE = FW_PORT_CMD_PTYPE_MASK +}; + +enum fw_port_module_type { +	FW_PORT_MOD_TYPE_NA, +	FW_PORT_MOD_TYPE_LR, +	FW_PORT_MOD_TYPE_SR, +	FW_PORT_MOD_TYPE_ER, + +	FW_PORT_MOD_TYPE_NONE = FW_PORT_CMD_MODTYPE_MASK +}; + +/* port stats */ +#define FW_NUM_PORT_STATS 50 +#define FW_NUM_PORT_TX_STATS 23 +#define FW_NUM_PORT_RX_STATS 27 + +enum fw_port_stats_tx_index { +	FW_STAT_TX_PORT_BYTES_IX, +	FW_STAT_TX_PORT_FRAMES_IX, +	FW_STAT_TX_PORT_BCAST_IX, +	FW_STAT_TX_PORT_MCAST_IX, +	FW_STAT_TX_PORT_UCAST_IX, +	FW_STAT_TX_PORT_ERROR_IX, +	FW_STAT_TX_PORT_64B_IX, +	FW_STAT_TX_PORT_65B_127B_IX, +	FW_STAT_TX_PORT_128B_255B_IX, +	FW_STAT_TX_PORT_256B_511B_IX, +	FW_STAT_TX_PORT_512B_1023B_IX, +	FW_STAT_TX_PORT_1024B_1518B_IX, +	FW_STAT_TX_PORT_1519B_MAX_IX, +	FW_STAT_TX_PORT_DROP_IX, +	FW_STAT_TX_PORT_PAUSE_IX, +	FW_STAT_TX_PORT_PPP0_IX, +	FW_STAT_TX_PORT_PPP1_IX, +	FW_STAT_TX_PORT_PPP2_IX, +	FW_STAT_TX_PORT_PPP3_IX, +	FW_STAT_TX_PORT_PPP4_IX, +	FW_STAT_TX_PORT_PPP5_IX, +	FW_STAT_TX_PORT_PPP6_IX, +	FW_STAT_TX_PORT_PPP7_IX +}; + +enum fw_port_stat_rx_index { +	FW_STAT_RX_PORT_BYTES_IX, +	FW_STAT_RX_PORT_FRAMES_IX, +	FW_STAT_RX_PORT_BCAST_IX, +	FW_STAT_RX_PORT_MCAST_IX, +	FW_STAT_RX_PORT_UCAST_IX, +	FW_STAT_RX_PORT_MTU_ERROR_IX, +	FW_STAT_RX_PORT_MTU_CRC_ERROR_IX, +	FW_STAT_RX_PORT_CRC_ERROR_IX, +	FW_STAT_RX_PORT_LEN_ERROR_IX, +	FW_STAT_RX_PORT_SYM_ERROR_IX, +	FW_STAT_RX_PORT_64B_IX, +	FW_STAT_RX_PORT_65B_127B_IX, +	FW_STAT_RX_PORT_128B_255B_IX, +	FW_STAT_RX_PORT_256B_511B_IX, +	FW_STAT_RX_PORT_512B_1023B_IX, +	FW_STAT_RX_PORT_1024B_1518B_IX, +	FW_STAT_RX_PORT_1519B_MAX_IX, +	FW_STAT_RX_PORT_PAUSE_IX, +	FW_STAT_RX_PORT_PPP0_IX, +	FW_STAT_RX_PORT_PPP1_IX, +	FW_STAT_RX_PORT_PPP2_IX, +	FW_STAT_RX_PORT_PPP3_IX, +	FW_STAT_RX_PORT_PPP4_IX, +	FW_STAT_RX_PORT_PPP5_IX, +	FW_STAT_RX_PORT_PPP6_IX, +	FW_STAT_RX_PORT_PPP7_IX, +	FW_STAT_RX_PORT_LESS_64B_IX +}; + +struct fw_port_stats_cmd { +	__be32 op_to_portid; +	__be32 retval_len16; +	union fw_port_stats { +		struct fw_port_stats_ctl { +			u8 nstats_bg_bm; +			u8 tx_ix; +			__be16 r6; +			__be32 r7; +			__be64 stat0; +			__be64 stat1; +			__be64 stat2; +			__be64 stat3; +			__be64 stat4; +			__be64 stat5; +		} ctl; +		struct fw_port_stats_all { +			__be64 tx_bytes; +			__be64 tx_frames; +			__be64 tx_bcast; +			__be64 tx_mcast; +			__be64 tx_ucast; +			__be64 tx_error; +			__be64 tx_64b; +			__be64 tx_65b_127b; +			__be64 tx_128b_255b; +			__be64 tx_256b_511b; +			__be64 tx_512b_1023b; +			__be64 tx_1024b_1518b; +			__be64 tx_1519b_max; +			__be64 tx_drop; +			__be64 tx_pause; +			__be64 tx_ppp0; +			__be64 tx_ppp1; +			__be64 tx_ppp2; +			__be64 tx_ppp3; +			__be64 tx_ppp4; +			__be64 tx_ppp5; +			__be64 tx_ppp6; +			__be64 tx_ppp7; +			__be64 rx_bytes; +			__be64 rx_frames; +			__be64 rx_bcast; +			__be64 rx_mcast; +			__be64 rx_ucast; +			__be64 rx_mtu_error; +			__be64 rx_mtu_crc_error; +			__be64 rx_crc_error; +			__be64 rx_len_error; +			__be64 rx_sym_error; +			__be64 rx_64b; +			__be64 rx_65b_127b; +			__be64 rx_128b_255b; +			__be64 rx_256b_511b; +			__be64 rx_512b_1023b; +			__be64 rx_1024b_1518b; +			__be64 rx_1519b_max; +			__be64 rx_pause; +			__be64 rx_ppp0; +			__be64 rx_ppp1; +			__be64 rx_ppp2; +			__be64 rx_ppp3; +			__be64 rx_ppp4; +			__be64 rx_ppp5; +			__be64 rx_ppp6; +			__be64 rx_ppp7; +			__be64 rx_less_64b; +			__be64 rx_bg_drop; +			__be64 rx_bg_trunc; +		} all; +	} u; +}; + +#define FW_PORT_STATS_CMD_NSTATS(x) ((x) << 4) +#define FW_PORT_STATS_CMD_BG_BM(x) ((x) << 0) +#define FW_PORT_STATS_CMD_TX(x) ((x) << 7) +#define FW_PORT_STATS_CMD_IX(x) ((x) << 0) + +/* port loopback stats */ +#define FW_NUM_LB_STATS 16 +enum fw_port_lb_stats_index { +	FW_STAT_LB_PORT_BYTES_IX, +	FW_STAT_LB_PORT_FRAMES_IX, +	FW_STAT_LB_PORT_BCAST_IX, +	FW_STAT_LB_PORT_MCAST_IX, +	FW_STAT_LB_PORT_UCAST_IX, +	FW_STAT_LB_PORT_ERROR_IX, +	FW_STAT_LB_PORT_64B_IX, +	FW_STAT_LB_PORT_65B_127B_IX, +	FW_STAT_LB_PORT_128B_255B_IX, +	FW_STAT_LB_PORT_256B_511B_IX, +	FW_STAT_LB_PORT_512B_1023B_IX, +	FW_STAT_LB_PORT_1024B_1518B_IX, +	FW_STAT_LB_PORT_1519B_MAX_IX, +	FW_STAT_LB_PORT_DROP_FRAMES_IX +}; + +struct fw_port_lb_stats_cmd { +	__be32 op_to_lbport; +	__be32 retval_len16; +	union fw_port_lb_stats { +		struct fw_port_lb_stats_ctl { +			u8 nstats_bg_bm; +			u8 ix_pkd; +			__be16 r6; +			__be32 r7; +			__be64 stat0; +			__be64 stat1; +			__be64 stat2; +			__be64 stat3; +			__be64 stat4; +			__be64 stat5; +		} ctl; +		struct fw_port_lb_stats_all { +			__be64 tx_bytes; +			__be64 tx_frames; +			__be64 tx_bcast; +			__be64 tx_mcast; +			__be64 tx_ucast; +			__be64 tx_error; +			__be64 tx_64b; +			__be64 tx_65b_127b; +			__be64 tx_128b_255b; +			__be64 tx_256b_511b; +			__be64 tx_512b_1023b; +			__be64 tx_1024b_1518b; +			__be64 tx_1519b_max; +			__be64 rx_lb_drop; +			__be64 rx_lb_trunc; +		} all; +	} u; +}; + +#define FW_PORT_LB_STATS_CMD_LBPORT(x) ((x) << 0) +#define FW_PORT_LB_STATS_CMD_NSTATS(x) ((x) << 4) +#define FW_PORT_LB_STATS_CMD_BG_BM(x) ((x) << 0) +#define FW_PORT_LB_STATS_CMD_IX(x) ((x) << 0) + +struct fw_rss_ind_tbl_cmd { +	__be32 op_to_viid; +#define FW_RSS_IND_TBL_CMD_VIID(x) ((x) << 0) +	__be32 retval_len16; +	__be16 niqid; +	__be16 startidx; +	__be32 r3; +	__be32 iq0_to_iq2; +#define FW_RSS_IND_TBL_CMD_IQ0(x) ((x) << 20) +#define FW_RSS_IND_TBL_CMD_IQ1(x) ((x) << 10) +#define FW_RSS_IND_TBL_CMD_IQ2(x) ((x) << 0) +	__be32 iq3_to_iq5; +	__be32 iq6_to_iq8; +	__be32 iq9_to_iq11; +	__be32 iq12_to_iq14; +	__be32 iq15_to_iq17; +	__be32 iq18_to_iq20; +	__be32 iq21_to_iq23; +	__be32 iq24_to_iq26; +	__be32 iq27_to_iq29; +	__be32 iq30_iq31; +	__be32 r15_lo; +}; + +struct fw_rss_glb_config_cmd { +	__be32 op_to_write; +	__be32 retval_len16; +	union fw_rss_glb_config { +		struct fw_rss_glb_config_manual { +			__be32 mode_pkd; +			__be32 r3; +			__be64 r4; +			__be64 r5; +		} manual; +		struct fw_rss_glb_config_basicvirtual { +			__be32 mode_pkd; +			__be32 synmapen_to_hashtoeplitz; +#define FW_RSS_GLB_CONFIG_CMD_SYNMAPEN      (1U << 8) +#define FW_RSS_GLB_CONFIG_CMD_SYN4TUPENIPV6 (1U << 7) +#define FW_RSS_GLB_CONFIG_CMD_SYN2TUPENIPV6 (1U << 6) +#define FW_RSS_GLB_CONFIG_CMD_SYN4TUPENIPV4 (1U << 5) +#define FW_RSS_GLB_CONFIG_CMD_SYN2TUPENIPV4 (1U << 4) +#define FW_RSS_GLB_CONFIG_CMD_OFDMAPEN      (1U << 3) +#define FW_RSS_GLB_CONFIG_CMD_TNLMAPEN      (1U << 2) +#define FW_RSS_GLB_CONFIG_CMD_TNLALLLKP     (1U << 1) +#define FW_RSS_GLB_CONFIG_CMD_HASHTOEPLITZ  (1U << 0) +			__be64 r8; +			__be64 r9; +		} basicvirtual; +	} u; +}; + +#define FW_RSS_GLB_CONFIG_CMD_MODE(x)	((x) << 28) + +#define FW_RSS_GLB_CONFIG_CMD_MODE_MANUAL	0 +#define FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL	1 + +struct fw_rss_vi_config_cmd { +	__be32 op_to_viid; +#define FW_RSS_VI_CONFIG_CMD_VIID(x) ((x) << 0) +	__be32 retval_len16; +	union fw_rss_vi_config { +		struct fw_rss_vi_config_manual { +			__be64 r3; +			__be64 r4; +			__be64 r5; +		} manual; +		struct fw_rss_vi_config_basicvirtual { +			__be32 r6; +			__be32 defaultq_to_ip4udpen; +#define FW_RSS_VI_CONFIG_CMD_DEFAULTQ(x)  ((x) << 16) +#define FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN (1U << 4) +#define FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN  (1U << 3) +#define FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN (1U << 2) +#define FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN  (1U << 1) +#define FW_RSS_VI_CONFIG_CMD_IP4UDPEN     (1U << 0) +			__be64 r9; +			__be64 r10; +		} basicvirtual; +	} u; +}; + +enum fw_error_type { +	FW_ERROR_TYPE_EXCEPTION		= 0x0, +	FW_ERROR_TYPE_HWMODULE		= 0x1, +	FW_ERROR_TYPE_WR		= 0x2, +	FW_ERROR_TYPE_ACL		= 0x3, +}; + +struct fw_error_cmd { +	__be32 op_to_type; +	__be32 len16_pkd; +	union fw_error { +		struct fw_error_exception { +			__be32 info[6]; +		} exception; +		struct fw_error_hwmodule { +			__be32 regaddr; +			__be32 regval; +		} hwmodule; +		struct fw_error_wr { +			__be16 cidx; +			__be16 pfn_vfn; +			__be32 eqid; +			u8 wrhdr[16]; +		} wr; +		struct fw_error_acl { +			__be16 cidx; +			__be16 pfn_vfn; +			__be32 eqid; +			__be16 mv_pkd; +			u8 val[6]; +			__be64 r4; +		} acl; +	} u; +}; + +struct fw_debug_cmd { +	__be32 op_type; +#define FW_DEBUG_CMD_TYPE_GET(x) ((x) & 0xff) +	__be32 len16_pkd; +	union fw_debug { +		struct fw_debug_assert { +			__be32 fcid; +			__be32 line; +			__be32 x; +			__be32 y; +			u8 filename_0_7[8]; +			u8 filename_8_15[8]; +			__be64 r3; +		} assert; +		struct fw_debug_prt { +			__be16 dprtstridx; +			__be16 r3[3]; +			__be32 dprtstrparam0; +			__be32 dprtstrparam1; +			__be32 dprtstrparam2; +			__be32 dprtstrparam3; +		} prt; +	} u; +}; + +struct fw_hdr { +	u8 ver; +	u8 reserved1; +	__be16	len512;			/* bin length in units of 512-bytes */ +	__be32	fw_ver;			/* firmware version */ +	__be32	tp_microcode_ver; +	u8 intfver_nic; +	u8 intfver_vnic; +	u8 intfver_ofld; +	u8 intfver_ri; +	u8 intfver_iscsipdu; +	u8 intfver_iscsi; +	u8 intfver_fcoe; +	u8 reserved2; +	__be32  reserved3[27]; +}; + +#define FW_HDR_FW_VER_MAJOR_GET(x) (((x) >> 24) & 0xff) +#define FW_HDR_FW_VER_MINOR_GET(x) (((x) >> 16) & 0xff) +#define FW_HDR_FW_VER_MICRO_GET(x) (((x) >> 8) & 0xff) +#define FW_HDR_FW_VER_BUILD_GET(x) (((x) >> 0) & 0xff) +#endif /* _T4FW_INTERFACE_H_ */ diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index 8bd086aee56..2b8edd2efbf 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -29,10 +29,6 @@   *     PHY layer usage   */ -/** Pending Items in this driver: - * 1. Use Linux cache infrastcture for DMA'ed memory (dma_xxx functions) - */ -  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/sched.h> @@ -504,12 +500,6 @@ static unsigned long mdio_max_freq;  /* Cache macros - Packet buffers would be from skb pool which is cached */  #define EMAC_VIRT_NOCACHE(addr) (addr) -#define EMAC_CACHE_INVALIDATE(addr, size) \ -	dma_cache_maint((void *)addr, size, DMA_FROM_DEVICE) -#define EMAC_CACHE_WRITEBACK(addr, size) \ -	dma_cache_maint((void *)addr, size, DMA_TO_DEVICE) -#define EMAC_CACHE_WRITEBACK_INVALIDATE(addr, size) \ -	dma_cache_maint((void *)addr, size, DMA_BIDIRECTIONAL)  /* DM644x does not have BD's in cached memory - so no cache functions */  #define BD_CACHE_INVALIDATE(addr, size) @@ -1235,6 +1225,10 @@ static void emac_txch_teardown(struct emac_priv *priv, u32 ch)  	if (1 == txch->queue_active) {  		curr_bd = txch->active_queue_head;  		while (curr_bd != NULL) { +			dma_unmap_single(emac_dev, curr_bd->buff_ptr, +				curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE, +				DMA_TO_DEVICE); +  			emac_net_tx_complete(priv, (void __force *)  					&curr_bd->buf_token, 1, ch);  			if (curr_bd != txch->active_queue_tail) @@ -1327,6 +1321,11 @@ static int emac_tx_bdproc(struct emac_priv *priv, u32 ch, u32 budget)  				txch->queue_active = 0; /* end of queue */  			}  		} + +		dma_unmap_single(emac_dev, curr_bd->buff_ptr, +				curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE, +				DMA_TO_DEVICE); +  		*tx_complete_ptr = (u32) curr_bd->buf_token;  		++tx_complete_ptr;  		++tx_complete_cnt; @@ -1387,8 +1386,8 @@ static int emac_send(struct emac_priv *priv, struct emac_netpktobj *pkt, u32 ch)  	txch->bd_pool_head = curr_bd->next;  	curr_bd->buf_token = buf_list->buf_token; -	/* FIXME buff_ptr = dma_map_single(... data_ptr ...) */ -	curr_bd->buff_ptr = virt_to_phys(buf_list->data_ptr); +	curr_bd->buff_ptr = dma_map_single(&priv->ndev->dev, buf_list->data_ptr, +			buf_list->length, DMA_TO_DEVICE);  	curr_bd->off_b_len = buf_list->length;  	curr_bd->h_next = 0;  	curr_bd->next = NULL; @@ -1468,7 +1467,6 @@ static int emac_dev_xmit(struct sk_buff *skb, struct net_device *ndev)  	tx_buf.length = skb->len;  	tx_buf.buf_token = (void *)skb;  	tx_buf.data_ptr = skb->data; -	EMAC_CACHE_WRITEBACK((unsigned long)skb->data, skb->len);  	ndev->trans_start = jiffies;  	ret_code = emac_send(priv, &tx_packet, EMAC_DEF_TX_CH);  	if (unlikely(ret_code != 0)) { @@ -1543,7 +1541,6 @@ static void *emac_net_alloc_rx_buf(struct emac_priv *priv, int buf_size,  	p_skb->dev = ndev;  	skb_reserve(p_skb, NET_IP_ALIGN);  	*data_token = (void *) p_skb; -	EMAC_CACHE_WRITEBACK_INVALIDATE((unsigned long)p_skb->data, buf_size);  	return p_skb->data;  } @@ -1612,8 +1609,8 @@ static int emac_init_rxch(struct emac_priv *priv, u32 ch, char *param)  		/* populate the hardware descriptor */  		curr_bd->h_next = emac_virt_to_phys(rxch->active_queue_head,  				priv); -		/* FIXME buff_ptr = dma_map_single(... data_ptr ...) */ -		curr_bd->buff_ptr = virt_to_phys(curr_bd->data_ptr); +		curr_bd->buff_ptr = dma_map_single(emac_dev, curr_bd->data_ptr, +				rxch->buf_size, DMA_FROM_DEVICE);  		curr_bd->off_b_len = rxch->buf_size;  		curr_bd->mode = EMAC_CPPI_OWNERSHIP_BIT; @@ -1697,6 +1694,12 @@ static void emac_cleanup_rxch(struct emac_priv *priv, u32 ch)  		curr_bd = rxch->active_queue_head;  		while (curr_bd) {  			if (curr_bd->buf_token) { +				dma_unmap_single(&priv->ndev->dev, +					curr_bd->buff_ptr, +					curr_bd->off_b_len +						& EMAC_RX_BD_BUF_SIZE, +					DMA_FROM_DEVICE); +  				dev_kfree_skb_any((struct sk_buff *)\  						  curr_bd->buf_token);  			} @@ -1871,8 +1874,8 @@ static void emac_addbd_to_rx_queue(struct emac_priv *priv, u32 ch,  	/* populate the hardware descriptor */  	curr_bd->h_next = 0; -	/* FIXME buff_ptr = dma_map_single(... buffer ...) */ -	curr_bd->buff_ptr = virt_to_phys(buffer); +	curr_bd->buff_ptr = dma_map_single(&priv->ndev->dev, buffer, +				rxch->buf_size, DMA_FROM_DEVICE);  	curr_bd->off_b_len = rxch->buf_size;  	curr_bd->mode = EMAC_CPPI_OWNERSHIP_BIT;  	curr_bd->next = NULL; @@ -1927,7 +1930,6 @@ static int emac_net_rx_cb(struct emac_priv *priv,  	p_skb = (struct sk_buff *)net_pkt_list->pkt_token;  	/* set length of packet */  	skb_put(p_skb, net_pkt_list->pkt_length); -	EMAC_CACHE_INVALIDATE((unsigned long)p_skb->data, p_skb->len);  	p_skb->protocol = eth_type_trans(p_skb, priv->ndev);  	netif_receive_skb(p_skb);  	priv->net_dev_stats.rx_bytes += net_pkt_list->pkt_length; @@ -1990,6 +1992,11 @@ static int emac_rx_bdproc(struct emac_priv *priv, u32 ch, u32 budget)  		rx_buf_obj->data_ptr = (char *)curr_bd->data_ptr;  		rx_buf_obj->length = curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE;  		rx_buf_obj->buf_token = curr_bd->buf_token; + +		dma_unmap_single(&priv->ndev->dev, curr_bd->buff_ptr, +				curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE, +				DMA_FROM_DEVICE); +  		curr_pkt->pkt_token = curr_pkt->buf_list->buf_token;  		curr_pkt->num_bufs = 1;  		curr_pkt->pkt_length = @@ -2820,31 +2827,37 @@ static int __devexit davinci_emac_remove(struct platform_device *pdev)  	return 0;  } -static -int davinci_emac_suspend(struct platform_device *pdev, pm_message_t state) +static int davinci_emac_suspend(struct device *dev)  { -	struct net_device *dev = platform_get_drvdata(pdev); +	struct platform_device *pdev = to_platform_device(dev); +	struct net_device *ndev = platform_get_drvdata(pdev); -	if (netif_running(dev)) -		emac_dev_stop(dev); +	if (netif_running(ndev)) +		emac_dev_stop(ndev);  	clk_disable(emac_clk);  	return 0;  } -static int davinci_emac_resume(struct platform_device *pdev) +static int davinci_emac_resume(struct device *dev)  { -	struct net_device *dev = platform_get_drvdata(pdev); +	struct platform_device *pdev = to_platform_device(dev); +	struct net_device *ndev = platform_get_drvdata(pdev);  	clk_enable(emac_clk); -	if (netif_running(dev)) -		emac_dev_open(dev); +	if (netif_running(ndev)) +		emac_dev_open(ndev);  	return 0;  } +static const struct dev_pm_ops davinci_emac_pm_ops = { +	.suspend	= davinci_emac_suspend, +	.resume		= davinci_emac_resume, +}; +  /**   * davinci_emac_driver: EMAC platform driver structure   */ @@ -2852,11 +2865,10 @@ static struct platform_driver davinci_emac_driver = {  	.driver = {  		.name	 = "davinci_emac",  		.owner	 = THIS_MODULE, +		.pm	 = &davinci_emac_pm_ops,  	},  	.probe = davinci_emac_probe,  	.remove = __devexit_p(davinci_emac_remove), -	.suspend = davinci_emac_suspend, -	.resume = davinci_emac_resume,  };  /** diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 1c67f1138ca..7f9960f718e 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -33,6 +33,7 @@  #include <linux/delay.h>  #include <linux/platform_device.h>  #include <linux/irq.h> +#include <linux/slab.h>  #include <asm/delay.h>  #include <asm/irq.h> diff --git a/drivers/net/e100.c b/drivers/net/e100.c index a26ccab057d..791080303db 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -166,6 +166,7 @@  #include <linux/ethtool.h>  #include <linux/string.h>  #include <linux/firmware.h> +#include <linux/rtnetlink.h>  #include <asm/unaligned.h> @@ -2265,8 +2266,13 @@ static void e100_tx_timeout_task(struct work_struct *work)  	DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n",  		ioread8(&nic->csr->scb.status)); -	e100_down(netdev_priv(netdev)); -	e100_up(netdev_priv(netdev)); + +	rtnl_lock(); +	if (netif_running(netdev)) { +		e100_down(netdev_priv(netdev)); +		e100_up(netdev_priv(netdev)); +	} +	rtnl_unlock();  }  static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode) @@ -2858,7 +2864,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,  	}  	nic->cbs_pool = pci_pool_create(netdev->name,  			   nic->pdev, -			   nic->params.cbs.count * sizeof(struct cb), +			   nic->params.cbs.max * sizeof(struct cb),  			   sizeof(u32),  			   0);  	DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, MAC addr %pM\n", diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 9902b33b716..2f29c213185 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -261,7 +261,6 @@ struct e1000_adapter {  	/* TX */  	struct e1000_tx_ring *tx_ring;      /* One per active queue */  	unsigned int restart_queue; -	unsigned long tx_queue_len;  	u32 txd_cmd;  	u32 tx_int_delay;  	u32 tx_abs_int_delay; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 8be6faee43e..b15ece26ed8 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -383,8 +383,6 @@ static void e1000_configure(struct e1000_adapter *adapter)  		adapter->alloc_rx_buf(adapter, ring,  		                      E1000_DESC_UNUSED(ring));  	} - -	adapter->tx_queue_len = netdev->tx_queue_len;  }  int e1000_up(struct e1000_adapter *adapter) @@ -503,7 +501,6 @@ void e1000_down(struct e1000_adapter *adapter)  	del_timer_sync(&adapter->watchdog_timer);  	del_timer_sync(&adapter->phy_info_timer); -	netdev->tx_queue_len = adapter->tx_queue_len;  	adapter->link_speed = 0;  	adapter->link_duplex = 0;  	netif_carrier_off(netdev); @@ -2316,19 +2313,15 @@ static void e1000_watchdog(unsigned long data)  			        E1000_CTRL_RFCE) ? "RX" : ((ctrl &  			        E1000_CTRL_TFCE) ? "TX" : "None" ))); -			/* tweak tx_queue_len according to speed/duplex -			 * and adjust the timeout factor */ -			netdev->tx_queue_len = adapter->tx_queue_len; +			/* adjust timeout factor according to speed/duplex */  			adapter->tx_timeout_factor = 1;  			switch (adapter->link_speed) {  			case SPEED_10:  				txb2b = false; -				netdev->tx_queue_len = 10;  				adapter->tx_timeout_factor = 16;  				break;  			case SPEED_100:  				txb2b = false; -				netdev->tx_queue_len = 100;  				/* maybe add some timeout factor ? */  				break;  			} diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index 712ccc66ba2..90155552ea0 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -336,7 +336,6 @@ static s32 e1000_get_variants_82571(struct e1000_adapter *adapter)  	struct e1000_hw *hw = &adapter->hw;  	static int global_quad_port_a; /* global port a indication */  	struct pci_dev *pdev = adapter->pdev; -	u16 eeprom_data = 0;  	int is_port_b = er32(STATUS) & E1000_STATUS_FUNC_1;  	s32 rc; @@ -387,16 +386,15 @@ static s32 e1000_get_variants_82571(struct e1000_adapter *adapter)  		if (pdev->device == E1000_DEV_ID_82571EB_SERDES_QUAD)  			adapter->flags &= ~FLAG_HAS_WOL;  		break; -  	case e1000_82573: +	case e1000_82574: +	case e1000_82583: +		/* Disable ASPM L0s due to hardware errata */ +		e1000e_disable_aspm(adapter->pdev, PCIE_LINK_STATE_L0S); +  		if (pdev->device == E1000_DEV_ID_82573L) { -			if (e1000_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1, -				       &eeprom_data) < 0) -				break; -			if (!(eeprom_data & NVM_WORD1A_ASPM_MASK)) { -				adapter->flags |= FLAG_HAS_JUMBO_FRAMES; -				adapter->max_hw_frame_size = DEFAULT_JUMBO; -			} +			adapter->flags |= FLAG_HAS_JUMBO_FRAMES; +			adapter->max_hw_frame_size = DEFAULT_JUMBO;  		}  		break;  	default: @@ -1792,6 +1790,7 @@ struct e1000_info e1000_82571_info = {  				  | FLAG_RESET_OVERWRITES_LAA /* errata */  				  | FLAG_TARC_SPEED_MODE_BIT /* errata */  				  | FLAG_APME_CHECK_PORT_B, +	.flags2			= FLAG2_DISABLE_ASPM_L1, /* errata 13 */  	.pba			= 38,  	.max_hw_frame_size	= DEFAULT_JUMBO,  	.get_variants		= e1000_get_variants_82571, @@ -1809,6 +1808,7 @@ struct e1000_info e1000_82572_info = {  				  | FLAG_RX_CSUM_ENABLED  				  | FLAG_HAS_CTRLEXT_ON_LOAD  				  | FLAG_TARC_SPEED_MODE_BIT, /* errata */ +	.flags2			= FLAG2_DISABLE_ASPM_L1, /* errata 13 */  	.pba			= 38,  	.max_hw_frame_size	= DEFAULT_JUMBO,  	.get_variants		= e1000_get_variants_82571, @@ -1820,13 +1820,11 @@ struct e1000_info e1000_82572_info = {  struct e1000_info e1000_82573_info = {  	.mac			= e1000_82573,  	.flags			= FLAG_HAS_HW_VLAN_FILTER -				  | FLAG_HAS_JUMBO_FRAMES  				  | FLAG_HAS_WOL  				  | FLAG_APME_IN_CTRL3  				  | FLAG_RX_CSUM_ENABLED  				  | FLAG_HAS_SMART_POWER_DOWN  				  | FLAG_HAS_AMT -				  | FLAG_HAS_ERT  				  | FLAG_HAS_SWSM_ON_LOAD,  	.pba			= 20,  	.max_hw_frame_size	= ETH_FRAME_LEN + ETH_FCS_LEN, diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index c2ec095d216..ee32b9b27a9 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -37,6 +37,7 @@  #include <linux/io.h>  #include <linux/netdevice.h>  #include <linux/pci.h> +#include <linux/pci-aspm.h>  #include "hw.h" @@ -279,7 +280,6 @@ struct e1000_adapter {  	struct napi_struct napi; -	unsigned long tx_queue_len;  	unsigned int restart_queue;  	u32 txd_cmd; @@ -375,7 +375,7 @@ struct e1000_adapter {  struct e1000_info {  	enum e1000_mac_type	mac;  	unsigned int		flags; -	unsigned int            flags2; +	unsigned int		flags2;  	u32			pba;  	u32			max_hw_frame_size;  	s32			(*get_variants)(struct e1000_adapter *); @@ -422,6 +422,7 @@ struct e1000_info {  #define FLAG2_CRC_STRIPPING               (1 << 0)  #define FLAG2_HAS_PHY_WAKEUP              (1 << 1)  #define FLAG2_IS_DISCARDING               (1 << 2) +#define FLAG2_DISABLE_ASPM_L1             (1 << 3)  #define E1000_RX_DESC_PS(R, i)	    \  	(&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) @@ -462,6 +463,7 @@ extern void e1000e_update_stats(struct e1000_adapter *adapter);  extern bool e1000e_has_link(struct e1000_adapter *adapter);  extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter);  extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter); +extern void e1000e_disable_aspm(struct pci_dev *pdev, u16 state);  extern unsigned int copybreak; diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index b33e3cbe9ab..983493f2330 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -31,6 +31,7 @@  #include <linux/netdevice.h>  #include <linux/ethtool.h>  #include <linux/pci.h> +#include <linux/slab.h>  #include <linux/delay.h>  #include "e1000.h" diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 88d54d3efce..dbf81788bb4 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -36,6 +36,7 @@  #include <linux/netdevice.h>  #include <linux/tcp.h>  #include <linux/ipv6.h> +#include <linux/slab.h>  #include <net/checksum.h>  #include <net/ip6_checksum.h>  #include <linux/mii.h> @@ -660,6 +661,8 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter)  				i = 0;  		} +		if (i == tx_ring->next_to_use) +			break;  		eop = tx_ring->buffer_info[i].next_to_watch;  		eop_desc = E1000_TX_DESC(*tx_ring, eop);  	} @@ -2289,8 +2292,6 @@ static void e1000_configure_tx(struct e1000_adapter *adapter)  	ew32(TCTL, tctl);  	e1000e_config_collision_dist(hw); - -	adapter->tx_queue_len = adapter->netdev->tx_queue_len;  }  /** @@ -2877,7 +2878,6 @@ void e1000e_down(struct e1000_adapter *adapter)  	del_timer_sync(&adapter->watchdog_timer);  	del_timer_sync(&adapter->phy_info_timer); -	netdev->tx_queue_len = adapter->tx_queue_len;  	netif_carrier_off(netdev);  	adapter->link_speed = 0;  	adapter->link_duplex = 0; @@ -3588,21 +3588,15 @@ static void e1000_watchdog_task(struct work_struct *work)  					       "link gets many collisions.\n");  			} -			/* -			 * tweak tx_queue_len according to speed/duplex -			 * and adjust the timeout factor -			 */ -			netdev->tx_queue_len = adapter->tx_queue_len; +			/* adjust timeout factor according to speed/duplex */  			adapter->tx_timeout_factor = 1;  			switch (adapter->link_speed) {  			case SPEED_10:  				txb2b = 0; -				netdev->tx_queue_len = 10;  				adapter->tx_timeout_factor = 16;  				break;  			case SPEED_100:  				txb2b = 0; -				netdev->tx_queue_len = 100;  				adapter->tx_timeout_factor = 10;  				break;  			} @@ -4289,6 +4283,14 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)  		return -EINVAL;  	} +	/* 82573 Errata 17 */ +	if (((adapter->hw.mac.type == e1000_82573) || +	     (adapter->hw.mac.type == e1000_82574)) && +	    (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN)) { +		adapter->flags2 |= FLAG2_DISABLE_ASPM_L1; +		e1000e_disable_aspm(adapter->pdev, PCIE_LINK_STATE_L1); +	} +  	while (test_and_set_bit(__E1000_RESETTING, &adapter->state))  		msleep(1);  	/* e1000e_down -> e1000e_reset dependent on max_frame_size & mtu */ @@ -4611,29 +4613,42 @@ static void e1000_complete_shutdown(struct pci_dev *pdev, bool sleep,  	}  } -static void e1000e_disable_l1aspm(struct pci_dev *pdev) +#ifdef CONFIG_PCIEASPM +static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state) +{ +	pci_disable_link_state(pdev, state); +} +#else +static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state)  {  	int pos; -	u16 val; +	u16 reg16;  	/* -	 * 82573 workaround - disable L1 ASPM on mobile chipsets -	 * -	 * L1 ASPM on various mobile (ich7) chipsets do not behave properly -	 * resulting in lost data or garbage information on the pci-e link -	 * level. This could result in (false) bad EEPROM checksum errors, -	 * long ping times (up to 2s) or even a system freeze/hang. -	 * -	 * Unfortunately this feature saves about 1W power consumption when -	 * active. +	 * Both device and parent should have the same ASPM setting. +	 * Disable ASPM in downstream component first and then upstream.  	 */ -	pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); -	pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, &val); -	if (val & 0x2) { -		dev_warn(&pdev->dev, "Disabling L1 ASPM\n"); -		val &= ~0x2; -		pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, val); -	} +	pos = pci_pcie_cap(pdev); +	pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); +	reg16 &= ~state; +	pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); + +	if (!pdev->bus->self) +		return; + +	pos = pci_pcie_cap(pdev->bus->self); +	pci_read_config_word(pdev->bus->self, pos + PCI_EXP_LNKCTL, ®16); +	reg16 &= ~state; +	pci_write_config_word(pdev->bus->self, pos + PCI_EXP_LNKCTL, reg16); +} +#endif +void e1000e_disable_aspm(struct pci_dev *pdev, u16 state) +{ +	dev_info(&pdev->dev, "Disabling ASPM %s %s\n", +		 (state & PCIE_LINK_STATE_L0S) ? "L0s" : "", +		 (state & PCIE_LINK_STATE_L1) ? "L1" : ""); + +	__e1000e_disable_aspm(pdev, state);  }  #ifdef CONFIG_PM @@ -4659,7 +4674,8 @@ static int e1000_resume(struct pci_dev *pdev)  	pci_set_power_state(pdev, PCI_D0);  	pci_restore_state(pdev);  	pci_save_state(pdev); -	e1000e_disable_l1aspm(pdev); +	if (adapter->flags2 & FLAG2_DISABLE_ASPM_L1) +		e1000e_disable_aspm(pdev, PCIE_LINK_STATE_L1);  	err = pci_enable_device_mem(pdev);  	if (err) { @@ -4801,7 +4817,8 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)  	int err;  	pci_ers_result_t result; -	e1000e_disable_l1aspm(pdev); +	if (adapter->flags2 & FLAG2_DISABLE_ASPM_L1) +		e1000e_disable_aspm(pdev, PCIE_LINK_STATE_L1);  	err = pci_enable_device_mem(pdev);  	if (err) {  		dev_err(&pdev->dev, @@ -4895,13 +4912,6 @@ static void e1000_eeprom_checks(struct e1000_adapter *adapter)  		dev_warn(&adapter->pdev->dev,  			 "Warning: detected DSPD enabled in EEPROM\n");  	} - -	ret_val = e1000_read_nvm(hw, NVM_INIT_3GIO_3, 1, &buf); -	if (!ret_val && (le16_to_cpu(buf) & (3 << 2))) { -		/* ASPM enable */ -		dev_warn(&adapter->pdev->dev, -			 "Warning: detected ASPM enabled in EEPROM\n"); -	}  }  static const struct net_device_ops e1000e_netdev_ops = { @@ -4950,7 +4960,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,  	u16 eeprom_data = 0;  	u16 eeprom_apme_mask = E1000_EEPROM_APME; -	e1000e_disable_l1aspm(pdev); +	if (ei->flags2 & FLAG2_DISABLE_ASPM_L1) +		e1000e_disable_aspm(pdev, PCIE_LINK_STATE_L1);  	err = pci_enable_device_mem(pdev);  	if (err) diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 1b05bdf62c3..27c7bdbfa00 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -137,7 +137,6 @@ static const char version[] =  #include <linux/interrupt.h>  #include <linux/ioport.h>  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/netdevice.h> diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 7013dc8a6cb..1a7322b80ea 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -111,7 +111,6 @@  #include <linux/netdevice.h>  #include <linux/etherdevice.h>  #include <linux/skbuff.h> -#include <linux/slab.h>  #include <linux/mca-legacy.h>  #include <linux/spinlock.h>  #include <linux/bitops.h> diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index b004eaba3d7..809ccc9ff09 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -32,6 +32,7 @@  #include <linux/udp.h>  #include <linux/if.h>  #include <linux/list.h> +#include <linux/slab.h>  #include <linux/if_ether.h>  #include <linux/notifier.h>  #include <linux/reboot.h> diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c index 18d405f78c0..a1b4c7e5636 100644 --- a/drivers/net/ehea/ehea_qmr.c +++ b/drivers/net/ehea/ehea_qmr.c @@ -27,6 +27,7 @@   */  #include <linux/mm.h> +#include <linux/slab.h>  #include "ehea.h"  #include "ehea_phyp.h"  #include "ehea_qmr.h" diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index 3ee32e58c7e..ff27f728fd9 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -18,7 +18,6 @@  #include <linux/types.h>  #include <linux/fcntl.h>  #include <linux/interrupt.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/init.h> diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c index 69b9b70c7da..cf22de71014 100644 --- a/drivers/net/enic/vnic_dev.c +++ b/drivers/net/enic/vnic_dev.c @@ -23,6 +23,7 @@  #include <linux/pci.h>  #include <linux/delay.h>  #include <linux/if_ether.h> +#include <linux/slab.h>  #include "vnic_resource.h"  #include "vnic_devcmd.h" diff --git a/drivers/net/enic/vnic_rq.c b/drivers/net/enic/vnic_rq.c index 75583978a5e..e186efaf9da 100644 --- a/drivers/net/enic/vnic_rq.c +++ b/drivers/net/enic/vnic_rq.c @@ -22,6 +22,7 @@  #include <linux/types.h>  #include <linux/pci.h>  #include <linux/delay.h> +#include <linux/slab.h>  #include "vnic_dev.h"  #include "vnic_rq.h" diff --git a/drivers/net/enic/vnic_wq.c b/drivers/net/enic/vnic_wq.c index d2e00e51b7b..d5f984357f5 100644 --- a/drivers/net/enic/vnic_wq.c +++ b/drivers/net/enic/vnic_wq.c @@ -22,6 +22,7 @@  #include <linux/types.h>  #include <linux/pci.h>  #include <linux/delay.h> +#include <linux/slab.h>  #include "vnic_dev.h"  #include "vnic_wq.h" diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 39c271b6be4..7a567201e82 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -73,7 +73,6 @@ static int rx_copybreak;  #include <linux/timer.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/pci.h>  #include <linux/delay.h> diff --git a/drivers/net/eql.c b/drivers/net/eql.c index f5b96cadeb2..b34a2ddeef4 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -115,6 +115,7 @@  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/init.h> +#include <linux/slab.h>  #include <linux/timer.h>  #include <linux/netdevice.h>  #include <net/net_namespace.h> diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index d3abeee3f11..d4e24f08b3b 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -152,7 +152,6 @@ static char *version =  #include <linux/interrupt.h>  #include <linux/ioport.h>  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/init.h> diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index 209742304e2..a8d92503226 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -18,6 +18,7 @@  #include <linux/phy.h>  #include <linux/platform_device.h>  #include <linux/sched.h> +#include <linux/slab.h>  #include <net/ethoc.h>  static int buffer_size = 0x8000; /* 32 KBytes */ diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index 9d5ad08a119..d11ae5197f0 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -74,7 +74,6 @@ static int full_duplex[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };  #include <linux/timer.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/pci.h>  #include <linux/netdevice.h> diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 9f98c1c4a34..9b4e8f797a7 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -1653,7 +1653,7 @@ fec_set_mac_address(struct net_device *dev, void *p)  		(dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24),  		fep->hwp + FEC_ADDR_LOW);  	writel((dev->dev_addr[5] << 16) | (dev->dev_addr[4] << 24), -		fep + FEC_ADDR_HIGH); +		fep->hwp + FEC_ADDR_HIGH);  	return 0;  } diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c index 0dbd7219bbd..4a43e56b739 100644 --- a/drivers/net/fec_mpc52xx.c +++ b/drivers/net/fec_mpc52xx.c @@ -19,6 +19,7 @@  #include <linux/kernel.h>  #include <linux/types.h>  #include <linux/spinlock.h> +#include <linux/slab.h>  #include <linux/errno.h>  #include <linux/init.h>  #include <linux/crc32.h> diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c index ee0f3c6d3f8..7658a082e39 100644 --- a/drivers/net/fec_mpc52xx_phy.c +++ b/drivers/net/fec_mpc52xx_phy.c @@ -14,6 +14,7 @@  #include <linux/netdevice.h>  #include <linux/phy.h>  #include <linux/of_platform.h> +#include <linux/slab.h>  #include <linux/of_mdio.h>  #include <asm/io.h>  #include <asm/mpc52xx.h> diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index ca05e566202..5c98f7c2242 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -59,6 +59,7 @@  #include <linux/init.h>  #include <linux/if_vlan.h>  #include <linux/dma-mapping.h> +#include <linux/slab.h>  #include <asm/irq.h>  #include <asm/io.h> @@ -5898,7 +5899,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i  	/* Limit the number of tx's outstanding for hw bug */  	if (id->driver_data & DEV_NEED_TX_LIMIT) {  		np->tx_limit = 1; -		if ((id->driver_data & DEV_NEED_TX_LIMIT2) && +		if (((id->driver_data & DEV_NEED_TX_LIMIT2) == DEV_NEED_TX_LIMIT2) &&  		    pci_dev->revision >= 0xA2)  			np->tx_limit = 0;  	} diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c index cf4f674f9e2..0a973e71876 100644 --- a/drivers/net/fs_enet/mac-fcc.c +++ b/drivers/net/fs_enet/mac-fcc.c @@ -19,7 +19,6 @@  #include <linux/ptrace.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/init.h>  #include <linux/delay.h> @@ -34,6 +33,7 @@  #include <linux/platform_device.h>  #include <linux/phy.h>  #include <linux/of_device.h> +#include <linux/gfp.h>  #include <asm/immap_cpm2.h>  #include <asm/mpc8260.h> diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c index cd2c6cca5f2..ec81f50d591 100644 --- a/drivers/net/fs_enet/mac-fec.c +++ b/drivers/net/fs_enet/mac-fec.c @@ -19,7 +19,6 @@  #include <linux/ptrace.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/init.h>  #include <linux/delay.h> @@ -33,6 +32,7 @@  #include <linux/fs.h>  #include <linux/platform_device.h>  #include <linux/of_device.h> +#include <linux/gfp.h>  #include <asm/irq.h>  #include <asm/uaccess.h> diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c index c490a466cae..34d3da751eb 100644 --- a/drivers/net/fs_enet/mac-scc.c +++ b/drivers/net/fs_enet/mac-scc.c @@ -19,7 +19,6 @@  #include <linux/ptrace.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/init.h>  #include <linux/delay.h> diff --git a/drivers/net/fsl_pq_mdio.c b/drivers/net/fsl_pq_mdio.c index d5160edf2fc..3acac5f930c 100644 --- a/drivers/net/fsl_pq_mdio.c +++ b/drivers/net/fsl_pq_mdio.c @@ -205,8 +205,6 @@ static int fsl_pq_mdio_find_free(struct mii_bus *new_bus)  static u32 __iomem *get_gfar_tbipa(struct fsl_pq_mdio __iomem *regs, struct device_node *np)  {  	struct gfar __iomem *enet_regs; -	u32 __iomem *ioremap_tbipa; -	u64 addr, size;  	/*  	 * This is mildly evil, but so is our hardware for doing this. @@ -220,9 +218,7 @@ static u32 __iomem *get_gfar_tbipa(struct fsl_pq_mdio __iomem *regs, struct devi  		return &enet_regs->tbipa;  	} else if (of_device_is_compatible(np, "fsl,etsec2-mdio") ||  			of_device_is_compatible(np, "fsl,etsec2-tbi")) { -		addr = of_translate_address(np, of_get_address(np, 1, &size, NULL)); -		ioremap_tbipa = ioremap(addr, size); -		return ioremap_tbipa; +		return of_iomap(np, 1);  	} else  		return NULL;  } @@ -279,6 +275,7 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev,  	u32 __iomem *tbipa;  	struct mii_bus *new_bus;  	int tbiaddr = -1; +	const u32 *addrp;  	u64 addr = 0, size = 0;  	int err = 0; @@ -297,8 +294,19 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev,  	new_bus->priv = priv;  	fsl_pq_mdio_bus_name(new_bus->id, np); +	addrp = of_get_address(np, 0, &size, NULL); +	if (!addrp) { +		err = -EINVAL; +		goto err_free_bus; +	} +  	/* Set the PHY base address */ -	addr = of_translate_address(np, of_get_address(np, 0, &size, NULL)); +	addr = of_translate_address(np, addrp); +	if (addr == OF_BAD_ADDR) { +		err = -EINVAL; +		goto err_free_bus; +	} +  	map = ioremap(addr, size);  	if (!map) {  		err = -ENOMEM; diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index b6715553cf1..4e97ca18299 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -549,12 +549,8 @@ static int gfar_parse_group(struct device_node *np,  		struct gfar_private *priv, const char *model)  {  	u32 *queue_mask; -	u64 addr, size; - -	addr = of_translate_address(np, -			of_get_address(np, 0, &size, NULL)); -	priv->gfargrp[priv->num_grps].regs = ioremap(addr, size); +	priv->gfargrp[priv->num_grps].regs = of_iomap(np, 0);  	if (!priv->gfargrp[priv->num_grps].regs)  		return -ENOMEM; @@ -676,7 +672,7 @@ static int gfar_of_init(struct of_device *ofdev, struct net_device **pdev)  		priv->rx_queue[i] = NULL;  	for (i = 0; i < priv->num_tx_queues; i++) { -		priv->tx_queue[i] =  (struct gfar_priv_tx_q *)kmalloc( +		priv->tx_queue[i] =  (struct gfar_priv_tx_q *)kzalloc(  				sizeof (struct gfar_priv_tx_q), GFP_KERNEL);  		if (!priv->tx_queue[i]) {  			err = -ENOMEM; @@ -689,7 +685,7 @@ static int gfar_of_init(struct of_device *ofdev, struct net_device **pdev)  	}  	for (i = 0; i < priv->num_rx_queues; i++) { -		priv->rx_queue[i] = (struct gfar_priv_rx_q *)kmalloc( +		priv->rx_queue[i] = (struct gfar_priv_rx_q *)kzalloc(  					sizeof (struct gfar_priv_rx_q), GFP_KERNEL);  		if (!priv->rx_queue[i]) {  			err = -ENOMEM; @@ -1120,10 +1116,10 @@ static int gfar_probe(struct of_device *ofdev,  	/* provided which set of benchmarks. */  	printk(KERN_INFO "%s: Running with NAPI enabled\n", dev->name);  	for (i = 0; i < priv->num_rx_queues; i++) -		printk(KERN_INFO "%s: :RX BD ring size for Q[%d]: %d\n", +		printk(KERN_INFO "%s: RX BD ring size for Q[%d]: %d\n",  			dev->name, i, priv->rx_queue[i]->rx_ring_size);  	for(i = 0; i < priv->num_tx_queues; i++) -		 printk(KERN_INFO "%s:TX BD ring size for Q[%d]: %d\n", +		 printk(KERN_INFO "%s: TX BD ring size for Q[%d]: %d\n",  			dev->name, i, priv->tx_queue[i]->tx_ring_size);  	return 0; @@ -1515,9 +1511,9 @@ static void gfar_halt_nodisable(struct net_device *dev)  		tempval |= (DMACTRL_GRS | DMACTRL_GTS);  		gfar_write(®s->dmactrl, tempval); -		while (!(gfar_read(®s->ievent) & -			 (IEVENT_GRSC | IEVENT_GTSC))) -			cpu_relax(); +		spin_event_timeout(((gfar_read(®s->ievent) & +			 (IEVENT_GRSC | IEVENT_GTSC)) == +			 (IEVENT_GRSC | IEVENT_GTSC)), -1, 0);  	}  } @@ -1638,13 +1634,13 @@ static void free_skb_resources(struct gfar_private *priv)  	/* Go through all the buffer descriptors and free their data buffers */  	for (i = 0; i < priv->num_tx_queues; i++) {  		tx_queue = priv->tx_queue[i]; -		if(!tx_queue->tx_skbuff) +		if(tx_queue->tx_skbuff)  			free_skb_tx_queue(tx_queue);  	}  	for (i = 0; i < priv->num_rx_queues; i++) {  		rx_queue = priv->rx_queue[i]; -		if(!rx_queue->rx_skbuff) +		if(rx_queue->rx_skbuff)  			free_skb_rx_queue(rx_queue);  	} @@ -2393,6 +2389,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev)  	 * as many bytes as needed to align the data properly  	 */  	skb_reserve(skb, alignamount); +	GFAR_CB(skb)->alignamount = alignamount;  	return skb;  } @@ -2533,13 +2530,13 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)  				newskb = skb;  			else if (skb) {  				/* -				 * We need to reset ->data to what it +				 * We need to un-reserve() the skb to what it  				 * was before gfar_new_skb() re-aligned  				 * it to an RXBUF_ALIGNMENT boundary  				 * before we put the skb back on the  				 * recycle list.  				 */ -				skb->data = skb->head + NET_SKB_PAD; +				skb_reserve(skb, -GFAR_CB(skb)->alignamount);  				__skb_queue_head(&priv->rx_recycle, skb);  			}  		} else { diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 3d72dc43dca..17d25e71423 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -566,6 +566,12 @@ struct rxfcb {  	u16	vlctl;	/* VLAN control word */  }; +struct gianfar_skb_cb { +	int alignamount; +}; + +#define GFAR_CB(skb) ((struct gianfar_skb_cb *)((skb)->cb)) +  struct rmon_mib  {  	u32	tr64;	/* 0x.680 - Transmit and Receive 64-byte Frame Counter */ diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index 1010367695e..9bda023c023 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -19,7 +19,6 @@  #include <linux/kernel.h>  #include <linux/string.h>  #include <linux/errno.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/init.h>  #include <linux/delay.h> diff --git a/drivers/net/gianfar_sysfs.c b/drivers/net/gianfar_sysfs.c index b98c6c51229..64f4094ac7f 100644 --- a/drivers/net/gianfar_sysfs.c +++ b/drivers/net/gianfar_sysfs.c @@ -24,7 +24,6 @@  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/unistd.h> -#include <linux/slab.h>  #include <linux/init.h>  #include <linux/delay.h>  #include <linux/etherdevice.h> diff --git a/drivers/net/greth.c b/drivers/net/greth.c index 2b9c1cbc9ec..3a90430de91 100644 --- a/drivers/net/greth.c +++ b/drivers/net/greth.c @@ -34,6 +34,7 @@  #include <linux/mii.h>  #include <linux/of_device.h>  #include <linux/of_platform.h> +#include <linux/slab.h>  #include <asm/cacheflush.h>  #include <asm/byteorder.h> diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 373546dd083..5d6f1387959 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -153,7 +153,6 @@ static int tx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};  #include <linux/time.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/pci.h>  #include <linux/init.h> diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 689b9bd377a..4b52c767ad0 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -24,6 +24,7 @@  #include <linux/errno.h>  #include <linux/netdevice.h>  #include <linux/timer.h> +#include <linux/slab.h>  #include <net/ax25.h>  #include <linux/etherdevice.h>  #include <linux/skbuff.h> diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index bdadf3e23c9..14f01d156db 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -61,6 +61,7 @@  #include <linux/kernel.h>  #include <linux/string.h>  #include <linux/net.h> +#include <linux/slab.h>  #include <net/ax25.h>  #include <linux/inet.h>  #include <linux/netdevice.h> diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index 9ee76b42668..52b14256e2c 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c @@ -32,6 +32,7 @@  #include <linux/kernel.h>  #include <linux/mm.h>  #include <linux/netdevice.h> +#include <linux/slab.h>  #include <linux/rtnetlink.h>  #include <linux/sockios.h>  #include <linux/workqueue.h> diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c index 91c5790c958..b8bdf9d51cd 100644 --- a/drivers/net/hamradio/hdlcdrv.c +++ b/drivers/net/hamradio/hdlcdrv.c @@ -48,7 +48,6 @@  #include <linux/net.h>  #include <linux/in.h>  #include <linux/if.h> -#include <linux/slab.h>  #include <linux/errno.h>  #include <linux/init.h>  #include <linux/bitops.h> diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 7db0a1c3216..66e88bd59ca 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -26,6 +26,7 @@  #include <linux/interrupt.h>  #include <linux/in.h>  #include <linux/inet.h> +#include <linux/slab.h>  #include <linux/tty.h>  #include <linux/errno.h>  #include <linux/netdevice.h> diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index 35c936175bb..f3a96b84391 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -158,7 +158,6 @@  #include <linux/in.h>  #include <linux/fcntl.h>  #include <linux/ptrace.h> -#include <linux/slab.h>  #include <linux/delay.h>  #include <linux/skbuff.h>  #include <linux/netdevice.h> diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index b766a69bf0c..4daad8cd56e 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -102,7 +102,6 @@  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/eisa.h>  #include <linux/pci.h> diff --git a/drivers/net/hplance.c b/drivers/net/hplance.c index 3e3528ade25..b6060f7538d 100644 --- a/drivers/net/hplance.c +++ b/drivers/net/hplance.c @@ -10,7 +10,6 @@  #include <linux/types.h>  #include <linux/interrupt.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/delay.h>  #include <linux/init.h> diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c index d496b6f4a47..24724b4ad70 100644 --- a/drivers/net/hydra.c +++ b/drivers/net/hydra.c @@ -17,7 +17,6 @@  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/netdevice.h>  #include <linux/etherdevice.h> diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index fb0ac6d7c04..dd873cc41c2 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -39,6 +39,7 @@  #include <linux/bitops.h>  #include <linux/workqueue.h>  #include <linux/of.h> +#include <linux/slab.h>  #include <asm/processor.h>  #include <asm/io.h> diff --git a/drivers/net/ibm_newemac/core.h b/drivers/net/ibm_newemac/core.h index 18d56c6c423..b1cbe6fdfc7 100644 --- a/drivers/net/ibm_newemac/core.h +++ b/drivers/net/ibm_newemac/core.h @@ -34,6 +34,7 @@  #include <linux/dma-mapping.h>  #include <linux/spinlock.h>  #include <linux/of_platform.h> +#include <linux/slab.h>  #include <asm/io.h>  #include <asm/dcr.h> diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c index 2a2fc17b287..5b3d94419fe 100644 --- a/drivers/net/ibm_newemac/mal.c +++ b/drivers/net/ibm_newemac/mal.c @@ -26,6 +26,7 @@   */  #include <linux/delay.h> +#include <linux/slab.h>  #include "core.h"  #include <asm/dcr-regs.h> diff --git a/drivers/net/ibm_newemac/rgmii.c b/drivers/net/ibm_newemac/rgmii.c index 8d76cb89dbd..5b90d34c845 100644 --- a/drivers/net/ibm_newemac/rgmii.c +++ b/drivers/net/ibm_newemac/rgmii.c @@ -21,6 +21,7 @@   * option) any later version.   *   */ +#include <linux/slab.h>  #include <linux/kernel.h>  #include <linux/ethtool.h>  #include <asm/io.h> diff --git a/drivers/net/ibm_newemac/zmii.c b/drivers/net/ibm_newemac/zmii.c index 17b15412494..1f038f808ab 100644 --- a/drivers/net/ibm_newemac/zmii.c +++ b/drivers/net/ibm_newemac/zmii.c @@ -21,6 +21,7 @@   * option) any later version.   *   */ +#include <linux/slab.h>  #include <linux/kernel.h>  #include <linux/ethtool.h>  #include <asm/io.h> diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index b5d0f4e973f..7d6cf3340c1 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -79,7 +79,6 @@ History:  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/delay.h>  #include <linux/time.h> diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 0bc777bac9b..cd508a8ee25 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -49,6 +49,7 @@  #include <linux/proc_fs.h>  #include <linux/in.h>  #include <linux/ip.h> +#include <linux/slab.h>  #include <net/net_namespace.h>  #include <asm/hvcall.h>  #include <asm/atomic.h> diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index 9d7fa2fb85e..4a32bed77c7 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -30,7 +30,6 @@   */  #include <linux/types.h> -#include <linux/slab.h>  #include <linux/if_ether.h>  #include "e1000_mac.h" @@ -94,6 +93,7 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)  	case E1000_DEV_ID_82576_FIBER:  	case E1000_DEV_ID_82576_SERDES:  	case E1000_DEV_ID_82576_QUAD_COPPER: +	case E1000_DEV_ID_82576_QUAD_COPPER_ET2:  	case E1000_DEV_ID_82576_SERDES_QUAD:  		mac->type = e1000_82576;  		break; diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h index 448005276b2..82a533f5192 100644 --- a/drivers/net/igb/e1000_hw.h +++ b/drivers/net/igb/e1000_hw.h @@ -41,6 +41,7 @@ struct e1000_hw;  #define E1000_DEV_ID_82576_FIBER              0x10E6  #define E1000_DEV_ID_82576_SERDES             0x10E7  #define E1000_DEV_ID_82576_QUAD_COPPER        0x10E8 +#define E1000_DEV_ID_82576_QUAD_COPPER_ET2    0x1526  #define E1000_DEV_ID_82576_NS                 0x150A  #define E1000_DEV_ID_82576_NS_SERDES          0x1518  #define E1000_DEV_ID_82576_SERDES_QUAD        0x150D diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c index 2a8a886b37e..be8d010e402 100644 --- a/drivers/net/igb/e1000_mac.c +++ b/drivers/net/igb/e1000_mac.c @@ -1367,7 +1367,8 @@ out:   *  igb_enable_mng_pass_thru - Enable processing of ARP's   *  @hw: pointer to the HW structure   * - *  Verifies the hardware needs to allow ARPs to be processed by the host. + *  Verifies the hardware needs to leave interface enabled so that frames can + *  be directed to and from the management interface.   **/  bool igb_enable_mng_pass_thru(struct e1000_hw *hw)  { @@ -1380,8 +1381,7 @@ bool igb_enable_mng_pass_thru(struct e1000_hw *hw)  	manc = rd32(E1000_MANC); -	if (!(manc & E1000_MANC_RCV_TCO_EN) || -	    !(manc & E1000_MANC_EN_MAC_ADDR_FILTER)) +	if (!(manc & E1000_MANC_RCV_TCO_EN))  		goto out;  	if (hw->mac.arc_subsystem_valid) { diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index a1775705b24..3b772b822a5 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -267,7 +267,6 @@ struct igb_adapter {  	/* TX */  	struct igb_ring *tx_ring[16]; -	unsigned long tx_queue_len;  	u32 tx_timeout_count;  	/* RX */ diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index a4cead12fd9..74303849010 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -35,6 +35,7 @@  #include <linux/if_ether.h>  #include <linux/ethtool.h>  #include <linux/sched.h> +#include <linux/slab.h>  #include "igb.h" @@ -1813,6 +1814,7 @@ static int igb_wol_exclusion(struct igb_adapter *adapter,  		retval = 0;  		break;  	case E1000_DEV_ID_82576_QUAD_COPPER: +	case E1000_DEV_ID_82576_QUAD_COPPER_ET2:  		/* quad port adapters only support WoL on port A */  		if (!(adapter->flags & IGB_FLAG_QUAD_PORT_A)) {  			wol->supported = 0; diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 0ed25f059a0..c9baa2aa98c 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -32,6 +32,7 @@  #include <linux/pagemap.h>  #include <linux/netdevice.h>  #include <linux/ipv6.h> +#include <linux/slab.h>  #include <net/checksum.h>  #include <net/ip6_checksum.h>  #include <linux/net_tstamp.h> @@ -72,6 +73,7 @@ static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = {  	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_FIBER), board_82575 },  	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES), board_82575 },  	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES_QUAD), board_82575 }, +	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER_ET2), board_82575 },  	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER), board_82575 },  	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER), board_82575 },  	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES), board_82575 }, @@ -1104,9 +1106,6 @@ static void igb_configure(struct igb_adapter *adapter)  		struct igb_ring *ring = adapter->rx_ring[i];  		igb_alloc_rx_buffers_adv(ring, igb_desc_unused(ring));  	} - - -	adapter->tx_queue_len = netdev->tx_queue_len;  }  /** @@ -1212,7 +1211,6 @@ void igb_down(struct igb_adapter *adapter)  	del_timer_sync(&adapter->watchdog_timer);  	del_timer_sync(&adapter->phy_info_timer); -	netdev->tx_queue_len = adapter->tx_queue_len;  	netif_carrier_off(netdev);  	/* record the stats before reset*/ @@ -1614,6 +1612,7 @@ static int __devinit igb_probe(struct pci_dev *pdev,  			adapter->eeprom_wol = 0;  		break;  	case E1000_DEV_ID_82576_QUAD_COPPER: +	case E1000_DEV_ID_82576_QUAD_COPPER_ET2:  		/* if quad port adapter, disable WoL on all but port A */  		if (global_quad_port_a != 0)  			adapter->eeprom_wol = 0; @@ -3105,17 +3104,13 @@ static void igb_watchdog_task(struct work_struct *work)  			       ((ctrl & E1000_CTRL_RFCE) ?  "RX" :  			       ((ctrl & E1000_CTRL_TFCE) ?  "TX" : "None"))); -			/* tweak tx_queue_len according to speed/duplex and -			 * adjust the timeout factor */ -			netdev->tx_queue_len = adapter->tx_queue_len; +			/* adjust timeout factor according to speed/duplex */  			adapter->tx_timeout_factor = 1;  			switch (adapter->link_speed) {  			case SPEED_10: -				netdev->tx_queue_len = 10;  				adapter->tx_timeout_factor = 14;  				break;  			case SPEED_100: -				netdev->tx_queue_len = 100;  				/* maybe add some timeout factor ? */  				break;  			} @@ -3962,7 +3957,7 @@ void igb_update_stats(struct igb_adapter *adapter)  	struct net_device_stats *net_stats = igb_get_stats(adapter->netdev);  	struct e1000_hw *hw = &adapter->hw;  	struct pci_dev *pdev = adapter->pdev; -	u32 rnbc, reg; +	u32 reg, mpc;  	u16 phy_tmp;  	int i;  	u64 bytes, packets; @@ -4020,7 +4015,9 @@ void igb_update_stats(struct igb_adapter *adapter)  	adapter->stats.symerrs += rd32(E1000_SYMERRS);  	adapter->stats.sec += rd32(E1000_SEC); -	adapter->stats.mpc += rd32(E1000_MPC); +	mpc = rd32(E1000_MPC); +	adapter->stats.mpc += mpc; +	net_stats->rx_fifo_errors += mpc;  	adapter->stats.scc += rd32(E1000_SCC);  	adapter->stats.ecol += rd32(E1000_ECOL);  	adapter->stats.mcc += rd32(E1000_MCC); @@ -4035,9 +4032,7 @@ void igb_update_stats(struct igb_adapter *adapter)  	adapter->stats.gptc += rd32(E1000_GPTC);  	adapter->stats.gotc += rd32(E1000_GOTCL);  	rd32(E1000_GOTCH); /* clear GOTCL */ -	rnbc = rd32(E1000_RNBC); -	adapter->stats.rnbc += rnbc; -	net_stats->rx_fifo_errors += rnbc; +	adapter->stats.rnbc += rd32(E1000_RNBC);  	adapter->stats.ruc += rd32(E1000_RUC);  	adapter->stats.rfc += rd32(E1000_RFC);  	adapter->stats.rjc += rd32(E1000_RJC); @@ -5109,7 +5104,7 @@ static void igb_receive_skb(struct igb_q_vector *q_vector,  {  	struct igb_adapter *adapter = q_vector->adapter; -	if (vlan_tag) +	if (vlan_tag && adapter->vlgrp)  		vlan_gro_receive(&q_vector->napi, adapter->vlgrp,  		                 vlan_tag, skb);  	else diff --git a/drivers/net/igbvf/igbvf.h b/drivers/net/igbvf/igbvf.h index a1774b29d22..debeee2dc71 100644 --- a/drivers/net/igbvf/igbvf.h +++ b/drivers/net/igbvf/igbvf.h @@ -198,7 +198,6 @@ struct igbvf_adapter {  	struct igbvf_ring *tx_ring /* One per active queue */  	____cacheline_aligned_in_smp; -	unsigned long tx_queue_len;  	unsigned int restart_queue;  	u32 txd_cmd; diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index a77afd8a14b..1b1edad1eb5 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -35,6 +35,7 @@  #include <linux/netdevice.h>  #include <linux/tcp.h>  #include <linux/ipv6.h> +#include <linux/slab.h>  #include <net/checksum.h>  #include <net/ip6_checksum.h>  #include <linux/mii.h> @@ -1304,8 +1305,6 @@ static void igbvf_configure_tx(struct igbvf_adapter *adapter)  	/* enable Report Status bit */  	adapter->txd_cmd |= E1000_ADVTXD_DCMD_RS; - -	adapter->tx_queue_len = adapter->netdev->tx_queue_len;  }  /** @@ -1524,7 +1523,6 @@ void igbvf_down(struct igbvf_adapter *adapter)  	del_timer_sync(&adapter->watchdog_timer); -	netdev->tx_queue_len = adapter->tx_queue_len;  	netif_carrier_off(netdev);  	/* record the stats before reset*/ @@ -1857,21 +1855,15 @@ static void igbvf_watchdog_task(struct work_struct *work)  			                          &adapter->link_duplex);  			igbvf_print_link_info(adapter); -			/* -			 * tweak tx_queue_len according to speed/duplex -			 * and adjust the timeout factor -			 */ -			netdev->tx_queue_len = adapter->tx_queue_len; +			/* adjust timeout factor according to speed/duplex */  			adapter->tx_timeout_factor = 1;  			switch (adapter->link_speed) {  			case SPEED_10:  				txb2b = 0; -				netdev->tx_queue_len = 10;  				adapter->tx_timeout_factor = 16;  				break;  			case SPEED_100:  				txb2b = 0; -				netdev->tx_queue_len = 100;  				/* maybe add some timeout factor ? */  				break;  			} diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index 70871b9b045..8f6197d647c 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -44,6 +44,7 @@  #include <linux/tcp.h>  #include <linux/udp.h>  #include <linux/dma-mapping.h> +#include <linux/gfp.h>  #ifdef CONFIG_SERIAL_8250  #include <linux/serial_core.h> diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index 150415e83f6..639bf9fb027 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -22,6 +22,7 @@   */  #include <linux/crc32.h>  #include <linux/ethtool.h> +#include <linux/gfp.h>  #include <linux/mii.h>  #include <linux/mutex.h> diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index 12c7b006f76..28992c815cb 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -22,6 +22,7 @@   ********************************************************************/  #include <linux/module.h> +#include <linux/gfp.h>  #include <linux/kernel.h>  #include <linux/types.h> @@ -29,7 +30,6 @@  #include <linux/netdevice.h>  #include <linux/ioport.h>  #include <linux/delay.h> -#include <linux/slab.h>  #include <linux/init.h>  #include <linux/rtnetlink.h>  #include <linux/serial_reg.h> diff --git a/drivers/net/irda/bfin_sir.h b/drivers/net/irda/bfin_sir.h index dac71b1f4f9..b54a6f08db4 100644 --- a/drivers/net/irda/bfin_sir.h +++ b/drivers/net/irda/bfin_sir.h @@ -16,6 +16,7 @@  #include <linux/delay.h>  #include <linux/platform_device.h>  #include <linux/dma-mapping.h> +#include <linux/slab.h>  #include <net/irda/irda.h>  #include <net/irda/wrapper.h> diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index 20f9bc62668..ee1dde52e8f 100644 --- a/drivers/net/irda/irtty-sir.c +++ b/drivers/net/irda/irtty-sir.c @@ -28,6 +28,7 @@  #include <linux/module.h>  #include <linux/kernel.h> +#include <linux/slab.h>  #include <linux/tty.h>  #include <linux/init.h>  #include <asm/uaccess.h> diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 2413295ebd9..e30cdbb1474 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -43,6 +43,7 @@   ********************************************************************/  #include <linux/module.h> +#include <linux/gfp.h>  #include <linux/kernel.h>  #include <linux/types.h> @@ -50,7 +51,6 @@  #include <linux/netdevice.h>  #include <linux/ioport.h>  #include <linux/delay.h> -#include <linux/slab.h>  #include <linux/init.h>  #include <linux/rtnetlink.h>  #include <linux/dma-mapping.h> diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c index 84db145d2b5..1a54f6bb68c 100644 --- a/drivers/net/irda/pxaficp_ir.c +++ b/drivers/net/irda/pxaficp_ir.c @@ -18,6 +18,7 @@  #include <linux/platform_device.h>  #include <linux/clk.h>  #include <linux/gpio.h> +#include <linux/slab.h>  #include <net/irda/irda.h>  #include <net/irda/irmod.h> diff --git a/drivers/net/irda/sh_sir.c b/drivers/net/irda/sh_sir.c index d7c983dc91a..0745581c4b5 100644 --- a/drivers/net/irda/sh_sir.c +++ b/drivers/net/irda/sh_sir.c @@ -14,6 +14,7 @@  #include <linux/module.h>  #include <linux/platform_device.h> +#include <linux/slab.h>  #include <net/irda/wrapper.h>  #include <net/irda/irda_device.h>  #include <asm/clock.h> diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index 4b2a1a9eac2..de91cd14016 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -13,6 +13,7 @@  #include <linux/module.h>  #include <linux/kernel.h> +#include <linux/slab.h>  #include <linux/init.h>  #include <linux/delay.h> diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 8f7d0d146f2..6af84d88cd0 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -48,13 +48,13 @@  #include <linux/netdevice.h>  #include <linux/ioport.h>  #include <linux/delay.h> -#include <linux/slab.h>  #include <linux/init.h>  #include <linux/rtnetlink.h>  #include <linux/serial_reg.h>  #include <linux/dma-mapping.h>  #include <linux/pnp.h>  #include <linux/platform_device.h> +#include <linux/gfp.h>  #include <asm/io.h>  #include <asm/dma.h> diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index 6533c010cf5..b0a6cd815be 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -45,11 +45,11 @@ F02 Oct/28/02: Add SB device ID for 3147 and 3177.  #include <linux/netdevice.h>  #include <linux/ioport.h>  #include <linux/delay.h> -#include <linux/slab.h>  #include <linux/init.h>  #include <linux/rtnetlink.h>  #include <linux/pci.h>  #include <linux/dma-mapping.h> +#include <linux/gfp.h>  #include <asm/io.h>  #include <asm/dma.h> diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index 551810fd297..cb0cb758be6 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -46,10 +46,10 @@  #include <linux/netdevice.h>  #include <linux/ioport.h>  #include <linux/delay.h> -#include <linux/slab.h>  #include <linux/init.h>  #include <linux/rtnetlink.h>  #include <linux/dma-mapping.h> +#include <linux/gfp.h>  #include <asm/io.h>  #include <asm/dma.h> @@ -65,7 +65,6 @@  #undef  CONFIG_NETWINDER_TX_DMA_PROBLEMS /* Not needed */  #define CONFIG_NETWINDER_RX_DMA_PROBLEMS /* Must have this one! */  #endif -#undef  CONFIG_USE_INTERNAL_TIMER  /* Just cannot make that timer work */  #define CONFIG_USE_W977_PNP        /* Currently needed */  #define PIO_MAX_SPEED       115200  @@ -533,25 +532,6 @@ static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb,  		self->tx_buff.len = skb->len;  		mtt = irda_get_mtt(skb); -#ifdef CONFIG_USE_INTERNAL_TIMER -	        if (mtt > 50) { -			/* Adjust for timer resolution */ -			mtt /= 1000+1; - -			/* Setup timer */ -			switch_bank(iobase, SET4); -			outb(mtt & 0xff, iobase+TMRL); -			outb((mtt >> 8) & 0x0f, iobase+TMRH); -			 -			/* Start timer */ -			outb(IR_MSL_EN_TMR, iobase+IR_MSL); -			self->io.direction = IO_XMIT; -			 -			/* Enable timer interrupt */ -			switch_bank(iobase, SET0); -			outb(ICR_ETMRI, iobase+ICR); -		} else { -#endif  			IRDA_DEBUG(4, "%s(%ld), mtt=%d\n", __func__ , jiffies, mtt);  			if (mtt)  				udelay(mtt); @@ -560,9 +540,6 @@ static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb,  			switch_bank(iobase, SET0);  	 		outb(ICR_EDMAI, iobase+ICR);  	     		w83977af_dma_write(self, iobase); -#ifdef CONFIG_USE_INTERNAL_TIMER -		} -#endif  	} else {  		self->tx_buff.data = self->tx_buff.head;  		self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,  @@ -876,20 +853,7 @@ static int w83977af_dma_receive_complete(struct w83977af_ir *self)  			/* Check if we have transferred all data to memory */  			switch_bank(iobase, SET0);  			if (inb(iobase+USR) & USR_RDR) { -#ifdef CONFIG_USE_INTERNAL_TIMER -				/* Put this entry back in fifo */ -				st_fifo->head--; -				st_fifo->len++; -				st_fifo->entries[st_fifo->head].status = status; -				st_fifo->entries[st_fifo->head].len = len; -				 -				/* Restore set register */ -				outb(set, iobase+SSR); -			 -				return FALSE; 	/* I'll be back! */ -#else  				udelay(80); /* Should be enough!? */ -#endif  			}  			skb = dev_alloc_skb(len+1); diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index e6e972d9b7c..773c59c8969 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -69,6 +69,7 @@  #include <linux/mm.h>  #include <linux/ethtool.h>  #include <linux/if_ether.h> +#include <linux/slab.h>  #include <asm/abs_addr.h>  #include <asm/iseries/mf.h> diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 19e94ee155a..79c35ae3718 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -204,14 +204,17 @@ enum ixgbe_ring_f_enum {  #define IXGBE_MAX_FDIR_INDICES 64  #ifdef IXGBE_FCOE  #define IXGBE_MAX_FCOE_INDICES  8 +#define MAX_RX_QUEUES (IXGBE_MAX_FDIR_INDICES + IXGBE_MAX_FCOE_INDICES) +#define MAX_TX_QUEUES (IXGBE_MAX_FDIR_INDICES + IXGBE_MAX_FCOE_INDICES) +#else +#define MAX_RX_QUEUES IXGBE_MAX_FDIR_INDICES +#define MAX_TX_QUEUES IXGBE_MAX_FDIR_INDICES  #endif /* IXGBE_FCOE */  struct ixgbe_ring_feature {  	int indices;  	int mask;  } ____cacheline_internodealigned_in_smp; -#define MAX_RX_QUEUES 128 -#define MAX_TX_QUEUES 128  #define MAX_RX_PACKET_BUFFERS ((adapter->flags & IXGBE_FLAG_DCB_ENABLED) \                                ? 8 : 1) diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 1f30e163bd9..12fc0e7ba2c 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -39,6 +39,9 @@  #define IXGBE_82599_MC_TBL_SIZE   128  #define IXGBE_82599_VFT_TBL_SIZE  128 +void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw); +void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw); +void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);  s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,                                            ixgbe_link_speed speed,                                            bool autoneg, @@ -68,7 +71,15 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw)  	if (hw->phy.multispeed_fiber) {  		/* Set up dual speed SFP+ support */  		mac->ops.setup_link = &ixgbe_setup_mac_link_multispeed_fiber; +		mac->ops.disable_tx_laser = +		                       &ixgbe_disable_tx_laser_multispeed_fiber; +		mac->ops.enable_tx_laser = +		                        &ixgbe_enable_tx_laser_multispeed_fiber; +		mac->ops.flap_tx_laser = &ixgbe_flap_tx_laser_multispeed_fiber;  	} else { +		mac->ops.disable_tx_laser = NULL; +		mac->ops.enable_tx_laser = NULL; +		mac->ops.flap_tx_laser = NULL;  		if ((mac->ops.get_media_type(hw) ==  		     ixgbe_media_type_backplane) &&  		    (hw->phy.smart_speed == ixgbe_smart_speed_auto || @@ -412,6 +423,67 @@ s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw,  	return status;  } + /** +  *  ixgbe_disable_tx_laser_multispeed_fiber - Disable Tx laser +  *  @hw: pointer to hardware structure +  * +  *  The base drivers may require better control over SFP+ module +  *  PHY states.  This includes selectively shutting down the Tx +  *  laser on the PHY, effectively halting physical link. +  **/ +void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw) +{ +	u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP); + +	/* Disable tx laser; allow 100us to go dark per spec */ +	esdp_reg |= IXGBE_ESDP_SDP3; +	IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); +	IXGBE_WRITE_FLUSH(hw); +	udelay(100); +} + +/** + *  ixgbe_enable_tx_laser_multispeed_fiber - Enable Tx laser + *  @hw: pointer to hardware structure + * + *  The base drivers may require better control over SFP+ module + *  PHY states.  This includes selectively turning on the Tx + *  laser on the PHY, effectively starting physical link. + **/ +void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw) +{ +	u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP); + +	/* Enable tx laser; allow 100ms to light up */ +	esdp_reg &= ~IXGBE_ESDP_SDP3; +	IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); +	IXGBE_WRITE_FLUSH(hw); +	msleep(100); +} + +/** + *  ixgbe_flap_tx_laser_multispeed_fiber - Flap Tx laser + *  @hw: pointer to hardware structure + * + *  When the driver changes the link speeds that it can support, + *  it sets autotry_restart to true to indicate that we need to + *  initiate a new autotry session with the link partner.  To do + *  so, we set the speed then disable and re-enable the tx laser, to + *  alert the link partner that it also needs to restart autotry on its + *  end.  This is consistent with true clause 37 autoneg, which also + *  involves a loss of signal. + **/ +void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw) +{ +	hw_dbg(hw, "ixgbe_flap_tx_laser_multispeed_fiber\n"); + +	if (hw->mac.autotry_restart) { +		ixgbe_disable_tx_laser_multispeed_fiber(hw); +		ixgbe_enable_tx_laser_multispeed_fiber(hw); +		hw->mac.autotry_restart = false; +	} +} +  /**   *  ixgbe_setup_mac_link_multispeed_fiber - Set MAC link speed   *  @hw: pointer to hardware structure @@ -440,16 +512,6 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,  	speed &= phy_link_speed;  	/* -	 * When the driver changes the link speeds that it can support, -	 * it sets autotry_restart to true to indicate that we need to -	 * initiate a new autotry session with the link partner.  To do -	 * so, we set the speed then disable and re-enable the tx laser, to -	 * alert the link partner that it also needs to restart autotry on its -	 * end.  This is consistent with true clause 37 autoneg, which also -	 * involves a loss of signal. -	 */ - -	/*  	 * Try each speed one by one, highest priority first.  We do this in  	 * software because 10gb fiber doesn't support speed autonegotiation.  	 */ @@ -466,6 +528,7 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,  		/* Set the module link speed */  		esdp_reg |= (IXGBE_ESDP_SDP5_DIR | IXGBE_ESDP_SDP5);  		IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); +		IXGBE_WRITE_FLUSH(hw);  		/* Allow module to change analog characteristics (1G->10G) */  		msleep(40); @@ -478,19 +541,7 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,  			return status;  		/* Flap the tx laser if it has not already been done */ -		if (hw->mac.autotry_restart) { -			/* Disable tx laser; allow 100us to go dark per spec */ -			esdp_reg |= IXGBE_ESDP_SDP3; -			IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); -			udelay(100); - -			/* Enable tx laser; allow 2ms to light up per spec */ -			esdp_reg &= ~IXGBE_ESDP_SDP3; -			IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); -			msleep(2); - -			hw->mac.autotry_restart = false; -		} +		hw->mac.ops.flap_tx_laser(hw);  		/*  		 * Wait for the controller to acquire link.  Per IEEE 802.3ap, @@ -525,6 +576,7 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,  		esdp_reg &= ~IXGBE_ESDP_SDP5;  		esdp_reg |= IXGBE_ESDP_SDP5_DIR;  		IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); +		IXGBE_WRITE_FLUSH(hw);  		/* Allow module to change analog characteristics (10G->1G) */  		msleep(40); @@ -537,19 +589,7 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,  			return status;  		/* Flap the tx laser if it has not already been done */ -		if (hw->mac.autotry_restart) { -			/* Disable tx laser; allow 100us to go dark per spec */ -			esdp_reg |= IXGBE_ESDP_SDP3; -			IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); -			udelay(100); - -			/* Enable tx laser; allow 2ms to light up per spec */ -			esdp_reg &= ~IXGBE_ESDP_SDP3; -			IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); -			msleep(2); - -			hw->mac.autotry_restart = false; -		} +		hw->mac.ops.flap_tx_laser(hw);  		/* Wait for the link partner to also set speed */  		msleep(100); diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 7949a446e4c..8f461d5cee7 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -29,6 +29,7 @@  #include <linux/types.h>  #include <linux/module.h> +#include <linux/slab.h>  #include <linux/pci.h>  #include <linux/netdevice.h>  #include <linux/ethtool.h> @@ -1853,6 +1854,26 @@ static void ixgbe_diag_test(struct net_device *netdev,  		if (ixgbe_link_test(adapter, &data[4]))  			eth_test->flags |= ETH_TEST_FL_FAILED; +		if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) { +			int i; +			for (i = 0; i < adapter->num_vfs; i++) { +				if (adapter->vfinfo[i].clear_to_send) { +					netdev_warn(netdev, "%s", +						    "offline diagnostic is not " +						    "supported when VFs are " +						    "present\n"); +					data[0] = 1; +					data[1] = 1; +					data[2] = 1; +					data[3] = 1; +					eth_test->flags |= ETH_TEST_FL_FAILED; +					clear_bit(__IXGBE_TESTING, +						  &adapter->state); +					goto skip_ol_tests; +				} +			} +		} +  		if (if_running)  			/* indicate we're in test mode */  			dev_close(netdev); @@ -1908,6 +1929,7 @@ skip_loopback:  		clear_bit(__IXGBE_TESTING, &adapter->state);  	} +skip_ol_tests:  	msleep_interruptible(4 * 1000);  } diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index 4123dec0dfb..6493049b663 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -31,6 +31,7 @@  #include "ixgbe_dcb_82599.h"  #endif /* CONFIG_IXGBE_DCB */  #include <linux/if_ether.h> +#include <linux/gfp.h>  #include <scsi/scsi_cmnd.h>  #include <scsi/scsi_device.h>  #include <scsi/fc/fc_fs.h> @@ -202,6 +203,15 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid,  		addr = sg_dma_address(sg);  		len = sg_dma_len(sg);  		while (len) { +			/* max number of buffers allowed in one DDP context */ +			if (j >= IXGBE_BUFFCNT_MAX) { +				netif_err(adapter, drv, adapter->netdev, +					  "xid=%x:%d,%d,%d:addr=%llx " +					  "not enough descriptors\n", +					  xid, i, j, dmacount, (u64)addr); +				goto out_noddp_free; +			} +  			/* get the offset of length of current buffer */  			thisoff = addr & ((dma_addr_t)bufflen - 1);  			thislen = min((bufflen - thisoff), len); @@ -227,20 +237,13 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid,  			len -= thislen;  			addr += thislen;  			j++; -			/* max number of buffers allowed in one DDP context */ -			if (j > IXGBE_BUFFCNT_MAX) { -				DPRINTK(DRV, ERR, "xid=%x:%d,%d,%d:addr=%llx " -					"not enough descriptors\n", -					xid, i, j, dmacount, (u64)addr); -				goto out_noddp_free; -			}  		}  	}  	/* only the last buffer may have non-full bufflen */  	lastsize = thisoff + thislen;  	fcbuff = (IXGBE_FCBUFF_4KB << IXGBE_FCBUFF_BUFFSIZE_SHIFT); -	fcbuff |= (j << IXGBE_FCBUFF_BUFFCNT_SHIFT); +	fcbuff |= ((j & 0xff) << IXGBE_FCBUFF_BUFFCNT_SHIFT);  	fcbuff |= (firstoff << IXGBE_FCBUFF_OFFSET_SHIFT);  	fcbuff |= (IXGBE_FCBUFF_VALID); @@ -520,6 +523,9 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter)  	/* Enable L2 eth type filter for FCoE */  	IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_FCOE),  			(ETH_P_FCOE | IXGBE_ETQF_FCOE | IXGBE_ETQF_FILTER_EN)); +	/* Enable L2 eth type filter for FIP */ +	IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_FIP), +			(ETH_P_FIP | IXGBE_ETQF_FILTER_EN));  	if (adapter->ring_feature[RING_F_FCOE].indices) {  		/* Use multiple rx queues for FCoE by redirection table */  		for (i = 0; i < IXGBE_FCRETA_SIZE; i++) { @@ -530,6 +536,12 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter)  		}  		IXGBE_WRITE_REG(hw, IXGBE_FCRECTL, IXGBE_FCRECTL_ENA);  		IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FCOE), 0); +		fcoe_i = f->mask; +		fcoe_i &= IXGBE_FCRETA_ENTRY_MASK; +		fcoe_q = adapter->rx_ring[fcoe_i]->reg_idx; +		IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FIP), +				IXGBE_ETQS_QUEUE_EN | +				(fcoe_q << IXGBE_ETQS_RX_QUEUE_SHIFT));  	} else  {  		/* Use single rx queue for FCoE */  		fcoe_i = f->mask; @@ -539,6 +551,12 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter)  				IXGBE_ETQS_QUEUE_EN |  				(fcoe_q << IXGBE_ETQS_RX_QUEUE_SHIFT));  	} +	/* send FIP frames to the first FCoE queue */ +	fcoe_i = f->mask; +	fcoe_q = adapter->rx_ring[fcoe_i]->reg_idx; +	IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FIP), +			IXGBE_ETQS_QUEUE_EN | +			(fcoe_q << IXGBE_ETQS_RX_QUEUE_SHIFT));  	IXGBE_WRITE_REG(hw, IXGBE_FCRXCTRL,  			IXGBE_FCRXCTRL_FCOELLI | @@ -614,9 +632,9 @@ int ixgbe_fcoe_enable(struct net_device *netdev)  	netdev->vlan_features |= NETIF_F_FSO;  	netdev->vlan_features |= NETIF_F_FCOE_MTU;  	netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1; -	netdev_features_change(netdev);  	ixgbe_init_interrupt_scheme(adapter); +	netdev_features_change(netdev);  	if (netif_running(netdev))  		netdev->netdev_ops->ndo_open(netdev); @@ -660,11 +678,11 @@ int ixgbe_fcoe_disable(struct net_device *netdev)  	netdev->vlan_features &= ~NETIF_F_FSO;  	netdev->vlan_features &= ~NETIF_F_FCOE_MTU;  	netdev->fcoe_ddp_xid = 0; -	netdev_features_change(netdev);  	ixgbe_cleanup_fcoe(adapter); -  	ixgbe_init_interrupt_scheme(adapter); +	netdev_features_change(netdev); +  	if (netif_running(netdev))  		netdev->netdev_ops->ndo_open(netdev);  	rc = 0; diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 684af371462..6c00ee493a3 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -36,6 +36,7 @@  #include <linux/tcp.h>  #include <linux/pkt_sched.h>  #include <linux/ipv6.h> +#include <linux/slab.h>  #include <net/checksum.h>  #include <net/ip6_checksum.h>  #include <linux/ethtool.h> @@ -935,10 +936,12 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,  			if (skb->prev)  				skb = ixgbe_transform_rsc_queue(skb, &(rx_ring->rsc_count));  			if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) { -				if (IXGBE_RSC_CB(skb)->dma) +				if (IXGBE_RSC_CB(skb)->dma) {  					pci_unmap_single(pdev, IXGBE_RSC_CB(skb)->dma,  					                 rx_ring->rx_buf_len,  					                 PCI_DMA_FROMDEVICE); +					IXGBE_RSC_CB(skb)->dma = 0; +				}  				if (rx_ring->flags & IXGBE_RING_RX_PS_ENABLED)  					rx_ring->rsc_count += skb_shinfo(skb)->nr_frags;  				else @@ -2979,6 +2982,10 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)  	else  		ixgbe_configure_msi_and_legacy(adapter); +	/* enable the optics */ +	if (hw->phy.multispeed_fiber) +		hw->mac.ops.enable_tx_laser(hw); +  	clear_bit(__IXGBE_DOWN, &adapter->state);  	ixgbe_napi_enable_all(adapter); @@ -3054,6 +3061,14 @@ void ixgbe_reinit_locked(struct ixgbe_adapter *adapter)  	while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))  		msleep(1);  	ixgbe_down(adapter); +	/* +	 * If SR-IOV enabled then wait a bit before bringing the adapter +	 * back up to give the VFs time to respond to the reset.  The +	 * two second wait is based upon the watchdog timer cycle in +	 * the VF driver. +	 */ +	if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) +		msleep(2000);  	ixgbe_up(adapter);  	clear_bit(__IXGBE_RESETTING, &adapter->state);  } @@ -3126,10 +3141,12 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,  			rx_buffer_info->skb = NULL;  			do {  				struct sk_buff *this = skb; -				if (IXGBE_RSC_CB(this)->dma) +				if (IXGBE_RSC_CB(this)->dma) {  					pci_unmap_single(pdev, IXGBE_RSC_CB(this)->dma,  					                 rx_ring->rx_buf_len,  					                 PCI_DMA_FROMDEVICE); +					IXGBE_RSC_CB(this)->dma = 0; +				}  				skb = skb->prev;  				dev_kfree_skb(this);  			} while (skb); @@ -3230,15 +3247,21 @@ void ixgbe_down(struct ixgbe_adapter *adapter)  	/* signal that we are down to the interrupt handler */  	set_bit(__IXGBE_DOWN, &adapter->state); +	/* power down the optics */ +	if (hw->phy.multispeed_fiber) +		hw->mac.ops.disable_tx_laser(hw); +  	/* disable receive for all VFs and wait one second */  	if (adapter->num_vfs) { -		for (i = 0 ; i < adapter->num_vfs; i++) -			adapter->vfinfo[i].clear_to_send = 0; -  		/* ping all the active vfs to let them know we are going down */  		ixgbe_ping_all_vfs(adapter); +  		/* Disable all VFTE/VFRE TX/RX */  		ixgbe_disable_tx_rx(adapter); + +		/* Mark all the VFs as inactive */ +		for (i = 0 ; i < adapter->num_vfs; i++) +			adapter->vfinfo[i].clear_to_send = 0;  	}  	/* disable receives */ @@ -5018,6 +5041,7 @@ static void ixgbe_multispeed_fiber_task(struct work_struct *work)  	autoneg = hw->phy.autoneg_advertised;  	if ((!autoneg) && (hw->mac.ops.get_link_capabilities))  		hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation); +	hw->mac.autotry_restart = false;  	if (hw->mac.ops.setup_link)  		hw->mac.ops.setup_link(hw, autoneg, negotiation, true);  	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; @@ -5633,7 +5657,8 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb)  #ifdef IXGBE_FCOE  	if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) && -	    (skb->protocol == htons(ETH_P_FCOE))) { +	    ((skb->protocol == htons(ETH_P_FCOE)) || +	     (skb->protocol == htons(ETH_P_FIP)))) {  		txq &= (adapter->ring_feature[RING_F_FCOE].indices - 1);  		txq += adapter->ring_feature[RING_F_FCOE].mask;  		return txq; @@ -5680,18 +5705,25 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb,  	tx_ring = adapter->tx_ring[skb->queue_mapping]; -	if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) && -	    (skb->protocol == htons(ETH_P_FCOE))) { -		tx_flags |= IXGBE_TX_FLAGS_FCOE;  #ifdef IXGBE_FCOE +	if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) {  #ifdef CONFIG_IXGBE_DCB -		tx_flags &= ~(IXGBE_TX_FLAGS_VLAN_PRIO_MASK -			      << IXGBE_TX_FLAGS_VLAN_SHIFT); -		tx_flags |= ((adapter->fcoe.up << 13) -			      << IXGBE_TX_FLAGS_VLAN_SHIFT); -#endif +		/* for FCoE with DCB, we force the priority to what +		 * was specified by the switch */ +		if ((skb->protocol == htons(ETH_P_FCOE)) || +		    (skb->protocol == htons(ETH_P_FIP))) { +			tx_flags &= ~(IXGBE_TX_FLAGS_VLAN_PRIO_MASK +				      << IXGBE_TX_FLAGS_VLAN_SHIFT); +			tx_flags |= ((adapter->fcoe.up << 13) +				     << IXGBE_TX_FLAGS_VLAN_SHIFT); +		}  #endif +		/* flag for FCoE offloads */ +		if (skb->protocol == htons(ETH_P_FCOE)) +			tx_flags |= IXGBE_TX_FLAGS_FCOE;  	} +#endif +  	/* four things can cause us to need a context descriptor */  	if (skb_is_gso(skb) ||  	    (skb->ip_summed == CHECKSUM_PARTIAL) || @@ -6046,7 +6078,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,  	indices += min_t(unsigned int, num_possible_cpus(),  			 IXGBE_MAX_FCOE_INDICES);  #endif -	indices = min_t(unsigned int, indices, MAX_TX_QUEUES);  	netdev = alloc_etherdev_mq(sizeof(struct ixgbe_adapter), indices);  	if (!netdev) {  		err = -ENOMEM; @@ -6230,6 +6261,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,  		goto err_eeprom;  	} +	/* power down the optics */ +	if (hw->phy.multispeed_fiber) +		hw->mac.ops.disable_tx_laser(hw); +  	init_timer(&adapter->watchdog_timer);  	adapter->watchdog_timer.function = &ixgbe_watchdog;  	adapter->watchdog_timer.data = (unsigned long)adapter; @@ -6245,9 +6280,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,  	case IXGBE_DEV_ID_82599_KX4:  		adapter->wol = (IXGBE_WUFC_MAG | IXGBE_WUFC_EX |  		                IXGBE_WUFC_MC | IXGBE_WUFC_BC); -		/* Enable ACPI wakeup in GRC */ -		IXGBE_WRITE_REG(hw, IXGBE_GRC, -		             (IXGBE_READ_REG(hw, IXGBE_GRC) & ~IXGBE_GRC_APME));  		break;  	default:  		adapter->wol = 0; diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 2be90746659..534affcc38c 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -1298,6 +1298,7 @@  #define IXGBE_ETQF_FILTER_BCN            1  #define IXGBE_ETQF_FILTER_FCOE           2  #define IXGBE_ETQF_FILTER_1588           3 +#define IXGBE_ETQF_FILTER_FIP            4  /* VLAN Control Bit Masks */  #define IXGBE_VLNCTRL_VET       0x0000FFFF  /* bits 0-15 */  #define IXGBE_VLNCTRL_CFI       0x10000000  /* bit 28 */ @@ -2397,6 +2398,9 @@ struct ixgbe_mac_operations {  	s32 (*enable_rx_dma)(struct ixgbe_hw *, u32);  	/* Link */ +	void (*disable_tx_laser)(struct ixgbe_hw *); +	void (*enable_tx_laser)(struct ixgbe_hw *); +	void (*flap_tx_laser)(struct ixgbe_hw *);  	s32 (*setup_link)(struct ixgbe_hw *, ixgbe_link_speed, bool, bool);  	s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *, bool);  	s32 (*get_link_capabilities)(struct ixgbe_hw *, ixgbe_link_speed *, diff --git a/drivers/net/ixgbevf/ethtool.c b/drivers/net/ixgbevf/ethtool.c index 399be0c34c3..4680b069b84 100644 --- a/drivers/net/ixgbevf/ethtool.c +++ b/drivers/net/ixgbevf/ethtool.c @@ -29,6 +29,7 @@  #include <linux/types.h>  #include <linux/module.h> +#include <linux/slab.h>  #include <linux/pci.h>  #include <linux/netdevice.h>  #include <linux/ethtool.h> @@ -46,22 +47,32 @@ struct ixgbe_stats {  	int sizeof_stat;  	int stat_offset;  	int base_stat_offset; +	int saved_reset_offset;  }; -#define IXGBEVF_STAT(m, b)  sizeof(((struct ixgbevf_adapter *)0)->m), \ -			    offsetof(struct ixgbevf_adapter, m),      \ -			    offsetof(struct ixgbevf_adapter, b) +#define IXGBEVF_STAT(m, b, r)  sizeof(((struct ixgbevf_adapter *)0)->m), \ +			    offsetof(struct ixgbevf_adapter, m),         \ +			    offsetof(struct ixgbevf_adapter, b),         \ +			    offsetof(struct ixgbevf_adapter, r)  static struct ixgbe_stats ixgbe_gstrings_stats[] = { -	{"rx_packets", IXGBEVF_STAT(stats.vfgprc, stats.base_vfgprc)}, -	{"tx_packets", IXGBEVF_STAT(stats.vfgptc, stats.base_vfgptc)}, -	{"rx_bytes", IXGBEVF_STAT(stats.vfgorc, stats.base_vfgorc)}, -	{"tx_bytes", IXGBEVF_STAT(stats.vfgotc, stats.base_vfgotc)}, -	{"tx_busy", IXGBEVF_STAT(tx_busy, zero_base)}, -	{"multicast", IXGBEVF_STAT(stats.vfmprc, stats.base_vfmprc)}, -	{"rx_csum_offload_good", IXGBEVF_STAT(hw_csum_rx_good, zero_base)}, -	{"rx_csum_offload_errors", IXGBEVF_STAT(hw_csum_rx_error, zero_base)}, -	{"tx_csum_offload_ctxt", IXGBEVF_STAT(hw_csum_tx_good, zero_base)}, -	{"rx_header_split", IXGBEVF_STAT(rx_hdr_split, zero_base)}, +	{"rx_packets", IXGBEVF_STAT(stats.vfgprc, stats.base_vfgprc, +				    stats.saved_reset_vfgprc)}, +	{"tx_packets", IXGBEVF_STAT(stats.vfgptc, stats.base_vfgptc, +				    stats.saved_reset_vfgptc)}, +	{"rx_bytes", IXGBEVF_STAT(stats.vfgorc, stats.base_vfgorc, +				  stats.saved_reset_vfgorc)}, +	{"tx_bytes", IXGBEVF_STAT(stats.vfgotc, stats.base_vfgotc, +				  stats.saved_reset_vfgotc)}, +	{"tx_busy", IXGBEVF_STAT(tx_busy, zero_base, zero_base)}, +	{"multicast", IXGBEVF_STAT(stats.vfmprc, stats.base_vfmprc, +				   stats.saved_reset_vfmprc)}, +	{"rx_csum_offload_good", IXGBEVF_STAT(hw_csum_rx_good, zero_base, +					      zero_base)}, +	{"rx_csum_offload_errors", IXGBEVF_STAT(hw_csum_rx_error, zero_base, +						zero_base)}, +	{"tx_csum_offload_ctxt", IXGBEVF_STAT(hw_csum_tx_good, zero_base, +					      zero_base)}, +	{"rx_header_split", IXGBEVF_STAT(rx_hdr_split, zero_base, zero_base)},  };  #define IXGBE_QUEUE_STATS_LEN 0 @@ -455,10 +466,14 @@ static void ixgbevf_get_ethtool_stats(struct net_device *netdev,  			ixgbe_gstrings_stats[i].stat_offset;  		char *b = (char *)adapter +  			ixgbe_gstrings_stats[i].base_stat_offset; +		char *r = (char *)adapter + +			ixgbe_gstrings_stats[i].saved_reset_offset;  		data[i] = ((ixgbe_gstrings_stats[i].sizeof_stat ==  			    sizeof(u64)) ? *(u64 *)p : *(u32 *)p) -  			  ((ixgbe_gstrings_stats[i].sizeof_stat == -			    sizeof(u64)) ? *(u64 *)b : *(u32 *)b); +			    sizeof(u64)) ? *(u64 *)b : *(u32 *)b) + +			  ((ixgbe_gstrings_stats[i].sizeof_stat == +			    sizeof(u64)) ? *(u64 *)r : *(u32 *)r);  	}  } diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c index ca653c49b76..0cd6202dfac 100644 --- a/drivers/net/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ixgbevf/ixgbevf_main.c @@ -39,6 +39,7 @@  #include <linux/ip.h>  #include <linux/tcp.h>  #include <linux/ipv6.h> +#include <linux/slab.h>  #include <net/checksum.h>  #include <net/ip6_checksum.h>  #include <linux/ethtool.h> @@ -965,7 +966,7 @@ static irqreturn_t ixgbevf_msix_mbx(int irq, void *data)  	if ((msg & IXGBE_MBVFICR_VFREQ_MASK) == IXGBE_PF_CONTROL_MSG)  		mod_timer(&adapter->watchdog_timer, -			  round_jiffies(jiffies + 10)); +			  round_jiffies(jiffies + 1));  	return IRQ_HANDLED;  } @@ -1610,6 +1611,44 @@ static inline void ixgbevf_rx_desc_queue_enable(struct ixgbevf_adapter *adapter,  				(adapter->rx_ring[rxr].count - 1));  } +static void ixgbevf_save_reset_stats(struct ixgbevf_adapter *adapter) +{ +	/* Only save pre-reset stats if there are some */ +	if (adapter->stats.vfgprc || adapter->stats.vfgptc) { +		adapter->stats.saved_reset_vfgprc += adapter->stats.vfgprc - +			adapter->stats.base_vfgprc; +		adapter->stats.saved_reset_vfgptc += adapter->stats.vfgptc - +			adapter->stats.base_vfgptc; +		adapter->stats.saved_reset_vfgorc += adapter->stats.vfgorc - +			adapter->stats.base_vfgorc; +		adapter->stats.saved_reset_vfgotc += adapter->stats.vfgotc - +			adapter->stats.base_vfgotc; +		adapter->stats.saved_reset_vfmprc += adapter->stats.vfmprc - +			adapter->stats.base_vfmprc; +	} +} + +static void ixgbevf_init_last_counter_stats(struct ixgbevf_adapter *adapter) +{ +	struct ixgbe_hw *hw = &adapter->hw; + +	adapter->stats.last_vfgprc = IXGBE_READ_REG(hw, IXGBE_VFGPRC); +	adapter->stats.last_vfgorc = IXGBE_READ_REG(hw, IXGBE_VFGORC_LSB); +	adapter->stats.last_vfgorc |= +		(((u64)(IXGBE_READ_REG(hw, IXGBE_VFGORC_MSB))) << 32); +	adapter->stats.last_vfgptc = IXGBE_READ_REG(hw, IXGBE_VFGPTC); +	adapter->stats.last_vfgotc = IXGBE_READ_REG(hw, IXGBE_VFGOTC_LSB); +	adapter->stats.last_vfgotc |= +		(((u64)(IXGBE_READ_REG(hw, IXGBE_VFGOTC_MSB))) << 32); +	adapter->stats.last_vfmprc = IXGBE_READ_REG(hw, IXGBE_VFMPRC); + +	adapter->stats.base_vfgprc = adapter->stats.last_vfgprc; +	adapter->stats.base_vfgorc = adapter->stats.last_vfgorc; +	adapter->stats.base_vfgptc = adapter->stats.last_vfgptc; +	adapter->stats.base_vfgotc = adapter->stats.last_vfgotc; +	adapter->stats.base_vfmprc = adapter->stats.last_vfmprc; +} +  static int ixgbevf_up_complete(struct ixgbevf_adapter *adapter)  {  	struct net_device *netdev = adapter->netdev; @@ -1656,6 +1695,9 @@ static int ixgbevf_up_complete(struct ixgbevf_adapter *adapter)  	/* enable transmits */  	netif_tx_start_all_queues(netdev); +	ixgbevf_save_reset_stats(adapter); +	ixgbevf_init_last_counter_stats(adapter); +  	/* bring the link up in the watchdog, this could race with our first  	 * link up interrupt but shouldn't be a problem */  	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; @@ -2228,27 +2270,6 @@ out:  	return err;  } -static void ixgbevf_init_last_counter_stats(struct ixgbevf_adapter *adapter) -{ -	struct ixgbe_hw *hw = &adapter->hw; - -	adapter->stats.last_vfgprc = IXGBE_READ_REG(hw, IXGBE_VFGPRC); -	adapter->stats.last_vfgorc = IXGBE_READ_REG(hw, IXGBE_VFGORC_LSB); -	adapter->stats.last_vfgorc |= -		(((u64)(IXGBE_READ_REG(hw, IXGBE_VFGORC_MSB))) << 32); -	adapter->stats.last_vfgptc = IXGBE_READ_REG(hw, IXGBE_VFGPTC); -	adapter->stats.last_vfgotc = IXGBE_READ_REG(hw, IXGBE_VFGOTC_LSB); -	adapter->stats.last_vfgotc |= -		(((u64)(IXGBE_READ_REG(hw, IXGBE_VFGOTC_MSB))) << 32); -	adapter->stats.last_vfmprc = IXGBE_READ_REG(hw, IXGBE_VFMPRC); - -	adapter->stats.base_vfgprc = adapter->stats.last_vfgprc; -	adapter->stats.base_vfgorc = adapter->stats.last_vfgorc; -	adapter->stats.base_vfgptc = adapter->stats.last_vfgptc; -	adapter->stats.base_vfgotc = adapter->stats.last_vfgotc; -	adapter->stats.base_vfmprc = adapter->stats.last_vfmprc; -} -  #define UPDATE_VF_COUNTER_32bit(reg, last_counter, counter)	\  	{							\  		u32 current_counter = IXGBE_READ_REG(hw, reg);	\ @@ -2399,7 +2420,7 @@ static void ixgbevf_watchdog_task(struct work_struct *work)  		if (!netif_carrier_ok(netdev)) {  			hw_dbg(&adapter->hw, "NIC Link is Up %s, ",  			       ((link_speed == IXGBE_LINK_SPEED_10GB_FULL) ? -				"10 Gbps" : "1 Gbps")); +				"10 Gbps\n" : "1 Gbps\n"));  			netif_carrier_on(netdev);  			netif_tx_wake_all_queues(netdev);  		} else { @@ -2416,9 +2437,9 @@ static void ixgbevf_watchdog_task(struct work_struct *work)  		}  	} -pf_has_reset:  	ixgbevf_update_stats(adapter); +pf_has_reset:  	/* Force detection of hung controller every watchdog period */  	adapter->detect_tx_hung = true; @@ -2675,7 +2696,7 @@ static int ixgbevf_open(struct net_device *netdev)  		if (hw->adapter_stopped) {  			err = IXGBE_ERR_MBX;  			printk(KERN_ERR "Unable to start - perhaps the PF" -			       "Driver isn't up yet\n"); +			       " Driver isn't up yet\n");  			goto err_setup_reset;  		}  	} @@ -2923,9 +2944,10 @@ static int ixgbevf_tx_map(struct ixgbevf_adapter *adapter,  	struct ixgbevf_tx_buffer *tx_buffer_info;  	unsigned int len;  	unsigned int total = skb->len; -	unsigned int offset = 0, size, count = 0, i; +	unsigned int offset = 0, size, count = 0;  	unsigned int nr_frags = skb_shinfo(skb)->nr_frags;  	unsigned int f; +	int i;  	i = tx_ring->next_to_use; @@ -3390,8 +3412,6 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,  	/* setup the private structure */  	err = ixgbevf_sw_init(adapter); -	ixgbevf_init_last_counter_stats(adapter); -  #ifdef MAX_SKB_FRAGS  	netdev->features = NETIF_F_SG |  			   NETIF_F_IP_CSUM | @@ -3449,6 +3469,8 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,  	adapter->netdev_registered = true; +	ixgbevf_init_last_counter_stats(adapter); +  	/* print the MAC address */  	hw_dbg(hw, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",  	       netdev->dev_addr[0], diff --git a/drivers/net/ixgbevf/vf.h b/drivers/net/ixgbevf/vf.h index 799600e9270..1f31b052d4b 100644 --- a/drivers/net/ixgbevf/vf.h +++ b/drivers/net/ixgbevf/vf.h @@ -157,6 +157,12 @@ struct ixgbevf_hw_stats {  	u64 vfgorc;  	u64 vfgotc;  	u64 vfmprc; + +	u64 saved_reset_vfgprc; +	u64 saved_reset_vfgptc; +	u64 saved_reset_vfgorc; +	u64 saved_reset_vfgotc; +	u64 saved_reset_vfmprc;  };  struct ixgbevf_info { diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c index e9d9d595e1b..d5932ca3e27 100644 --- a/drivers/net/ixp2000/ixpdev.c +++ b/drivers/net/ixp2000/ixpdev.c @@ -15,6 +15,7 @@  #include <linux/etherdevice.h>  #include <linux/init.h>  #include <linux/moduleparam.h> +#include <linux/gfp.h>  #include <asm/hardware/uengine.h>  #include <asm/io.h>  #include "ixp2400_rx.ucode" diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index f47d4d663b1..3e6aaf9e5ce 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -22,11 +22,11 @@  #include <linux/module.h>  #include <linux/types.h>  #include <linux/fcntl.h> +#include <linux/gfp.h>  #include <linux/interrupt.h>  #include <linux/init.h>  #include <linux/ioport.h>  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/delay.h>  #include <linux/errno.h> @@ -35,6 +35,7 @@  #include <linux/skbuff.h>  #include <linux/platform_device.h>  #include <linux/dma-mapping.h> +#include <linux/slab.h>  #include <asm/bootinfo.h>  #include <asm/system.h> diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 0f31497833d..b705ad3a53a 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -37,6 +37,7 @@  #include <linux/tcp.h>  #include <linux/udp.h>  #include <linux/if_vlan.h> +#include <linux/slab.h>  #include <net/ip6_checksum.h>  #include "jme.h" @@ -946,6 +947,8 @@ jme_alloc_and_feed_skb(struct jme_adapter *jme, int idx)  				jme->jme_vlan_rx(skb, jme->vlgrp,  					le16_to_cpu(rxdesc->descwb.vlan));  				NET_STAT(jme).rx_bytes += 4; +			} else { +				dev_kfree_skb(skb);  			}  		} else {  			jme->jme_rx(skb); @@ -2081,12 +2084,45 @@ jme_tx_timeout(struct net_device *netdev)  	jme_reset_link(jme);  } +static inline void jme_pause_rx(struct jme_adapter *jme) +{ +	atomic_dec(&jme->link_changing); + +	jme_set_rx_pcc(jme, PCC_OFF); +	if (test_bit(JME_FLAG_POLL, &jme->flags)) { +		JME_NAPI_DISABLE(jme); +	} else { +		tasklet_disable(&jme->rxclean_task); +		tasklet_disable(&jme->rxempty_task); +	} +} + +static inline void jme_resume_rx(struct jme_adapter *jme) +{ +	struct dynpcc_info *dpi = &(jme->dpi); + +	if (test_bit(JME_FLAG_POLL, &jme->flags)) { +		JME_NAPI_ENABLE(jme); +	} else { +		tasklet_hi_enable(&jme->rxclean_task); +		tasklet_hi_enable(&jme->rxempty_task); +	} +	dpi->cur		= PCC_P1; +	dpi->attempt		= PCC_P1; +	dpi->cnt		= 0; +	jme_set_rx_pcc(jme, PCC_P1); + +	atomic_inc(&jme->link_changing); +} +  static void  jme_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)  {  	struct jme_adapter *jme = netdev_priv(netdev); +	jme_pause_rx(jme);  	jme->vlgrp = grp; +	jme_resume_rx(jme);  }  static void diff --git a/drivers/net/jme.h b/drivers/net/jme.h index c19db9146a2..07ad3a45718 100644 --- a/drivers/net/jme.h +++ b/drivers/net/jme.h @@ -25,7 +25,7 @@  #define __JME_H_INCLUDED__  #define DRV_NAME	"jme" -#define DRV_VERSION	"1.0.5" +#define DRV_VERSION	"1.0.6"  #define PFX		DRV_NAME ": "  #define PCI_DEVICE_ID_JMICRON_JMC250	0x0250 diff --git a/drivers/net/ks8851.c b/drivers/net/ks8851.c index 0573e0bb444..9e9f9b34976 100644 --- a/drivers/net/ks8851.c +++ b/drivers/net/ks8851.c @@ -722,12 +722,14 @@ static void ks8851_tx_work(struct work_struct *work)  		txb = skb_dequeue(&ks->txq);  		last = skb_queue_empty(&ks->txq); -		ks8851_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr | RXQCR_SDA); -		ks8851_wrpkt(ks, txb, last); -		ks8851_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr); -		ks8851_wrreg16(ks, KS_TXQCR, TXQCR_METFE); +		if (txb != NULL) { +			ks8851_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr | RXQCR_SDA); +			ks8851_wrpkt(ks, txb, last); +			ks8851_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr); +			ks8851_wrreg16(ks, KS_TXQCR, TXQCR_METFE); -		ks8851_done_tx(ks, txb); +			ks8851_done_tx(ks, txb); +		}  	}  	mutex_unlock(&ks->lock); @@ -976,7 +978,6 @@ static void ks8851_set_rx_mode(struct net_device *dev)  			crc >>= (32 - 6);  /* get top six bits */  			rxctrl.mchash[crc >> 4] |= (1 << (crc & 0xf)); -			mcptr = mcptr->next;  		}  		rxctrl.rxcr1 = RXCR1_RXME | RXCR1_RXPAFMA; diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c index 84b0e15831f..6354ab3a45a 100644 --- a/drivers/net/ks8851_mll.c +++ b/drivers/net/ks8851_mll.c @@ -31,6 +31,7 @@  #include <linux/mii.h>  #include <linux/platform_device.h>  #include <linux/delay.h> +#include <linux/slab.h>  #define	DRV_NAME	"ks8851_mll" diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c index 7264a3e5c2c..0606a1f359f 100644 --- a/drivers/net/ksz884x.c +++ b/drivers/net/ksz884x.c @@ -30,6 +30,7 @@  #include <linux/if_vlan.h>  #include <linux/crc32.h>  #include <linux/sched.h> +#include <linux/slab.h>  /* DMA Registers */ @@ -4899,8 +4900,10 @@ static int netdev_tx(struct sk_buff *skb, struct net_device *dev)  			struct sk_buff *org_skb = skb;  			skb = dev_alloc_skb(org_skb->len); -			if (!skb) -				return NETDEV_TX_BUSY; +			if (!skb) { +				rc = NETDEV_TX_BUSY; +				goto unlock; +			}  			skb_copy_and_csum_dev(org_skb, skb->data);  			org_skb->ip_summed = 0;  			skb->len = org_skb->len; @@ -4914,7 +4917,7 @@ static int netdev_tx(struct sk_buff *skb, struct net_device *dev)  		netif_stop_queue(dev);  		rc = NETDEV_TX_BUSY;  	} - +unlock:  	spin_unlock_irq(&hw_priv->hwlock);  	return rc; @@ -6320,7 +6323,7 @@ static int netdev_set_eeprom(struct net_device *dev,  	int len;  	if (eeprom->magic != EEPROM_MAGIC) -		return 1; +		return -EINVAL;  	len = (eeprom->offset + eeprom->len + 1) / 2;  	for (i = eeprom->offset / 2; i < len; i++) diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c index b77238dbafb..6eba352c52e 100644 --- a/drivers/net/lasi_82596.c +++ b/drivers/net/lasi_82596.c @@ -74,7 +74,6 @@  #include <linux/ptrace.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/delay.h>  #include <linux/netdevice.h> diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c index 443c39a3732..973390b82ec 100644 --- a/drivers/net/lib82596.c +++ b/drivers/net/lib82596.c @@ -73,7 +73,6 @@  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/delay.h>  #include <linux/netdevice.h> @@ -85,6 +84,7 @@  #include <linux/dma-mapping.h>  #include <linux/io.h>  #include <linux/irq.h> +#include <linux/gfp.h>  /* DEBUG flags   */ diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c index a18e3485476..ba617e3cf1b 100644 --- a/drivers/net/ll_temac_main.c +++ b/drivers/net/ll_temac_main.c @@ -49,6 +49,7 @@  #include <linux/in.h>  #include <linux/io.h>  #include <linux/ip.h> +#include <linux/slab.h>  #include "ll_temac.h" diff --git a/drivers/net/ll_temac_mdio.c b/drivers/net/ll_temac_mdio.c index da0e462308d..5ae28c975b3 100644 --- a/drivers/net/ll_temac_mdio.c +++ b/drivers/net/ll_temac_mdio.c @@ -10,6 +10,7 @@  #include <linux/phy.h>  #include <linux/of.h>  #include <linux/of_device.h> +#include <linux/slab.h>  #include <linux/of_mdio.h>  #include "ll_temac.h" diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c index a8768672dc5..c8e68fde066 100644 --- a/drivers/net/mac8390.c +++ b/drivers/net/mac8390.c @@ -28,7 +28,6 @@  #include <linux/ioport.h>  #include <linux/nubus.h>  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/init.h> diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index c292a608f9a..c0876e915ee 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -88,7 +88,6 @@ static char *version =  #include <linux/interrupt.h>  #include <linux/ioport.h>  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/nubus.h>  #include <linux/errno.h> @@ -98,6 +97,7 @@ static char *version =  #include <linux/skbuff.h>  #include <linux/delay.h>  #include <linux/bitops.h> +#include <linux/gfp.h>  #include <asm/system.h>  #include <asm/io.h> diff --git a/drivers/net/mace.c b/drivers/net/mace.c index ab5f0bf6d1a..962c41d0c8d 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -16,6 +16,7 @@  #include <linux/crc32.h>  #include <linux/spinlock.h>  #include <linux/bitrev.h> +#include <linux/slab.h>  #include <asm/prom.h>  #include <asm/dbdma.h>  #include <asm/io.h> diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 13ba8f4afb7..52e9a51c4c4 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -30,6 +30,7 @@  #include <linux/bitrev.h>  #include <linux/dma-mapping.h>  #include <linux/platform_device.h> +#include <linux/gfp.h>  #include <asm/io.h>  #include <asm/irq.h>  #include <asm/macintosh.h> diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index 24109c28810..adb54fe2d82 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -35,11 +35,11 @@  #include <linux/module.h>  #include <linux/types.h>  #include <linux/fcntl.h> +#include <linux/gfp.h>  #include <linux/interrupt.h>  #include <linux/init.h>  #include <linux/ioport.h>  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/delay.h>  #include <linux/nubus.h> @@ -50,6 +50,7 @@  #include <linux/platform_device.h>  #include <linux/dma-mapping.h>  #include <linux/bitrev.h> +#include <linux/slab.h>  #include <asm/bootinfo.h>  #include <asm/system.h> diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 55ceae09738..abba3cc81f1 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -9,6 +9,7 @@  #include <linux/cache.h>  #include <linux/sched.h>  #include <linux/types.h> +#include <linux/slab.h>  #include <linux/init.h>  #include <linux/wait.h>  #include <linux/cdev.h> diff --git a/drivers/net/mlx4/cmd.c b/drivers/net/mlx4/cmd.c index 65ec77dc31f..23cee7b6af9 100644 --- a/drivers/net/mlx4/cmd.c +++ b/drivers/net/mlx4/cmd.c @@ -33,6 +33,7 @@   */  #include <linux/sched.h> +#include <linux/slab.h>  #include <linux/pci.h>  #include <linux/errno.h> diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c index ccfe276943f..7cd34e9c7c7 100644 --- a/drivers/net/mlx4/cq.c +++ b/drivers/net/mlx4/cq.c @@ -35,6 +35,7 @@   */  #include <linux/hardirq.h> +#include <linux/gfp.h>  #include <linux/mlx4/cmd.h>  #include <linux/mlx4/cq.h> diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c index 507e11fce9e..cbabf14f95d 100644 --- a/drivers/net/mlx4/en_main.c +++ b/drivers/net/mlx4/en_main.c @@ -35,6 +35,7 @@  #include <linux/module.h>  #include <linux/delay.h>  #include <linux/netdevice.h> +#include <linux/slab.h>  #include <linux/mlx4/driver.h>  #include <linux/mlx4/device.h> diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index c48b0f4b17b..73c3d20c645 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -35,6 +35,7 @@  #include <linux/tcp.h>  #include <linux/if_vlan.h>  #include <linux/delay.h> +#include <linux/slab.h>  #include <linux/mlx4/driver.h>  #include <linux/mlx4/device.h> diff --git a/drivers/net/mlx4/en_resources.c b/drivers/net/mlx4/en_resources.c index 16256784a94..0dfb4ec8a9d 100644 --- a/drivers/net/mlx4/en_resources.c +++ b/drivers/net/mlx4/en_resources.c @@ -31,6 +31,7 @@   *   */ +#include <linux/slab.h>  #include <linux/vmalloc.h>  #include <linux/mlx4/qp.h> diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 64394647ddd..8e2fcb7103c 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c @@ -32,6 +32,7 @@   */  #include <linux/mlx4/cq.h> +#include <linux/slab.h>  #include <linux/mlx4/qp.h>  #include <linux/skbuff.h>  #include <linux/if_ether.h> diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index 3d1396af946..580968f304e 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c @@ -33,6 +33,7 @@  #include <asm/page.h>  #include <linux/mlx4/cq.h> +#include <linux/slab.h>  #include <linux/mlx4/qp.h>  #include <linux/skbuff.h>  #include <linux/if_vlan.h> diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index bffb7995cb7..7365bf488b8 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c @@ -32,6 +32,7 @@   */  #include <linux/interrupt.h> +#include <linux/slab.h>  #include <linux/mm.h>  #include <linux/dma-mapping.h> diff --git a/drivers/net/mlx4/icm.c b/drivers/net/mlx4/icm.c index 04b382fcb8c..57288ca1395 100644 --- a/drivers/net/mlx4/icm.c +++ b/drivers/net/mlx4/icm.c @@ -34,6 +34,7 @@  #include <linux/errno.h>  #include <linux/mm.h>  #include <linux/scatterlist.h> +#include <linux/slab.h>  #include <linux/mlx4/cmd.h> diff --git a/drivers/net/mlx4/intf.c b/drivers/net/mlx4/intf.c index 0e7eb1038f9..55506780275 100644 --- a/drivers/net/mlx4/intf.c +++ b/drivers/net/mlx4/intf.c @@ -31,6 +31,8 @@   * SOFTWARE.   */ +#include <linux/slab.h> +  #include "mlx4.h"  struct mlx4_device_context { diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 8f6e816a739..e3e0d54a7c8 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -38,6 +38,7 @@  #include <linux/errno.h>  #include <linux/pci.h>  #include <linux/dma-mapping.h> +#include <linux/slab.h>  #include <linux/mlx4/device.h>  #include <linux/mlx4/doorbell.h> @@ -1023,6 +1024,7 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port)  	info->port_attr.attr.mode = S_IRUGO | S_IWUSR;  	info->port_attr.show      = show_port_type;  	info->port_attr.store     = set_port_type; +	sysfs_attr_init(&info->port_attr.attr);  	err = device_create_file(&dev->pdev->dev, &info->port_attr);  	if (err) { diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c index 5ccbce9866f..c4f88b7ef7b 100644 --- a/drivers/net/mlx4/mcg.c +++ b/drivers/net/mlx4/mcg.c @@ -32,7 +32,6 @@   */  #include <linux/string.h> -#include <linux/slab.h>  #include <linux/mlx4/cmd.h> diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c index ca7ab8e7b4c..3dc69be4949 100644 --- a/drivers/net/mlx4/mr.c +++ b/drivers/net/mlx4/mr.c @@ -33,6 +33,7 @@   */  #include <linux/errno.h> +#include <linux/slab.h>  #include <linux/mlx4/cmd.h> diff --git a/drivers/net/mlx4/profile.c b/drivers/net/mlx4/profile.c index ca25b9dc837..5caf0115fa5 100644 --- a/drivers/net/mlx4/profile.c +++ b/drivers/net/mlx4/profile.c @@ -32,6 +32,8 @@   * SOFTWARE.   */ +#include <linux/slab.h> +  #include "mlx4.h"  #include "fw.h" diff --git a/drivers/net/mlx4/qp.c b/drivers/net/mlx4/qp.c index 42ab9fc01d3..ec9350e5f21 100644 --- a/drivers/net/mlx4/qp.c +++ b/drivers/net/mlx4/qp.c @@ -33,6 +33,7 @@   * SOFTWARE.   */ +#include <linux/gfp.h>  #include <linux/mlx4/cmd.h>  #include <linux/mlx4/qp.h> diff --git a/drivers/net/mlx4/srq.c b/drivers/net/mlx4/srq.c index 1377d0dc8f1..3b07b80a045 100644 --- a/drivers/net/mlx4/srq.c +++ b/drivers/net/mlx4/srq.c @@ -32,6 +32,7 @@   */  #include <linux/mlx4/cmd.h> +#include <linux/gfp.h>  #include "mlx4.h"  #include "icm.h" diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index c97b6e4365a..8613a52ddf1 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -54,6 +54,7 @@  #include <linux/io.h>  #include <linux/types.h>  #include <linux/inet_lro.h> +#include <linux/slab.h>  #include <asm/system.h>  static char mv643xx_eth_driver_name[] = "mv643xx_eth"; diff --git a/drivers/net/mvme147.c b/drivers/net/mvme147.c index 93c709d63e2..3a7ad840d5b 100644 --- a/drivers/net/mvme147.c +++ b/drivers/net/mvme147.c @@ -10,11 +10,11 @@  #include <linux/types.h>  #include <linux/interrupt.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/delay.h>  #include <linux/init.h>  #include <linux/errno.h> +#include <linux/gfp.h>  /* Used for the temporal inet entries and routing */  #include <linux/socket.h>  #include <linux/route.h> diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 676c513e12f..ecde0876a78 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -64,6 +64,7 @@  #include <linux/moduleparam.h>  #include <linux/io.h>  #include <linux/log2.h> +#include <linux/slab.h>  #include <net/checksum.h>  #include <net/ip.h>  #include <net/tcp.h> @@ -1689,7 +1690,7 @@ myri10ge_set_pauseparam(struct net_device *netdev,  	if (pause->tx_pause != mgp->pause)  		return myri10ge_change_pause(mgp, pause->tx_pause);  	if (pause->rx_pause != mgp->pause) -		return myri10ge_change_pause(mgp, pause->tx_pause); +		return myri10ge_change_pause(mgp, pause->rx_pause);  	if (pause->autoneg != 0)  		return -EINVAL;  	return 0; @@ -3687,7 +3688,6 @@ static void myri10ge_probe_slices(struct myri10ge_priv *mgp)  	if (status != 0) {  		dev_err(&mgp->pdev->dev, "failed reset\n");  		goto abort_with_fw; -		return;  	}  	mgp->max_intr_slots = cmd.data0 / sizeof(struct mcp_slot); diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 8b431308535..b72e749afdf 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -14,7 +14,6 @@ static char version[] =  #include <linux/interrupt.h>  #include <linux/ioport.h>  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/delay.h>  #include <linux/init.h> @@ -26,6 +25,7 @@ static char version[] =  #include <linux/of.h>  #include <linux/of_device.h>  #include <linux/firmware.h> +#include <linux/gfp.h>  #include <net/dst.h>  #include <net/arp.h> diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 992dbfffdb0..f4347f88b6f 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -142,7 +142,7 @@ bad_clone_list[] __initdata = {      {"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */      {"REALTEK", "RTL8019", {0x00, 0x00, 0xe8}}, /* no-name with Realtek chip */  #ifdef CONFIG_MACH_TX49XX -    {"RBHMA4X00-RTL8019", "RBHMA4X00/RTL8019", {0x00, 0x60, 0x0a}},  /* Toshiba built-in */ +    {"RBHMA4X00-RTL8019", "RBHMA4X00-RTL8019", {0x00, 0x60, 0x0a}},  /* Toshiba built-in */  #endif      {"LCS-8834", "LCS-8836", {0x04, 0x04, 0x37}}, /* ShinyNet (SET) */      {NULL,} diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c index a53bb201d3c..ff3c4c81498 100644 --- a/drivers/net/ne2.c +++ b/drivers/net/ne2.c @@ -66,7 +66,6 @@ static const char *version = "ne2.c:v0.91 Nov 16 1998 Wim Dumon <wimpie@kotnet.o  #include <linux/interrupt.h>  #include <linux/ioport.h>  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/init.h> diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index bf4af5248cb..a361dea3557 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -37,6 +37,7 @@  #include <linux/mm.h>  #include <linux/init.h>  #include <linux/module.h> +#include <linux/slab.h>  #include <linux/console.h>  #include <linux/moduleparam.h>  #include <linux/string.h> diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 144d2e88042..0f703838e21 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -53,8 +53,8 @@  #define _NETXEN_NIC_LINUX_MAJOR 4  #define _NETXEN_NIC_LINUX_MINOR 0 -#define _NETXEN_NIC_LINUX_SUBVERSION 72 -#define NETXEN_NIC_LINUX_VERSIONID  "4.0.72" +#define _NETXEN_NIC_LINUX_SUBVERSION 73 +#define NETXEN_NIC_LINUX_VERSIONID  "4.0.73"  #define NETXEN_VERSION_CODE(a, b, c)	(((a) << 24) + ((b) << 16) + (c))  #define _major(v)	(((v) >> 24) & 0xff) diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 2a8ef5fc966..f26e54716c8 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -669,13 +669,15 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter)  		}  		sds_ring->desc_head = (struct status_desc *)addr; -		sds_ring->crb_sts_consumer = -			netxen_get_ioaddr(adapter, -			recv_crb_registers[port].crb_sts_consumer[ring]); +		if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { +			sds_ring->crb_sts_consumer = +				netxen_get_ioaddr(adapter, +				recv_crb_registers[port].crb_sts_consumer[ring]); -		sds_ring->crb_intr_mask = -			netxen_get_ioaddr(adapter, -			recv_crb_registers[port].sw_int_mask[ring]); +			sds_ring->crb_intr_mask = +				netxen_get_ioaddr(adapter, +				recv_crb_registers[port].sw_int_mask[ring]); +		}  	} diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index a945591298a..b1cf46a0c48 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -23,6 +23,7 @@   *   */ +#include <linux/slab.h>  #include "netxen_nic.h"  #include "netxen_nic_hw.h" diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 1c63610ead4..02876f59cbb 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -25,6 +25,7 @@  #include <linux/netdevice.h>  #include <linux/delay.h> +#include <linux/slab.h>  #include "netxen_nic.h"  #include "netxen_nic_hw.h" @@ -761,7 +762,7 @@ nx_get_bios_version(struct netxen_adapter *adapter)  	if (adapter->fw_type == NX_UNIFIED_ROMIMAGE) {  		bios_ver = cpu_to_le32(*((u32 *) (&fw->data[prd_off])  						+ NX_UNI_BIOS_VERSION_OFF)); -		return (bios_ver << 24) + ((bios_ver >> 8) & 0xff00) + +		return (bios_ver << 16) + ((bios_ver >> 8) & 0xff00) +  							(bios_ver >> 24);  	} else  		return cpu_to_le32(*(u32 *)&fw->data[NX_BIOS_VERSION_OFFSET]); diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 08780ef1c1f..ce838f7c8b0 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -23,6 +23,7 @@   *   */ +#include <linux/slab.h>  #include <linux/vmalloc.h>  #include <linux/interrupt.h>  #include "netxen_nic_hw.h" @@ -604,16 +605,14 @@ netxen_cleanup_pci_map(struct netxen_adapter *adapter)  static int  netxen_setup_pci_map(struct netxen_adapter *adapter)  { -	void __iomem *mem_ptr0 = NULL; -	void __iomem *mem_ptr1 = NULL; -	void __iomem *mem_ptr2 = NULL;  	void __iomem *db_ptr = NULL;  	resource_size_t mem_base, db_base; -	unsigned long mem_len, db_len = 0, pci_len0 = 0; +	unsigned long mem_len, db_len = 0;  	struct pci_dev *pdev = adapter->pdev;  	int pci_func = adapter->ahw.pci_func; +	struct netxen_hardware_context *ahw = &adapter->ahw;  	int err = 0; @@ -630,24 +629,40 @@ netxen_setup_pci_map(struct netxen_adapter *adapter)  	/* 128 Meg of memory */  	if (mem_len == NETXEN_PCI_128MB_SIZE) { -		mem_ptr0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE); -		mem_ptr1 = ioremap(mem_base + SECOND_PAGE_GROUP_START, + +		ahw->pci_base0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE); +		ahw->pci_base1 = ioremap(mem_base + SECOND_PAGE_GROUP_START,  				SECOND_PAGE_GROUP_SIZE); -		mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START, +		ahw->pci_base2 = ioremap(mem_base + THIRD_PAGE_GROUP_START,  				THIRD_PAGE_GROUP_SIZE); -		pci_len0 = FIRST_PAGE_GROUP_SIZE; +		if (ahw->pci_base0 == NULL || ahw->pci_base1 == NULL || +						ahw->pci_base2 == NULL) { +			dev_err(&pdev->dev, "failed to map PCI bar 0\n"); +			err = -EIO; +			goto err_out; +		} + +		ahw->pci_len0 = FIRST_PAGE_GROUP_SIZE; +  	} else if (mem_len == NETXEN_PCI_32MB_SIZE) { -		mem_ptr1 = ioremap(mem_base, SECOND_PAGE_GROUP_SIZE); -		mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START - + +		ahw->pci_base1 = ioremap(mem_base, SECOND_PAGE_GROUP_SIZE); +		ahw->pci_base2 = ioremap(mem_base + THIRD_PAGE_GROUP_START -  			SECOND_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE); +		if (ahw->pci_base1 == NULL || ahw->pci_base2 == NULL) { +			dev_err(&pdev->dev, "failed to map PCI bar 0\n"); +			err = -EIO; +			goto err_out; +		} +  	} else if (mem_len == NETXEN_PCI_2MB_SIZE) { -		mem_ptr0 = pci_ioremap_bar(pdev, 0); -		if (mem_ptr0 == NULL) { +		ahw->pci_base0 = pci_ioremap_bar(pdev, 0); +		if (ahw->pci_base0 == NULL) {  			dev_err(&pdev->dev, "failed to map PCI bar 0\n");  			return -EIO;  		} -		pci_len0 = mem_len; +		ahw->pci_len0 = mem_len;  	} else {  		return -EIO;  	} @@ -656,11 +671,6 @@ netxen_setup_pci_map(struct netxen_adapter *adapter)  	dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20)); -	adapter->ahw.pci_base0 = mem_ptr0; -	adapter->ahw.pci_len0 = pci_len0; -	adapter->ahw.pci_base1 = mem_ptr1; -	adapter->ahw.pci_base2 = mem_ptr2; -  	if (NX_IS_REVISION_P3P(adapter->ahw.revision_id)) {  		adapter->ahw.ocm_win_crb = netxen_get_ioaddr(adapter,  			NETXEN_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(pci_func))); @@ -1246,8 +1256,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	int pci_func_id = PCI_FUNC(pdev->devfn);  	uint8_t revision_id; -	if (pdev->revision >= NX_P3_A0 && pdev->revision < NX_P3_B1) { -		pr_warning("%s: chip revisions between 0x%x-0x%x" +	if (pdev->revision >= NX_P3_A0 && pdev->revision <= NX_P3_B1) { +		pr_warning("%s: chip revisions between 0x%x-0x%x "  				"will not be enabled.\n",  				module_name(THIS_MODULE), NX_P3_A0, NX_P3_B1);  		return -ENODEV; diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c index c16cbfb4061..3892330f244 100644 --- a/drivers/net/ni5010.c +++ b/drivers/net/ni5010.c @@ -51,7 +51,6 @@  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/delay.h>  #include <linux/init.h> diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index 05c29c2cef2..f7a8f707361 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -109,7 +109,6 @@ static int fifo = 0x8;	/* don't change */  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/delay.h>  #include <linux/init.h> diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 0678f3106cb..d5cd16bfc90 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -25,6 +25,7 @@  #include <linux/jiffies.h>  #include <linux/crc32.h>  #include <linux/list.h> +#include <linux/slab.h>  #include <linux/io.h> diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index 8dd509c09bc..e88e97cd1b1 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -116,6 +116,7 @@  #include <linux/if_vlan.h>  #include <linux/rtnetlink.h>  #include <linux/jiffies.h> +#include <linux/slab.h>  #include <asm/io.h>  #include <asm/uaccess.h> diff --git a/drivers/net/octeon/octeon_mgmt.c b/drivers/net/octeon/octeon_mgmt.c index be368e5cbf7..8aadc8e2ddd 100644 --- a/drivers/net/octeon/octeon_mgmt.c +++ b/drivers/net/octeon/octeon_mgmt.c @@ -13,6 +13,7 @@  #include <linux/netdevice.h>  #include <linux/etherdevice.h>  #include <linux/if_vlan.h> +#include <linux/slab.h>  #include <linux/phy.h>  #include <linux/spinlock.h> diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index d44d4a208bb..370c147d08a 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -20,6 +20,7 @@  #include <linux/init.h>  #include <linux/module.h>  #include <linux/pci.h> +#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/dmaengine.h>  #include <linux/delay.h> diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 3d1d3a7b7ed..757f87bb1db 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -781,8 +781,13 @@ static netdev_tx_t el3_start_xmit(struct sk_buff *skb,  		  inw(ioaddr + EL3_STATUS));  	spin_lock_irqsave(&lp->window_lock, flags); + +	dev->stats.tx_bytes += skb->len; + +	/* Put out the doubleword header... */  	outw(skb->len, ioaddr + TX_FIFO);  	outw(0, ioaddr + TX_FIFO); +	/* ... and the packet rounded to a doubleword. */  	outsl(ioaddr + TX_FIFO, skb->data, (skb->len+3)>>2);  	dev->trans_start = jiffies; @@ -1021,8 +1026,6 @@ static void update_stats(struct net_device *dev)  	/* BadSSD */				   inb(ioaddr + 12);  	up					 = inb(ioaddr + 13); -	dev->stats.tx_bytes 			+= tx + ((up & 0xf0) << 12); -  	EL3WINDOW(1);  } diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 09291e60d30..9f3d593f14e 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -28,7 +28,6 @@  #include <linux/module.h>  #include <linux/init.h>  #include <linux/ptrace.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/timer.h>  #include <linux/delay.h> diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 776cad2f571..4c0368de181 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -32,7 +32,6 @@  #include <linux/module.h>  #include <linux/init.h>  #include <linux/ptrace.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/timer.h>  #include <linux/delay.h> @@ -1549,6 +1548,7 @@ static struct pcmcia_device_id pcnet_ids[] = {  	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x021b, 0x0101),  	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x08a1, 0xc0ab),  	PCMCIA_PFC_DEVICE_PROD_ID12(0, "AnyCom", "Fast Ethernet + 56K COMBO", 0x578ba6e7, 0xb0ac62c4), +	PCMCIA_PFC_DEVICE_PROD_ID12(0, "ATKK", "LM33-PCM-T", 0xba9eb7e2, 0x077c174e),  	PCMCIA_PFC_DEVICE_PROD_ID12(0, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff),  	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae),  	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033), @@ -1740,7 +1740,7 @@ static struct pcmcia_device_id pcnet_ids[] = {  	PCMCIA_MFC_DEVICE_CIS_PROD_ID12(0, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "cis/DP83903.cis"),  	PCMCIA_MFC_DEVICE_CIS_PROD_ID4(0, "NSC MF LAN/Modem", 0x58fc6056, "cis/DP83903.cis"),  	PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0175, 0x0000, "cis/DP83903.cis"), -	PCMCIA_DEVICE_CIS_MANF_CARD(0xc00f, 0x0002, "cis/LA-PCM.cis"), +	PCMCIA_DEVICE_CIS_PROD_ID12("Allied Telesis,K.K", "Ethernet LAN Card", 0x2ad62f3c, 0x9fd2f0a2, "cis/LA-PCM.cis"),  	PCMCIA_DEVICE_CIS_PROD_ID12("KTI", "PE520 PLUS", 0xad180345, 0x9d58d392, "cis/PE520.cis"),  	PCMCIA_DEVICE_CIS_PROD_ID12("NDC", "Ethernet", 0x01c43ae1, 0x00b2e941, "cis/NE2K.cis"),  	PCMCIA_DEVICE_CIS_PROD_ID12("PMX   ", "PE-200", 0x34f3f1c8, 0x10b59f8c, "cis/PE-200.cis"), diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 5adc662c4bf..ccc553782a0 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -493,13 +493,14 @@ static int pcmcia_get_versmac(struct pcmcia_device *p_dev,  {  	struct net_device *dev = priv;  	cisparse_t parse; +	u8 *buf;  	if (pcmcia_parse_tuple(tuple, &parse))  		return -EINVAL; -	if ((parse.version_1.ns > 3) && -	    (cvt_ascii_address(dev, -			       (parse.version_1.str + parse.version_1.ofs[3])))) +	buf = parse.version_1.str + parse.version_1.ofs[3]; + +	if ((parse.version_1.ns > 3) && (cvt_ascii_address(dev, buf) == 0))  		return 0;  	return -EINVAL; @@ -528,7 +529,7 @@ static int mhz_setup(struct pcmcia_device *link)      len = pcmcia_get_tuple(link, 0x81, &buf);      if (buf && len >= 13) {  	    buf[12] = '\0'; -	    if (cvt_ascii_address(dev, buf)) +	    if (cvt_ascii_address(dev, buf) == 0)  		    rc = 0;      }      kfree(buf); @@ -910,7 +911,7 @@ static int smc91c92_config(struct pcmcia_device *link)      if (i != 0) {  	printk(KERN_NOTICE "smc91c92_cs: Unable to find hardware address.\n"); -	goto config_undo; +	goto config_failed;      }      smc->duplex = 0; @@ -998,6 +999,7 @@ config_undo:      unregister_netdev(dev);  config_failed:      smc91c92_release(link); +    free_netdev(dev);      return -ENODEV;  } /* smc91c92_config */ @@ -1606,9 +1608,12 @@ static void set_rx_mode(struct net_device *dev)  {      unsigned int ioaddr = dev->base_addr;      struct smc_private *smc = netdev_priv(dev); -    u_int multicast_table[ 2 ] = { 0, }; +    unsigned char multicast_table[8];      unsigned long flags;      u_short rx_cfg_setting; +    int i; + +    memset(multicast_table, 0, sizeof(multicast_table));      if (dev->flags & IFF_PROMISC) {  	rx_cfg_setting = RxStripCRC | RxEnable | RxPromisc | RxAllMulti; @@ -1620,10 +1625,6 @@ static void set_rx_mode(struct net_device *dev)  	    netdev_for_each_mc_addr(mc_addr, dev) {  		u_int position = ether_crc(6, mc_addr->dmi_addr); -#ifndef final_version		/* Verify multicast address. */ -		if ((mc_addr->dmi_addr[0] & 1) == 0) -		    continue; -#endif  		multicast_table[position >> 29] |= 1 << ((position >> 26) & 7);  	    }  	} @@ -1633,8 +1634,8 @@ static void set_rx_mode(struct net_device *dev)      /* Load MC table and Rx setting into the chip without interrupts. */      spin_lock_irqsave(&smc->lock, flags);      SMC_SELECT_BANK(3); -    outl(multicast_table[0], ioaddr + MULTICAST0); -    outl(multicast_table[1], ioaddr + MULTICAST4); +    for (i = 0; i < 8; i++) +	outb(multicast_table[i], ioaddr + MULTICAST0 + i);      SMC_SELECT_BANK(0);      outw(rx_cfg_setting, ioaddr + RCR);      SMC_SELECT_BANK(2); @@ -1803,23 +1804,30 @@ static void media_check(u_long arg)      SMC_SELECT_BANK(1);      media |= (inw(ioaddr + CONFIG) & CFG_AUI_SELECT) ? 2 : 1; +    SMC_SELECT_BANK(saved_bank); +    spin_unlock_irqrestore(&smc->lock, flags); +      /* Check for pending interrupt with watchdog flag set: with         this, we can limp along even if the interrupt is blocked */      if (smc->watchdog++ && ((i>>8) & i)) {  	if (!smc->fast_poll)  	    printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name); +	local_irq_save(flags);  	smc_interrupt(dev->irq, dev); +	local_irq_restore(flags);  	smc->fast_poll = HZ;      }      if (smc->fast_poll) {  	smc->fast_poll--;  	smc->media.expires = jiffies + HZ/100;  	add_timer(&smc->media); -	SMC_SELECT_BANK(saved_bank); -	spin_unlock_irqrestore(&smc->lock, flags);  	return;      } +    spin_lock_irqsave(&smc->lock, flags); + +    saved_bank = inw(ioaddr + BANK_SELECT); +      if (smc->cfg & CFG_MII_SELECT) {  	if (smc->mii_if.phy_id < 0)  	    goto reschedule; @@ -1977,15 +1985,16 @@ static int smc_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)  	unsigned int ioaddr = dev->base_addr;  	u16 saved_bank = inw(ioaddr + BANK_SELECT);  	int ret; +	unsigned long flags; -	spin_lock_irq(&smc->lock); +	spin_lock_irqsave(&smc->lock, flags);  	SMC_SELECT_BANK(3);  	if (smc->cfg & CFG_MII_SELECT)  		ret = mii_ethtool_gset(&smc->mii_if, ecmd);  	else  		ret = smc_netdev_get_ecmd(dev, ecmd);  	SMC_SELECT_BANK(saved_bank); -	spin_unlock_irq(&smc->lock); +	spin_unlock_irqrestore(&smc->lock, flags);  	return ret;  } @@ -1995,15 +2004,16 @@ static int smc_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)  	unsigned int ioaddr = dev->base_addr;  	u16 saved_bank = inw(ioaddr + BANK_SELECT);  	int ret; +	unsigned long flags; -	spin_lock_irq(&smc->lock); +	spin_lock_irqsave(&smc->lock, flags);  	SMC_SELECT_BANK(3);  	if (smc->cfg & CFG_MII_SELECT)  		ret = mii_ethtool_sset(&smc->mii_if, ecmd);  	else  		ret = smc_netdev_set_ecmd(dev, ecmd);  	SMC_SELECT_BANK(saved_bank); -	spin_unlock_irq(&smc->lock); +	spin_unlock_irqrestore(&smc->lock, flags);  	return ret;  } @@ -2013,12 +2023,13 @@ static u32 smc_get_link(struct net_device *dev)  	unsigned int ioaddr = dev->base_addr;  	u16 saved_bank = inw(ioaddr + BANK_SELECT);  	u32 ret; +	unsigned long flags; -	spin_lock_irq(&smc->lock); +	spin_lock_irqsave(&smc->lock, flags);  	SMC_SELECT_BANK(3);  	ret = smc_link_ok(dev);  	SMC_SELECT_BANK(saved_bank); -	spin_unlock_irq(&smc->lock); +	spin_unlock_irqrestore(&smc->lock, flags);  	return ret;  } @@ -2055,16 +2066,17 @@ static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)  	int rc = 0;  	u16 saved_bank;  	unsigned int ioaddr = dev->base_addr; +	unsigned long flags;  	if (!netif_running(dev))  		return -EINVAL; -	spin_lock_irq(&smc->lock); +	spin_lock_irqsave(&smc->lock, flags);  	saved_bank = inw(ioaddr + BANK_SELECT);  	SMC_SELECT_BANK(3);  	rc = generic_mii_ioctl(&smc->mii_if, mii, cmd, NULL);  	SMC_SELECT_BANK(saved_bank); -	spin_unlock_irq(&smc->lock); +	spin_unlock_irqrestore(&smc->lock, flags);  	return rc;  } diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index fc5938ba3d7..a527e37728c 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -88,6 +88,11 @@ config LSI_ET1011C_PHY  	---help---  	  Supports the LSI ET1011C PHY. +config MICREL_PHY +	tristate "Driver for Micrel PHYs" +	---help--- +	  Supports the KSZ9021, VSC8201, KS8001 PHYs. +  config FIXED_PHY  	bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"  	depends on PHYLIB=y diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 1342585af38..13bebab65d0 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -20,4 +20,5 @@ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o  obj-$(CONFIG_MDIO_GPIO)		+= mdio-gpio.o  obj-$(CONFIG_NATIONAL_PHY)	+= national.o  obj-$(CONFIG_STE10XP)		+= ste10Xp.o +obj-$(CONFIG_MICREL_PHY)	+= micrel.o  obj-$(CONFIG_MDIO_OCTEON)	+= mdio-octeon.o diff --git a/drivers/net/phy/cicada.c b/drivers/net/phy/cicada.c index a1bd599c8a5..92282b31d94 100644 --- a/drivers/net/phy/cicada.c +++ b/drivers/net/phy/cicada.c @@ -17,7 +17,6 @@  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/unistd.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/init.h>  #include <linux/delay.h> diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c index d926168bc78..c722e95853f 100644 --- a/drivers/net/phy/davicom.c +++ b/drivers/net/phy/davicom.c @@ -17,7 +17,6 @@  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/unistd.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/init.h>  #include <linux/delay.h> diff --git a/drivers/net/phy/et1011c.c b/drivers/net/phy/et1011c.c index b031fa21f1a..7712ebeba9b 100644 --- a/drivers/net/phy/et1011c.c +++ b/drivers/net/phy/et1011c.c @@ -17,7 +17,6 @@  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/unistd.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/init.h>  #include <linux/delay.h> diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c index e7070515d2e..1fa4d73c3cc 100644 --- a/drivers/net/phy/fixed.c +++ b/drivers/net/phy/fixed.c @@ -20,6 +20,7 @@  #include <linux/phy.h>  #include <linux/phy_fixed.h>  #include <linux/err.h> +#include <linux/slab.h>  #define MII_REGS_NUM 29 diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c index af3f1f2a9f8..904208b95d4 100644 --- a/drivers/net/phy/icplus.c +++ b/drivers/net/phy/icplus.c @@ -13,7 +13,6 @@  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/unistd.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/init.h>  #include <linux/delay.h> diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c index 4cf3324ba16..057ecaacde6 100644 --- a/drivers/net/phy/lxt.c +++ b/drivers/net/phy/lxt.c @@ -17,7 +17,6 @@  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/unistd.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/init.h>  #include <linux/delay.h> diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 65ed385c2ce..64c7fbe0a8e 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -17,7 +17,6 @@  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/unistd.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/init.h>  #include <linux/delay.h> diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c index 2576055b350..19e70d7e27a 100644 --- a/drivers/net/phy/mdio-bitbang.c +++ b/drivers/net/phy/mdio-bitbang.c @@ -19,7 +19,6 @@  #include <linux/module.h>  #include <linux/mdio-bitbang.h> -#include <linux/slab.h>  #include <linux/types.h>  #include <linux/delay.h> diff --git a/drivers/net/phy/mdio-octeon.c b/drivers/net/phy/mdio-octeon.c index 61a4461cbda..f443d43edd8 100644 --- a/drivers/net/phy/mdio-octeon.c +++ b/drivers/net/phy/mdio-octeon.c @@ -6,6 +6,7 @@   * Copyright (C) 2009 Cavium Networks   */ +#include <linux/gfp.h>  #include <linux/init.h>  #include <linux/module.h>  #include <linux/platform_device.h> @@ -87,6 +88,7 @@ static int octeon_mdiobus_write(struct mii_bus *bus, int phy_id,  static int __init octeon_mdiobus_probe(struct platform_device *pdev)  {  	struct octeon_mdiobus *bus; +	union cvmx_smix_en smi_en;  	int i;  	int err = -ENOENT; @@ -102,6 +104,10 @@ static int __init octeon_mdiobus_probe(struct platform_device *pdev)  	if (!bus->mii_bus)  		goto err; +	smi_en.u64 = 0; +	smi_en.s.en = 1; +	cvmx_write_csr(CVMX_SMIX_EN(bus->unit), smi_en.u64); +  	/*  	 * Standard Octeon evaluation boards don't support phy  	 * interrupts, we need to poll. @@ -132,17 +138,22 @@ err_register:  err:  	devm_kfree(&pdev->dev, bus); +	smi_en.u64 = 0; +	cvmx_write_csr(CVMX_SMIX_EN(bus->unit), smi_en.u64);  	return err;  }  static int __exit octeon_mdiobus_remove(struct platform_device *pdev)  {  	struct octeon_mdiobus *bus; +	union cvmx_smix_en smi_en;  	bus = dev_get_drvdata(&pdev->dev);  	mdiobus_unregister(bus->mii_bus);  	mdiobus_free(bus->mii_bus); +	smi_en.u64 = 0; +	cvmx_write_csr(CVMX_SMIX_EN(bus->unit), smi_en.u64);  	return 0;  } diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c new file mode 100644 index 00000000000..0cd80e4d71d --- /dev/null +++ b/drivers/net/phy/micrel.c @@ -0,0 +1,104 @@ +/* + * drivers/net/phy/micrel.c + * + * Driver for Micrel PHYs + * + * Author: David J. Choi + * + * Copyright (c) 2010 Micrel, Inc. + * + * 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. + * + * Support : ksz9021 , vsc8201, ks8001 + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/phy.h> + +#define	PHY_ID_KSZ9021			0x00221611 +#define	PHY_ID_VSC8201			0x000FC413 +#define	PHY_ID_KS8001			0x0022161A + + +static int kszphy_config_init(struct phy_device *phydev) +{ +	return 0; +} + + +static struct phy_driver ks8001_driver = { +	.phy_id		= PHY_ID_KS8001, +	.phy_id_mask	= 0x00fffff0, +	.features	= PHY_BASIC_FEATURES, +	.flags		= PHY_POLL, +	.config_init	= kszphy_config_init, +	.config_aneg	= genphy_config_aneg, +	.read_status	= genphy_read_status, +	.driver		= { .owner = THIS_MODULE,}, +}; + +static struct phy_driver vsc8201_driver = { +	.phy_id		= PHY_ID_VSC8201, +	.name		= "Micrel VSC8201", +	.phy_id_mask	= 0x00fffff0, +	.features	= PHY_BASIC_FEATURES, +	.flags		= PHY_POLL, +	.config_init	= kszphy_config_init, +	.config_aneg	= genphy_config_aneg, +	.read_status	= genphy_read_status, +	.driver		= { .owner = THIS_MODULE,}, +}; + +static struct phy_driver ksz9021_driver = { +	.phy_id		= PHY_ID_KSZ9021, +	.phy_id_mask	= 0x000fff10, +	.name		= "Micrel KSZ9021 Gigabit PHY", +	.features	= PHY_GBIT_FEATURES | SUPPORTED_Pause, +	.flags		= PHY_POLL, +	.config_init	= kszphy_config_init, +	.config_aneg	= genphy_config_aneg, +	.read_status	= genphy_read_status, +	.driver		= { .owner = THIS_MODULE, }, +}; + +static int __init ksphy_init(void) +{ +	int ret; + +	ret = phy_driver_register(&ks8001_driver); +	if (ret) +		goto err1; +	ret = phy_driver_register(&vsc8201_driver); +	if (ret) +		goto err2; + +	ret = phy_driver_register(&ksz9021_driver); +	if (ret) +		goto err3; +	return 0; + +err3: +	phy_driver_unregister(&vsc8201_driver); +err2: +	phy_driver_unregister(&ks8001_driver); +err1: +	return ret; +} + +static void __exit ksphy_exit(void) +{ +	phy_driver_unregister(&ks8001_driver); +	phy_driver_unregister(&vsc8201_driver); +	phy_driver_unregister(&ksz9021_driver); +} + +module_init(ksphy_init); +module_exit(ksphy_exit); + +MODULE_DESCRIPTION("Micrel PHY driver"); +MODULE_AUTHOR("David J. Choi"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 0295097d6c4..64be4664cca 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -19,7 +19,6 @@  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/unistd.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/init.h>  #include <linux/delay.h> diff --git a/drivers/net/phy/qsemi.c b/drivers/net/phy/qsemi.c index 23062d06723..f6e190f73c3 100644 --- a/drivers/net/phy/qsemi.c +++ b/drivers/net/phy/qsemi.c @@ -17,7 +17,6 @@  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/unistd.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/init.h>  #include <linux/delay.h> diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 3327e9fc7b5..9a2103a69e1 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -94,6 +94,7 @@ static const char version[] = "NET3 PLIP version 2.4-parport gniibe@mri.co.jp\n"  #include <linux/fcntl.h>  #include <linux/interrupt.h>  #include <linux/string.h> +#include <linux/slab.h>  #include <linux/if_ether.h>  #include <linux/in.h>  #include <linux/errno.h> diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c index 6a375ea4947..6c2e8fa0ca3 100644 --- a/drivers/net/ppp_async.c +++ b/drivers/net/ppp_async.c @@ -31,6 +31,7 @@  #include <linux/spinlock.h>  #include <linux/init.h>  #include <linux/jiffies.h> +#include <linux/slab.h>  #include <asm/uaccess.h>  #include <asm/string.h> diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 6d61602208c..8518a2e58e5 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -46,6 +46,7 @@  #include <linux/stddef.h>  #include <linux/device.h>  #include <linux/mutex.h> +#include <linux/slab.h>  #include <net/slhc_vj.h>  #include <asm/atomic.h> @@ -404,6 +405,7 @@ static ssize_t ppp_read(struct file *file, char __user *buf,  	DECLARE_WAITQUEUE(wait, current);  	ssize_t ret;  	struct sk_buff *skb = NULL; +	struct iovec iov;  	ret = count; @@ -447,7 +449,9 @@ static ssize_t ppp_read(struct file *file, char __user *buf,  	if (skb->len > count)  		goto outf;  	ret = -EFAULT; -	if (copy_to_user(buf, skb->data, skb->len)) +	iov.iov_base = buf; +	iov.iov_len = count; +	if (skb_copy_datagram_iovec(skb, 0, &iov, skb->len))  		goto outf;  	ret = skb->len; @@ -1566,13 +1570,22 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb)  	struct channel *pch = chan->ppp;  	int proto; -	if (!pch || skb->len == 0) { +	if (!pch) {  		kfree_skb(skb);  		return;  	} -	proto = PPP_PROTO(skb);  	read_lock_bh(&pch->upl); +	if (!pskb_may_pull(skb, 2)) { +		kfree_skb(skb); +		if (pch->ppp) { +			++pch->ppp->dev->stats.rx_length_errors; +			ppp_receive_error(pch->ppp); +		} +		goto done; +	} + +	proto = PPP_PROTO(skb);  	if (!pch->ppp || proto >= 0xc000 || proto == PPP_CCPFRAG) {  		/* put it on the channel queue */  		skb_queue_tail(&pch->file.rq, skb); @@ -1584,6 +1597,8 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb)  	} else {  		ppp_do_recv(pch->ppp, skb, pch);  	} + +done:  	read_unlock_bh(&pch->upl);  } @@ -1616,7 +1631,8 @@ ppp_input_error(struct ppp_channel *chan, int code)  static void  ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)  { -	if (pskb_may_pull(skb, 2)) { +	/* note: a 0-length skb is used as an error indication */ +	if (skb->len > 0) {  #ifdef CONFIG_PPP_MULTILINK  		/* XXX do channel-level decompression here */  		if (PPP_PROTO(skb) == PPP_MP) @@ -1624,15 +1640,10 @@ ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)  		else  #endif /* CONFIG_PPP_MULTILINK */  			ppp_receive_nonmp_frame(ppp, skb); -		return; +	} else { +		kfree_skb(skb); +		ppp_receive_error(ppp);  	} - -	if (skb->len > 0) -		/* note: a 0-length skb is used as an error indication */ -		++ppp->dev->stats.rx_length_errors; - -	kfree_skb(skb); -	ppp_receive_error(ppp);  }  static void diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c index 3a13cecae3e..52938da1e54 100644 --- a/drivers/net/ppp_synctty.c +++ b/drivers/net/ppp_synctty.c @@ -44,6 +44,7 @@  #include <linux/spinlock.h>  #include <linux/completion.h>  #include <linux/init.h> +#include <linux/slab.h>  #include <asm/uaccess.h>  #define PPP_VERSION	"2.4.2" diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index 9fbb2eba9a0..449a9825200 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -756,6 +756,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)  	/* Try to dequeue as many skbs from reorder_q as we can. */  	pppol2tp_recv_dequeue(session); +	sock_put(sock);  	return 0; @@ -772,6 +773,7 @@ discard_bad_csum:  	UDP_INC_STATS_USER(&init_net, UDP_MIB_INERRORS, 0);  	tunnel->stats.rx_errors++;  	kfree_skb(skb); +	sock_put(sock);  	return 0; @@ -1180,7 +1182,8 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)  	/* Calculate UDP checksum if configured to do so */  	if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT)  		skb->ip_summed = CHECKSUM_NONE; -	else if (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM)) { +	else if ((skb_dst(skb) && skb_dst(skb)->dev) && +		 (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM))) {  		skb->ip_summed = CHECKSUM_COMPLETE;  		csum = skb_checksum(skb, 0, udp_len, 0);  		uh->check = csum_tcpudp_magic(inet->inet_saddr, @@ -1661,6 +1664,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,  		if (tunnel_sock == NULL)  			goto end; +		sock_hold(tunnel_sock);  		tunnel = tunnel_sock->sk_user_data;  	} else {  		tunnel = pppol2tp_tunnel_find(sock_net(sk), sp->pppol2tp.s_tunnel); diff --git a/drivers/net/pppox.c b/drivers/net/pppox.c index ac806b27c65..d4191ef9cad 100644 --- a/drivers/net/pppox.c +++ b/drivers/net/pppox.c @@ -22,7 +22,6 @@  #include <linux/string.h>  #include <linux/module.h>  #include <linux/kernel.h> -#include <linux/slab.h>  #include <linux/errno.h>  #include <linux/netdevice.h>  #include <linux/net.h> diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index a849f6f23a1..5bf229bb34c 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -30,6 +30,7 @@  #include <linux/kernel.h>  #include <linux/module.h> +#include <linux/slab.h>  #include <linux/etherdevice.h>  #include <linux/ethtool.h> diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index 2663b2fdc0b..f0be507e532 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -21,6 +21,7 @@  #include <linux/kernel.h>  #include <linux/module.h> +#include <linux/slab.h>  #include <linux/etherdevice.h>  #include <linux/ethtool.h> diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c index da00e162b6d..e73ba455aa2 100644 --- a/drivers/net/qlcnic/qlcnic_hw.c +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -24,6 +24,7 @@  #include "qlcnic.h" +#include <linux/slab.h>  #include <net/ip.h>  #define MASK(n) ((1ULL<<(n))-1) @@ -430,6 +431,9 @@ void qlcnic_set_multi(struct net_device *netdev)  	u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };  	u32 mode = VPORT_MISS_MODE_DROP; +	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) +		return; +  	qlcnic_nic_add_mac(adapter, adapter->mac_addr);  	qlcnic_nic_add_mac(adapter, bcast_addr); diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index 7c34e4e29b3..9d2c124048f 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -24,6 +24,7 @@  #include <linux/netdevice.h>  #include <linux/delay.h> +#include <linux/slab.h>  #include "qlcnic.h"  struct crb_addr_pair { diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index fc721564e69..234dab1f998 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -22,6 +22,7 @@   *   */ +#include <linux/slab.h>  #include <linux/vmalloc.h>  #include <linux/interrupt.h> diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c index ff8550d2ca8..36266462893 100644 --- a/drivers/net/qlge/qlge_dbg.c +++ b/drivers/net/qlge/qlge_dbg.c @@ -1,3 +1,5 @@ +#include <linux/slab.h> +  #include "qlge.h"  /* Read a NIC register from the alternate function. */ diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c index 7dbff87480d..7e09ff4a575 100644 --- a/drivers/net/qlge/qlge_ethtool.c +++ b/drivers/net/qlge/qlge_ethtool.c @@ -7,7 +7,6 @@  #include <linux/dma-mapping.h>  #include <linux/pagemap.h>  #include <linux/sched.h> -#include <linux/slab.h>  #include <linux/dmapool.h>  #include <linux/mempool.h>  #include <linux/spinlock.h> diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 15d5373dc8f..0298d8c1dcb 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -29,7 +29,6 @@  #include <linux/timer.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/pci.h>  #include <linux/netdevice.h> @@ -135,7 +134,7 @@  #define RX_DESC_SIZE	(RX_DCNT * sizeof(struct r6040_descriptor))  #define TX_DESC_SIZE	(TX_DCNT * sizeof(struct r6040_descriptor))  #define MBCR_DEFAULT	0x012A	/* MAC Bus Control Register */ -#define MCAST_MAX	4	/* Max number multicast addresses to filter */ +#define MCAST_MAX	3	/* Max number multicast addresses to filter */  /* Descriptor status */  #define DSC_OWNER_MAC	0x8000	/* MAC is the owner of this descriptor */ @@ -983,9 +982,6 @@ static void r6040_multicast_list(struct net_device *dev)  			crc >>= 26;  			hash_table[crc >> 4] |= 1 << (15 - (crc & 0xf));  		} -		/* Write the index of the hash table */ -		for (i = 0; i < 4; i++) -			iowrite16(hash_table[i] << 14, ioaddr + MCR1);  		/* Fill the MAC hash tables with their values */  		iowrite16(hash_table[0], ioaddr + MAR0);  		iowrite16(hash_table[1], ioaddr + MAR1); @@ -1001,9 +997,9 @@ static void r6040_multicast_list(struct net_device *dev)  			iowrite16(adrp[1], ioaddr + MID_1M + 8 * i);  			iowrite16(adrp[2], ioaddr + MID_1H + 8 * i);  		} else { -			iowrite16(0xffff, ioaddr + MID_0L + 8 * i); -			iowrite16(0xffff, ioaddr + MID_0M + 8 * i); -			iowrite16(0xffff, ioaddr + MID_0H + 8 * i); +			iowrite16(0xffff, ioaddr + MID_1L + 8 * i); +			iowrite16(0xffff, ioaddr + MID_1M + 8 * i); +			iowrite16(0xffff, ioaddr + MID_1H + 8 * i);  		}  		i++;  	} diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 9d3ebf3e975..dd8106ff35a 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -186,8 +186,13 @@ static DEFINE_PCI_DEVICE_TABLE(rtl8169_pci_tbl) = {  MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl); -static int rx_copybreak = 200; -static int use_dac = -1; +/* + * we set our copybreak very high so that we don't have + * to allocate 16k frames all the time (see note in + * rtl8169_open() + */ +static int rx_copybreak = 16383; +static int use_dac;  static struct {  	u32 msg_enable;  } debug = { -1 }; @@ -511,8 +516,7 @@ MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver");  module_param(rx_copybreak, int, 0);  MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");  module_param(use_dac, int, 0); -MODULE_PARM_DESC(use_dac, "Enable PCI DAC. -1 defaults on for PCI Express only." -" Unsafe on 32 bit PCI slot."); +MODULE_PARM_DESC(use_dac, "Enable PCI DAC. Unsafe on 32 bit PCI slot.");  module_param_named(debug, debug.msg_enable, int, 0);  MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)");  MODULE_LICENSE("GPL"); @@ -1038,14 +1042,14 @@ static void rtl8169_vlan_rx_register(struct net_device *dev,  }  static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc, -			       struct sk_buff *skb) +			       struct sk_buff *skb, int polling)  {  	u32 opts2 = le32_to_cpu(desc->opts2);  	struct vlan_group *vlgrp = tp->vlgrp;  	int ret;  	if (vlgrp && (opts2 & RxVlanTag)) { -		vlan_hwaccel_receive_skb(skb, vlgrp, swab16(opts2 & 0xffff)); +		__vlan_hwaccel_rx(skb, vlgrp, swab16(opts2 & 0xffff), polling);  		ret = 0;  	} else  		ret = -1; @@ -1062,7 +1066,7 @@ static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp,  }  static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc, -			       struct sk_buff *skb) +			       struct sk_buff *skb, int polling)  {  	return -1;  } @@ -2755,6 +2759,7 @@ static void rtl8169_release_board(struct pci_dev *pdev, struct net_device *dev,  {  	iounmap(ioaddr);  	pci_release_regions(pdev); +	pci_clear_mwi(pdev);  	pci_disable_device(pdev);  	free_netdev(dev);  } @@ -2821,8 +2826,13 @@ static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr)  	spin_lock_irq(&tp->lock);  	RTL_W8(Cfg9346, Cfg9346_Unlock); -	RTL_W32(MAC0, low); +  	RTL_W32(MAC4, high); +	RTL_R32(MAC4); + +	RTL_W32(MAC0, low); +	RTL_R32(MAC0); +  	RTL_W8(Cfg9346, Cfg9346_Lock);  	spin_unlock_irq(&tp->lock); @@ -2974,7 +2984,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  	void __iomem *ioaddr;  	unsigned int i;  	int rc; -	int this_use_dac = use_dac;  	if (netif_msg_drv(&debug)) {  		printk(KERN_INFO "%s Gigabit Ethernet driver %s loaded\n", @@ -3011,9 +3020,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  		goto err_out_free_dev_1;  	} -	rc = pci_set_mwi(pdev); -	if (rc < 0) -		goto err_out_disable_2; +	if (pci_set_mwi(pdev) < 0) +		netif_info(tp, probe, dev, "Mem-Wr-Inval unavailable\n");  	/* make sure PCI base addr 1 is MMIO */  	if (!(pci_resource_flags(pdev, region) & IORESOURCE_MEM)) { @@ -3021,7 +3029,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  			  "region #%d not an MMIO resource, aborting\n",  			  region);  		rc = -ENODEV; -		goto err_out_mwi_3; +		goto err_out_mwi_2;  	}  	/* check for weird/broken PCI region reporting */ @@ -3029,35 +3037,26 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  		netif_err(tp, probe, dev,  			  "Invalid PCI region size(s), aborting\n");  		rc = -ENODEV; -		goto err_out_mwi_3; +		goto err_out_mwi_2;  	}  	rc = pci_request_regions(pdev, MODULENAME);  	if (rc < 0) {  		netif_err(tp, probe, dev, "could not request regions\n"); -		goto err_out_mwi_3; +		goto err_out_mwi_2;  	}  	tp->cp_cmd = PCIMulRW | RxChkSum; -	tp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); -	if (!tp->pcie_cap) -		netif_info(tp, probe, dev, "no PCI Express capability\n"); - -	if (this_use_dac < 0) -		this_use_dac = tp->pcie_cap != 0; -  	if ((sizeof(dma_addr_t) > 4) && -	    this_use_dac && -	    !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { -		netif_info(tp, probe, dev, "using 64-bit DMA\n"); +	    !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && use_dac) {  		tp->cp_cmd |= PCIDAC;  		dev->features |= NETIF_F_HIGHDMA;  	} else {  		rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));  		if (rc < 0) {  			netif_err(tp, probe, dev, "DMA configuration failed\n"); -			goto err_out_free_res_4; +			goto err_out_free_res_3;  		}  	} @@ -3066,9 +3065,13 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  	if (!ioaddr) {  		netif_err(tp, probe, dev, "cannot remap MMIO, aborting\n");  		rc = -EIO; -		goto err_out_free_res_4; +		goto err_out_free_res_3;  	} +	tp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); +	if (!tp->pcie_cap) +		netif_info(tp, probe, dev, "no PCI Express capability\n"); +  	RTL_W16(IntrMask, 0x0000);  	/* Soft reset the chip. */ @@ -3104,7 +3107,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  	if (i == ARRAY_SIZE(rtl_chip_info)) {  		dev_err(&pdev->dev,  			"driver bug, MAC version not found in rtl_chip_info\n"); -		goto err_out_msi_5; +		goto err_out_msi_4;  	}  	tp->chipset = i; @@ -3169,7 +3172,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  	rc = register_netdev(dev);  	if (rc < 0) -		goto err_out_msi_5; +		goto err_out_msi_4;  	pci_set_drvdata(pdev, dev); @@ -3192,14 +3195,13 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  out:  	return rc; -err_out_msi_5: +err_out_msi_4:  	rtl_disable_msi(pdev, tp);  	iounmap(ioaddr); -err_out_free_res_4: +err_out_free_res_3:  	pci_release_regions(pdev); -err_out_mwi_3: +err_out_mwi_2:  	pci_clear_mwi(pdev); -err_out_disable_2:  	pci_disable_device(pdev);  err_out_free_dev_1:  	free_netdev(dev); @@ -3224,9 +3226,13 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev)  }  static void rtl8169_set_rxbufsize(struct rtl8169_private *tp, -				  struct net_device *dev) +				  unsigned int mtu)  { -	unsigned int max_frame = dev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; +	unsigned int max_frame = mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; + +	if (max_frame != 16383) +		printk(KERN_WARNING PFX "WARNING! Changing of MTU on this " +			"NIC may lead to frame reception errors!\n");  	tp->rx_buf_sz = (max_frame > RX_BUF_SIZE) ? max_frame : RX_BUF_SIZE;  } @@ -3238,7 +3244,17 @@ static int rtl8169_open(struct net_device *dev)  	int retval = -ENOMEM; -	rtl8169_set_rxbufsize(tp, dev); +	/* +	 * Note that we use a magic value here, its wierd I know +	 * its done because, some subset of rtl8169 hardware suffers from +	 * a problem in which frames received that are longer than +	 * the size set in RxMaxSize register return garbage sizes +	 * when received.  To avoid this we need to turn off filtering, +	 * which is done by setting a value of 16383 in the RxMaxSize register +	 * and allocating 16k frames to handle the largest possible rx value +	 * thats what the magic math below does. +	 */ +	rtl8169_set_rxbufsize(tp, 16383 - VLAN_ETH_HLEN - ETH_FCS_LEN);  	/*  	 * Rx and Tx desscriptors needs 256 bytes alignment. @@ -3891,7 +3907,7 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)  	rtl8169_down(dev); -	rtl8169_set_rxbufsize(tp, dev); +	rtl8169_set_rxbufsize(tp, dev->mtu);  	ret = rtl8169_init_ring(dev);  	if (ret < 0) @@ -4429,12 +4445,20 @@ out:  	return done;  } +/* + * Warning : rtl8169_rx_interrupt() might be called : + * 1) from NAPI (softirq) context + *	(polling = 1 : we should call netif_receive_skb()) + * 2) from process context (rtl8169_reset_task()) + *	(polling = 0 : we must call netif_rx() instead) + */  static int rtl8169_rx_interrupt(struct net_device *dev,  				struct rtl8169_private *tp,  				void __iomem *ioaddr, u32 budget)  {  	unsigned int cur_rx, rx_left;  	unsigned int delta, count; +	int polling = (budget != ~(u32)0) ? 1 : 0;  	cur_rx = tp->cur_rx;  	rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx; @@ -4496,8 +4520,12 @@ static int rtl8169_rx_interrupt(struct net_device *dev,  			skb_put(skb, pkt_size);  			skb->protocol = eth_type_trans(skb, dev); -			if (rtl8169_rx_vlan_skb(tp, desc, skb) < 0) -				netif_receive_skb(skb); +			if (rtl8169_rx_vlan_skb(tp, desc, skb, polling) < 0) { +				if (likely(polling)) +					netif_receive_skb(skb); +				else +					netif_rx(skb); +			}  			dev->stats.rx_bytes += pkt_size;  			dev->stats.rx_packets++; @@ -4754,8 +4782,8 @@ static void rtl_set_rx_mode(struct net_device *dev)  		mc_filter[1] = swab32(data);  	} -	RTL_W32(MAR0 + 0, mc_filter[0]);  	RTL_W32(MAR0 + 4, mc_filter[1]); +	RTL_W32(MAR0 + 0, mc_filter[0]);  	RTL_W32(RxConfig, tmp); diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index ede937ee50c..07eb884ff98 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -16,6 +16,7 @@  #include <linux/delay.h>  #include <linux/rio.h>  #include <linux/rio_drv.h> +#include <linux/slab.h>  #include <linux/rio_ids.h>  #include <linux/netdevice.h> diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index 266baf53496..f2e335f0d1b 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -40,6 +40,7 @@  #include <linux/init.h>  #include <linux/delay.h>  #include <linux/mm.h> +#include <linux/slab.h>  #include <net/sock.h>  #include <asm/system.h> diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index df70657260d..92ae8d3de39 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -79,6 +79,7 @@  #include <linux/tcp.h>  #include <linux/uaccess.h>  #include <linux/io.h> +#include <linux/slab.h>  #include <net/tcp.h>  #include <asm/system.h> @@ -5819,10 +5820,8 @@ static void s2io_vpd_read(struct s2io_nic *nic)  		}  	} -	if ((!fail) && (vpd_data[1] < VPD_STRING_LEN)) { -		memset(nic->product_name, 0, vpd_data[1]); +	if ((!fail) && (vpd_data[1] < VPD_STRING_LEN))  		memcpy(nic->product_name, &vpd_data[3], vpd_data[1]); -	}  	kfree(vpd_data);  	swstats->mem_freed += 256;  } diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index 9f83a119737..abc8eefdd4b 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -42,7 +42,6 @@ static char version[] = "sb1000.c:v1.1.2 6/01/98 (fventuri@mediaone.net)\n";  #include <linux/errno.h>  #include <linux/if_cablemodem.h> /* for SIOGCM/SIOSCM stuff */  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/ioport.h>  #include <linux/netdevice.h>  #include <linux/if_arp.h> @@ -52,6 +51,7 @@ static char version[] = "sb1000.c:v1.1.2 6/01/98 (fventuri@mediaone.net)\n";  #include <linux/pnp.h>  #include <linux/init.h>  #include <linux/bitops.h> +#include <linux/gfp.h>  #include <asm/io.h>  #include <asm/processor.h> diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 9944e5d662c..04efc0c1bda 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2353,17 +2353,36 @@ static int sbmac_init(struct platform_device *pldev, long long base)  	sc->mii_bus = mdiobus_alloc();  	if (sc->mii_bus == NULL) { -		sbmac_uninitctx(sc); -		return -ENOMEM; +		err = -ENOMEM; +		goto uninit_ctx;  	} +	sc->mii_bus->name = sbmac_mdio_string; +	snprintf(sc->mii_bus->id, MII_BUS_ID_SIZE, "%x", idx); +	sc->mii_bus->priv = sc; +	sc->mii_bus->read = sbmac_mii_read; +	sc->mii_bus->write = sbmac_mii_write; +	sc->mii_bus->irq = sc->phy_irq; +	for (i = 0; i < PHY_MAX_ADDR; ++i) +		sc->mii_bus->irq[i] = SBMAC_PHY_INT; + +	sc->mii_bus->parent = &pldev->dev; +	/* +	 * Probe PHY address +	 */ +	err = mdiobus_register(sc->mii_bus); +	if (err) { +		printk(KERN_ERR "%s: unable to register MDIO bus\n", +		       dev->name); +		goto free_mdio; +	} +	dev_set_drvdata(&pldev->dev, sc->mii_bus); +  	err = register_netdev(dev);  	if (err) {  		printk(KERN_ERR "%s.%d: unable to register netdev\n",  		       sbmac_string, idx); -		mdiobus_free(sc->mii_bus); -		sbmac_uninitctx(sc); -		return err; +		goto unreg_mdio;  	}  	pr_info("%s.%d: registered as %s\n", sbmac_string, idx, dev->name); @@ -2379,19 +2398,15 @@ static int sbmac_init(struct platform_device *pldev, long long base)  	pr_info("%s: SiByte Ethernet at 0x%08Lx, address: %pM\n",  	       dev->name, base, eaddr); -	sc->mii_bus->name = sbmac_mdio_string; -	snprintf(sc->mii_bus->id, MII_BUS_ID_SIZE, "%x", idx); -	sc->mii_bus->priv = sc; -	sc->mii_bus->read = sbmac_mii_read; -	sc->mii_bus->write = sbmac_mii_write; -	sc->mii_bus->irq = sc->phy_irq; -	for (i = 0; i < PHY_MAX_ADDR; ++i) -		sc->mii_bus->irq[i] = SBMAC_PHY_INT; - -	sc->mii_bus->parent = &pldev->dev; -	dev_set_drvdata(&pldev->dev, sc->mii_bus); -  	return 0; +unreg_mdio: +	mdiobus_unregister(sc->mii_bus); +	dev_set_drvdata(&pldev->dev, NULL); +free_mdio: +	mdiobus_free(sc->mii_bus); +uninit_ctx: +	sbmac_uninitctx(sc); +	return err;  } @@ -2417,16 +2432,6 @@ static int sbmac_open(struct net_device *dev)  		goto out_err;  	} -	/* -	 * Probe PHY address -	 */ -	err = mdiobus_register(sc->mii_bus); -	if (err) { -		printk(KERN_ERR "%s: unable to register MDIO bus\n", -		       dev->name); -		goto out_unirq; -	} -  	sc->sbm_speed = sbmac_speed_none;  	sc->sbm_duplex = sbmac_duplex_none;  	sc->sbm_fc = sbmac_fc_none; @@ -2457,11 +2462,7 @@ static int sbmac_open(struct net_device *dev)  	return 0;  out_unregister: -	mdiobus_unregister(sc->mii_bus); - -out_unirq:  	free_irq(dev->irq, dev); -  out_err:  	return err;  } @@ -2650,9 +2651,6 @@ static int sbmac_close(struct net_device *dev)  	phy_disconnect(sc->phy_dev);  	sc->phy_dev = NULL; - -	mdiobus_unregister(sc->mii_bus); -  	free_irq(dev->irq, dev);  	sbdma_emptyring(&(sc->sbm_txdma)); @@ -2760,6 +2758,7 @@ static int __exit sbmac_remove(struct platform_device *pldev)  	unregister_netdev(dev);  	sbmac_uninitctx(sc); +	mdiobus_unregister(sc->mii_bus);  	mdiobus_free(sc->mii_bus);  	iounmap(sc->sbm_base);  	free_netdev(dev); diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index fe806bd9b95..374832cca11 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -37,7 +37,6 @@ static const char version[] =  #include <linux/interrupt.h>  #include <linux/ioport.h>  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/init.h>  #include <linux/delay.h> diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 88f2fb193ab..649a264d6a8 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -20,6 +20,7 @@  #include <linux/crc32.h>  #include <linux/ethtool.h>  #include <linux/topology.h> +#include <linux/gfp.h>  #include "net_driver.h"  #include "efx.h"  #include "mdio_10g.h" @@ -1860,6 +1861,7 @@ out:  	}  	if (disabled) { +		dev_close(efx->net_dev);  		EFX_ERR(efx, "has been disabled\n");  		efx->state = STATE_DISABLED;  	} else { @@ -1883,8 +1885,7 @@ static void efx_reset_work(struct work_struct *data)  	}  	rtnl_lock(); -	if (efx_reset(efx, efx->reset_pending)) -		dev_close(efx->net_dev); +	(void)efx_reset(efx, efx->reset_pending);  	rtnl_unlock();  } diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 1b8d83657aa..08278e7302b 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -15,6 +15,7 @@  #include <linux/seq_file.h>  #include <linux/i2c.h>  #include <linux/mii.h> +#include <linux/slab.h>  #include "net_driver.h"  #include "bitfield.h"  #include "efx.h" @@ -1319,7 +1320,9 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)  	EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mdio.prtad); -	falcon_probe_board(efx, board_rev); +	rc = falcon_probe_board(efx, board_rev); +	if (rc) +		goto fail2;  	kfree(nvconfig);  	return 0; diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c index 5712fddd72f..c7a933a3292 100644 --- a/drivers/net/sfc/falcon_boards.c +++ b/drivers/net/sfc/falcon_boards.c @@ -728,15 +728,7 @@ static const struct falcon_board_type board_types[] = {  	},  }; -static const struct falcon_board_type falcon_dummy_board = { -	.init		= efx_port_dummy_op_int, -	.init_phy	= efx_port_dummy_op_void, -	.fini		= efx_port_dummy_op_void, -	.set_id_led	= efx_port_dummy_op_set_id_led, -	.monitor	= efx_port_dummy_op_int, -}; - -void falcon_probe_board(struct efx_nic *efx, u16 revision_info) +int falcon_probe_board(struct efx_nic *efx, u16 revision_info)  {  	struct falcon_board *board = falcon_board(efx);  	u8 type_id = FALCON_BOARD_TYPE(revision_info); @@ -754,8 +746,9 @@ void falcon_probe_board(struct efx_nic *efx, u16 revision_info)  			 (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC)  			 ? board->type->ref_model : board->type->gen_type,  			 'A' + board->major, board->minor); +		return 0;  	} else {  		EFX_ERR(efx, "unknown board type %d\n", type_id); -		board->type = &falcon_dummy_board; +		return -ENODEV;  	}  } diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c index 34c22fa986e..2f235469666 100644 --- a/drivers/net/sfc/mcdi_phy.c +++ b/drivers/net/sfc/mcdi_phy.c @@ -11,6 +11,7 @@   * Driver for PHY related operations via MCDI.   */ +#include <linux/slab.h>  #include "efx.h"  #include "phy.h"  #include "mcdi.h" diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c index 407bbaddfea..f3ac7f30b5e 100644 --- a/drivers/net/sfc/mtd.c +++ b/drivers/net/sfc/mtd.c @@ -12,6 +12,7 @@  #include <linux/module.h>  #include <linux/mtd/mtd.h>  #include <linux/delay.h> +#include <linux/slab.h>  #include <linux/rtnetlink.h>  #define EFX_DRIVER_NAME "sfc_mtd" diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h index 9351c0331a4..3166bafdfbe 100644 --- a/drivers/net/sfc/nic.h +++ b/drivers/net/sfc/nic.h @@ -156,7 +156,7 @@ extern struct efx_nic_type siena_a0_nic_type;   **************************************************************************   */ -extern void falcon_probe_board(struct efx_nic *efx, u16 revision_info); +extern int falcon_probe_board(struct efx_nic *efx, u16 revision_info);  /* TX data path */  extern int efx_nic_probe_tx(struct efx_tx_queue *tx_queue); diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c index 1bee62c8300..e077bef08a5 100644 --- a/drivers/net/sfc/qt202x_phy.c +++ b/drivers/net/sfc/qt202x_phy.c @@ -10,6 +10,7 @@   * Driver for AMCC QT202x SFP+ and XFP adapters; see www.amcc.com for details   */ +#include <linux/slab.h>  #include <linux/timer.h>  #include <linux/delay.h>  #include "efx.h" diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c index a97c923b560..e308818b9f5 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c @@ -10,6 +10,7 @@  #include <linux/socket.h>  #include <linux/in.h> +#include <linux/slab.h>  #include <linux/ip.h>  #include <linux/tcp.h>  #include <linux/udp.h> diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index cf0139a7d9a..0106b1d9aae 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -18,6 +18,7 @@  #include <linux/in.h>  #include <linux/udp.h>  #include <linux/rtnetlink.h> +#include <linux/slab.h>  #include <asm/io.h>  #include "net_driver.h"  #include "efx.h" diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index 1619fb5a64f..e0c46f59d1f 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -12,6 +12,7 @@  #include <linux/delay.h>  #include <linux/pci.h>  #include <linux/module.h> +#include <linux/slab.h>  #include "net_driver.h"  #include "bitfield.h"  #include "efx.h" @@ -455,8 +456,17 @@ static int siena_try_update_nic_stats(struct efx_nic *efx)  static void siena_update_nic_stats(struct efx_nic *efx)  { -	while (siena_try_update_nic_stats(efx) == -EAGAIN) -		cpu_relax(); +	int retry; + +	/* If we're unlucky enough to read statistics wduring the DMA, wait +	 * up to 10ms for it to finish (typically takes <500us) */ +	for (retry = 0; retry < 100; ++retry) { +		if (siena_try_update_nic_stats(efx) == 0) +			return; +		udelay(100); +	} + +	/* Use the old values instead */  }  static void siena_start_nic_stats(struct efx_nic *efx) diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index 10db071bd83..f21efe7bd31 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -10,6 +10,7 @@  #include <linux/delay.h>  #include <linux/rtnetlink.h>  #include <linux/seq_file.h> +#include <linux/slab.h>  #include "efx.h"  #include "mdio_10g.h"  #include "nic.h" diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index a8b70ef6d81..be0e110a1f7 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -13,6 +13,7 @@  #include <linux/ip.h>  #include <linux/in.h>  #include <linux/ipv6.h> +#include <linux/slab.h>  #include <net/ipv6.h>  #include <linux/if_ether.h>  #include <linux/highmem.h> diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index ed999d31f1f..c8fc896fc46 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -8,6 +8,7 @@  #include <linux/kernel.h>  #include <linux/module.h> +#include <linux/slab.h>  #include <linux/errno.h>  #include <linux/init.h>  #include <linux/types.h> @@ -592,8 +593,10 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)  	/* Setup... */  	len = skb->len;  	if (len < ETH_ZLEN) { -		if (skb_padto(skb, ETH_ZLEN)) +		if (skb_padto(skb, ETH_ZLEN)) { +			spin_unlock_irqrestore(&sp->tx_lock, flags);  			return NETDEV_TX_OK; +		}  		len = ETH_ZLEN;  	} diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 42a35f086a9..6242b85d5d1 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -31,6 +31,7 @@  #include <linux/cache.h>  #include <linux/io.h>  #include <linux/pm_runtime.h> +#include <linux/slab.h>  #include <asm/cacheflush.h>  #include "sh_eth.h" diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 760d9e83a46..b30ce752bbf 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -32,6 +32,7 @@  #include <linux/delay.h>  #include <linux/crc32.h>  #include <linux/dma-mapping.h> +#include <linux/slab.h>  #include <asm/irq.h>  #define PHY_MAX_ADDR		32 diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index 1921a54ea99..d9016b75abc 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -78,13 +78,13 @@ static const char * const boot_msg =  #include <linux/kernel.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/pci.h>  #include <linux/netdevice.h>  #include <linux/fddidevice.h>  #include <linux/skbuff.h>  #include <linux/bitops.h> +#include <linux/gfp.h>  #include <asm/byteorder.h>  #include <asm/io.h> diff --git a/drivers/net/skge.c b/drivers/net/skge.c index d0058e5bb6a..50eb70609f2 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -42,6 +42,7 @@  #include <linux/sched.h>  #include <linux/seq_file.h>  #include <linux/mii.h> +#include <linux/slab.h>  #include <asm/irq.h>  #include "skge.h" diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index d8ec4c11fd4..088c797eb73 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -33,6 +33,7 @@  #include <linux/ethtool.h>  #include <linux/pci.h>  #include <linux/ip.h> +#include <linux/slab.h>  #include <net/ip.h>  #include <linux/tcp.h>  #include <linux/in.h> diff --git a/drivers/net/slhc.c b/drivers/net/slhc.c index d640c0f5470..140d63f3caf 100644 --- a/drivers/net/slhc.c +++ b/drivers/net/slhc.c @@ -51,6 +51,7 @@   */  #include <linux/module.h> +#include <linux/slab.h>  #include <linux/types.h>  #include <linux/string.h>  #include <linux/errno.h> diff --git a/drivers/net/slip.c b/drivers/net/slip.c index ba5bbc50344..89696156c05 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -83,6 +83,7 @@  #include <linux/compat.h>  #include <linux/delay.h>  #include <linux/init.h> +#include <linux/slab.h>  #include "slip.h"  #ifdef CONFIG_INET  #include <linux/ip.h> diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 9871a2b61f8..635820d42b1 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -59,7 +59,6 @@ static const char version[] =  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/sched.h> -#include <linux/slab.h>  #include <linux/delay.h>  #include <linux/interrupt.h>  #include <linux/errno.h> diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index f9a960e7fc1..3f2f7843aa4 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -64,7 +64,6 @@ static const char version[] =  #include <linux/interrupt.h>  #include <linux/ioport.h>  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/init.h>  #include <linux/crc32.h> diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index fc1b5a1a358..860339d51d5 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -70,7 +70,6 @@ static const char version[] =  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/sched.h> -#include <linux/slab.h>  #include <linux/delay.h>  #include <linux/interrupt.h>  #include <linux/errno.h> diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index 4fd1d8b3878..cbf520d38ea 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -41,7 +41,6 @@  #include <linux/netdevice.h>  #include <linux/platform_device.h>  #include <linux/sched.h> -#include <linux/slab.h>  #include <linux/timer.h>  #include <linux/bug.h>  #include <linux/bitops.h> diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c index 34fa10d8ad4..aafaebf4574 100644 --- a/drivers/net/smsc9420.c +++ b/drivers/net/smsc9420.c @@ -26,6 +26,7 @@  #include <linux/if_vlan.h>  #include <linux/dma-mapping.h>  #include <linux/crc32.h> +#include <linux/slab.h>  #include <asm/unaligned.h>  #include "smsc9420.h" diff --git a/drivers/net/sni_82596.c b/drivers/net/sni_82596.c index 854ccf2b410..6b2a8881747 100644 --- a/drivers/net/sni_82596.c +++ b/drivers/net/sni_82596.c @@ -8,7 +8,6 @@  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/delay.h>  #include <linux/netdevice.h> diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 5ba9d989f8f..dd3cb0f2d21 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -31,6 +31,7 @@  #include <linux/if_vlan.h>  #include <linux/in.h>  #include <linux/init.h> +#include <linux/gfp.h>  #include <linux/ioport.h>  #include <linux/ip.h>  #include <linux/kernel.h> @@ -40,7 +41,6 @@  #include <linux/device.h>  #include <linux/pci.h>  #include <linux/skbuff.h> -#include <linux/slab.h>  #include <linux/tcp.h>  #include <linux/types.h>  #include <linux/vmalloc.h> diff --git a/drivers/net/stmmac/Kconfig b/drivers/net/stmmac/Kconfig index fb287649a30..eb63d44748a 100644 --- a/drivers/net/stmmac/Kconfig +++ b/drivers/net/stmmac/Kconfig @@ -2,6 +2,7 @@ config STMMAC_ETH  	tristate "STMicroelectronics 10/100/1000 Ethernet driver"  	select MII  	select PHYLIB +	select CRC32  	depends on NETDEVICES && CPU_SUBTYPE_ST40  	help  	  This is the driver for the Ethernet IPs are built around a diff --git a/drivers/net/stmmac/dwmac100.c b/drivers/net/stmmac/dwmac100.c index 803b0373d84..4cacca614fc 100644 --- a/drivers/net/stmmac/dwmac100.c +++ b/drivers/net/stmmac/dwmac100.c @@ -29,6 +29,7 @@  #include <linux/crc32.h>  #include <linux/mii.h>  #include <linux/phy.h> +#include <linux/slab.h>  #include "common.h"  #include "dwmac100.h" diff --git a/drivers/net/stmmac/dwmac1000_core.c b/drivers/net/stmmac/dwmac1000_core.c index a6538ae4694..5bd95ebfe49 100644 --- a/drivers/net/stmmac/dwmac1000_core.c +++ b/drivers/net/stmmac/dwmac1000_core.c @@ -27,6 +27,7 @@  *******************************************************************************/  #include <linux/crc32.h> +#include <linux/slab.h>  #include "dwmac1000.h"  static void dwmac1000_core_init(unsigned long ioaddr) diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index a6733612d64..4111a85ec80 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -44,6 +44,7 @@  #include <linux/phy.h>  #include <linux/if_vlan.h>  #include <linux/dma-mapping.h> +#include <linux/slab.h>  #include "stmmac.h"  #define STMMAC_RESOURCE_NAME	"stmmaceth" @@ -1685,7 +1686,7 @@ static int stmmac_dvr_probe(struct platform_device *pdev)  	}  	pr_info("done!\n"); -	if (!request_mem_region(res->start, (res->end - res->start), +	if (!request_mem_region(res->start, resource_size(res),  				pdev->name)) {  		pr_err("%s: ERROR: memory allocation failed"  		       "cannot get the I/O addr 0x%x\n", @@ -1694,9 +1695,9 @@ static int stmmac_dvr_probe(struct platform_device *pdev)  		goto out;  	} -	addr = ioremap(res->start, (res->end - res->start)); +	addr = ioremap(res->start, resource_size(res));  	if (!addr) { -		pr_err("%s: ERROR: memory mapping failed \n", __func__); +		pr_err("%s: ERROR: memory mapping failed\n", __func__);  		ret = -ENOMEM;  		goto out;  	} @@ -1774,7 +1775,7 @@ static int stmmac_dvr_probe(struct platform_device *pdev)  out:  	if (ret < 0) {  		platform_set_drvdata(pdev, NULL); -		release_mem_region(res->start, (res->end - res->start)); +		release_mem_region(res->start, resource_size(res));  		if (addr != NULL)  			iounmap(addr);  	} @@ -1812,7 +1813,7 @@ static int stmmac_dvr_remove(struct platform_device *pdev)  	iounmap((void *)ndev->base_addr);  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	release_mem_region(res->start, (res->end - res->start)); +	release_mem_region(res->start, resource_size(res));  	free_netdev(ndev); diff --git a/drivers/net/stmmac/stmmac_mdio.c b/drivers/net/stmmac/stmmac_mdio.c index fffe1d037fe..40b2c792971 100644 --- a/drivers/net/stmmac/stmmac_mdio.c +++ b/drivers/net/stmmac/stmmac_mdio.c @@ -26,6 +26,7 @@  #include <linux/mii.h>  #include <linux/phy.h> +#include <linux/slab.h>  #include "stmmac.h" diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c index 2f6a760e5f2..8b28c89a9a7 100644 --- a/drivers/net/sun3_82586.c +++ b/drivers/net/sun3_82586.c @@ -33,7 +33,6 @@ static int fifo=0x8;	/* don't change */  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/delay.h>  #include <linux/init.h> diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index 99998862c22..1694ca5bfb4 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -28,7 +28,6 @@ static char *version = "sun3lance.c: v1.2 1/12/2001  Sam Creasey (sammy@sammy.ne  #include <linux/kernel.h>  #include <linux/string.h>  #include <linux/errno.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/init.h>  #include <linux/ioport.h> diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index a0bd361d5ec..ed7865a0b5b 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -11,7 +11,6 @@  #include <linux/interrupt.h>  #include <linux/ioport.h>  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/delay.h>  #include <linux/init.h> @@ -25,6 +24,7 @@  #include <linux/dma-mapping.h>  #include <linux/of.h>  #include <linux/of_device.h> +#include <linux/gfp.h>  #include <asm/auxio.h>  #include <asm/byteorder.h> diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index a855934dfc3..8249a394a4e 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -84,7 +84,6 @@ static char *media[MAX_UNITS];  #include <linux/timer.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/pci.h>  #include <linux/netdevice.h> diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 70196bc5fe6..e6880f1c4e8 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -39,7 +39,6 @@  #include <linux/ioport.h>  #include <linux/in.h>  #include <linux/sched.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/delay.h>  #include <linux/init.h> @@ -58,6 +57,7 @@  #include <linux/bitops.h>  #include <linux/mutex.h>  #include <linux/mm.h> +#include <linux/gfp.h>  #include <asm/system.h>  #include <asm/io.h> diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index d7c73f478ef..0c21653ff9f 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -78,7 +78,6 @@ static char lancestr[] = "LANCE";  #include <linux/interrupt.h>  #include <linux/ioport.h>  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/delay.h>  #include <linux/init.h> @@ -94,6 +93,7 @@ static char lancestr[] = "LANCE";  #include <linux/dma-mapping.h>  #include <linux/of.h>  #include <linux/of_device.h> +#include <linux/gfp.h>  #include <asm/system.h>  #include <asm/io.h> diff --git a/drivers/net/tehuti.h b/drivers/net/tehuti.h index a19dcf8b6b5..cff98d07cba 100644 --- a/drivers/net/tehuti.h +++ b/drivers/net/tehuti.h @@ -32,6 +32,7 @@  #include <linux/firmware.h>  #include <asm/byteorder.h>  #include <linux/dma-mapping.h> +#include <linux/slab.h>  /* Compile Time Switches */  /* start */ diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 22cf1c446de..ecc41cffb47 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8633,6 +8633,7 @@ static int tg3_test_msi(struct tg3 *tp)  	pci_disable_msi(tp->pdev);  	tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; +	tp->napi[0].irq_vec = tp->pdev->irq;  	err = tg3_request_irq(tp, 0);  	if (err) diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index 0fb930feea4..7d7f3eef1ab 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -63,6 +63,7 @@  #include <linux/spinlock.h>  #include <linux/bitops.h>  #include <linux/firmware.h> +#include <linux/slab.h>  #include <net/checksum.h> diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index dd028fee9dc..7a5fbf5a9d7 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -121,6 +121,7 @@  #include <linux/spinlock.h>  #include <linux/bitops.h>  #include <linux/jiffies.h> +#include <linux/slab.h>  #include <net/net_namespace.h>  #include <net/checksum.h> diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c index 456f8bff40b..53f631ebb16 100644 --- a/drivers/net/tokenring/madgemc.c +++ b/drivers/net/tokenring/madgemc.c @@ -21,6 +21,7 @@ static const char version[] = "madgemc.c: v0.91 23/01/2000 by Adam Fritzler\n";  #include <linux/module.h>  #include <linux/mca.h> +#include <linux/slab.h>  #include <linux/kernel.h>  #include <linux/errno.h>  #include <linux/init.h> diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index 5401d86a7be..e40560137c4 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -36,7 +36,6 @@  #include <linux/ptrace.h>  #include <linux/ioport.h>  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/time.h>  #include <linux/errno.h> diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index ee71bcfb375..8b508c92241 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -85,7 +85,6 @@ static const char version[] = "tms380tr.c: v1.10 30/12/2002 by Christoph Goos, A  #include <linux/ptrace.h>  #include <linux/ioport.h>  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/time.h>  #include <linux/errno.h> diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index 647cdd1d4e2..5b1fbb3c3b5 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -38,7 +38,6 @@  #include <linux/etherdevice.h>  #include <linux/ethtool.h>  #include <linux/skbuff.h> -#include <linux/slab.h>  #include <linux/spinlock.h>  #include <linux/delay.h>  #include <linux/crc32.h> @@ -48,6 +47,7 @@  #include <linux/rtnetlink.h>  #include <linux/timer.h>  #include <linux/platform_device.h> +#include <linux/gfp.h>  #include <asm/system.h>  #include <asm/io.h> diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index cb429723b2c..19cafc2b418 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -42,6 +42,7 @@  #include <linux/compiler.h>  #include <linux/rtnetlink.h>  #include <linux/crc32.h> +#include <linux/slab.h>  #include <asm/io.h>  #include <asm/irq.h> diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index c4ecb9a9540..09b57193a16 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -450,7 +450,6 @@  #include <linux/ptrace.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/pci.h>  #include <linux/eisa.h>  #include <linux/delay.h> @@ -467,6 +466,7 @@  #include <linux/dma-mapping.h>  #include <linux/moduleparam.h>  #include <linux/bitops.h> +#include <linux/gfp.h>  #include <asm/io.h>  #include <asm/dma.h> diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index 95b38d803e9..9568156dea9 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -74,7 +74,6 @@  #include <linux/ptrace.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/pci.h>  #include <linux/dma-mapping.h> diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c index 49f05d1431f..6002e651b9e 100644 --- a/drivers/net/tulip/eeprom.c +++ b/drivers/net/tulip/eeprom.c @@ -13,6 +13,7 @@  */  #include <linux/pci.h> +#include <linux/slab.h>  #include "tulip.h"  #include <linux/init.h>  #include <asm/unaligned.h> diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 7f544ef2f5f..3810db9dc2d 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -24,6 +24,7 @@  #include <linux/module.h>  #include <linux/pci.h> +#include <linux/slab.h>  #include "tulip.h"  #include <linux/init.h>  #include <linux/etherdevice.h> diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index 0ab05af237e..a589dd34891 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -25,7 +25,6 @@  #include <linux/timer.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/pci.h>  #include <linux/init.h> @@ -851,13 +850,15 @@ static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info  			if ( !(rdes0 & 0x8000) ||  				((db->cr6_data & CR6_PM) && (rxlen>6)) ) { +				struct sk_buff *new_skb = NULL; +  				skb = rxptr->rx_skb_ptr;  				/* Good packet, send to upper layer */  				/* Shorst packet used new SKB */ -				if ( (rxlen < RX_COPY_SIZE) && -					( (skb = dev_alloc_skb(rxlen + 2) ) -					!= NULL) ) { +				if ((rxlen < RX_COPY_SIZE) && +				    (((new_skb = dev_alloc_skb(rxlen + 2)) != NULL))) { +					skb = new_skb;  					/* size less than COPY_SIZE, allocate a rxlen SKB */  					skb_reserve(skb, 2); /* 16byte align */  					memcpy(skb_put(skb, rxlen), diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 304f43866c4..98dbf6cc1d6 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -114,7 +114,6 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};  #include <linux/timer.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/pci.h>  #include <linux/dma-mapping.h> diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 96c39bddc78..43265207d46 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -387,6 +387,10 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)  		}  	} +	/* Orphan the skb - required as we might hang on to it +	 * for indefinite time. */ +	skb_orphan(skb); +  	/* Enqueue packet */  	skb_queue_tail(&tun->socket.sk->sk_receive_queue, skb);  	dev->trans_start = jiffies; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index cd24e5f2b2a..98d818daa77 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -109,7 +109,6 @@ static const int multicast_filter_limit = 32;  #include <linux/timer.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/pci.h>  #include <linux/netdevice.h> diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c index 7075f26e97d..6f92e48f02d 100644 --- a/drivers/net/ucc_geth_ethtool.c +++ b/drivers/net/ucc_geth_ethtool.c @@ -18,7 +18,6 @@  #include <linux/kernel.h>  #include <linux/init.h>  #include <linux/errno.h> -#include <linux/slab.h>  #include <linux/stddef.h>  #include <linux/interrupt.h>  #include <linux/netdevice.h> diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 32d93564a74..d7b7018a1de 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -204,6 +204,14 @@ config USB_NET_DM9601  	  This option adds support for Davicom DM9601 based USB 1.1  	  10/100 Ethernet adapters. +config USB_NET_SMSC75XX +	tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices" +	depends on USB_USBNET +	select CRC32 +	help +	  This option adds support for SMSC LAN95XX based USB 2.0 +	  Gigabit Ethernet adapters. +  config USB_NET_SMSC95XX  	tristate "SMSC LAN95XX based USB 2.0 10/100 ethernet devices"  	depends on USB_USBNET @@ -377,4 +385,25 @@ config USB_CDC_PHONET  	  cellular modem, as found on most Nokia handsets with the  	  "PC suite" USB profile. +config USB_IPHETH +	tristate "Apple iPhone USB Ethernet driver" +	default n +	---help--- +	  Module used to share Internet connection (tethering) from your +	  iPhone (Original, 3G and 3GS) to your system. +	  Note that you need userspace libraries and programs that are needed +	  to pair your device with your system and that understand the iPhone +	  protocol. + +	  For more information: http://giagio.com/wiki/moin.cgi/iPhoneEthernetDriver + +config USB_SIERRA_NET +	tristate "USB-to-WWAN Driver for Sierra Wireless modems" +	depends on USB_USBNET +	help +	  Choose this option if you have a Sierra Wireless USB-to-WWAN device. + +	  To compile this driver as a module, choose M here: the +	  module will be called sierra_net. +  endmenu diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile index e17afb78f37..b13a279663b 100644 --- a/drivers/net/usb/Makefile +++ b/drivers/net/usb/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_USB_NET_AX8817X)	+= asix.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 +obj-$(CONFIG_USB_NET_SMSC75XX)	+= smsc75xx.o  obj-$(CONFIG_USB_NET_SMSC95XX)	+= smsc95xx.o  obj-$(CONFIG_USB_NET_GL620A)	+= gl620a.o  obj-$(CONFIG_USB_NET_NET1080)	+= net1080.o @@ -22,4 +23,6 @@ obj-$(CONFIG_USB_NET_MCS7830)	+= mcs7830.o  obj-$(CONFIG_USB_USBNET)	+= usbnet.o  obj-$(CONFIG_USB_NET_INT51X1)	+= int51x1.o  obj-$(CONFIG_USB_CDC_PHONET)	+= cdc-phonet.o +obj-$(CONFIG_USB_IPHETH)	+= ipheth.o +obj-$(CONFIG_USB_SIERRA_NET)	+= sierra_net.o diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index 9e05639435f..35f56fc8280 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -34,6 +34,7 @@  #include <linux/usb.h>  #include <linux/crc32.h>  #include <linux/usb/usbnet.h> +#include <linux/slab.h>  #define DRIVER_VERSION "14-Jun-2006"  static const char driver_name [] = "asix"; diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index 96f1ebe0d34..602e123b274 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -36,7 +36,6 @@  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/string.h> -#include <linux/slab.h>  #include <linux/netdevice.h>  #include <linux/etherdevice.h>  #include <linux/skbuff.h> @@ -44,6 +43,7 @@  #include <linux/ethtool.h>  #include <linux/crc32.h>  #include <linux/bitops.h> +#include <linux/gfp.h>  #include <asm/uaccess.h>  #undef DEBUG diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c index 6491c9c00c8..dc9444525b4 100644 --- a/drivers/net/usb/cdc-phonet.c +++ b/drivers/net/usb/cdc-phonet.c @@ -22,6 +22,7 @@  #include <linux/kernel.h>  #include <linux/module.h> +#include <linux/gfp.h>  #include <linux/usb.h>  #include <linux/usb/cdc.h>  #include <linux/netdevice.h> diff --git a/drivers/net/usb/cdc_eem.c b/drivers/net/usb/cdc_eem.c index a4a85a6ed86..5f3b97668e6 100644 --- a/drivers/net/usb/cdc_eem.c +++ b/drivers/net/usb/cdc_eem.c @@ -30,6 +30,7 @@  #include <linux/crc32.h>  #include <linux/usb/cdc.h>  #include <linux/usb/usbnet.h> +#include <linux/gfp.h>  /* diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index c8cdb7f30ad..3547cf13d21 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -431,6 +431,7 @@ static const struct driver_info mbm_info = {  	.bind = 	cdc_bind,  	.unbind =	usbnet_cdc_unbind,  	.status =	cdc_status, +	.manage_power =	cdc_manage_power,  };  /*-------------------------------------------------------------------------*/ diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index 269339769f4..5dfed9297b2 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c @@ -21,6 +21,7 @@  #include <linux/usb.h>  #include <linux/crc32.h>  #include <linux/usb/usbnet.h> +#include <linux/slab.h>  /* datasheet:   http://ptm2.cc.utu.fi/ftp/network/cards/DM9601/From_NET/DM9601-DS-P01-930914.pdf @@ -239,7 +240,7 @@ static int dm_write_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 valu  		goto out;  	dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg); -	dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0x1c : 0x14); +	dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0x1a : 0x12);  	for (i = 0; i < DM_TIMEOUT; i++) {  		u8 tmp; diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c index f7ccfad9384..dcd57c37ef7 100644 --- a/drivers/net/usb/gl620a.c +++ b/drivers/net/usb/gl620a.c @@ -30,6 +30,7 @@  #include <linux/mii.h>  #include <linux/usb.h>  #include <linux/usb/usbnet.h> +#include <linux/gfp.h>  /* diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 6895f153123..be0cc99e881 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -1155,9 +1155,6 @@ static void _hso_serial_set_termios(struct tty_struct *tty,  static void hso_resubmit_rx_bulk_urb(struct hso_serial *serial, struct urb *urb)  {  	int result; -#ifdef CONFIG_HSO_AUTOPM -	usb_mark_last_busy(urb->dev); -#endif  	/* We are done with this URB, resubmit it. Prep the USB to wait for  	 * another frame */  	usb_fill_bulk_urb(urb, serial->parent->usb, diff --git a/drivers/net/usb/int51x1.c b/drivers/net/usb/int51x1.c index 3c228df5706..be02a25da71 100644 --- a/drivers/net/usb/int51x1.c +++ b/drivers/net/usb/int51x1.c @@ -29,6 +29,7 @@  #include <linux/netdevice.h>  #include <linux/etherdevice.h>  #include <linux/ethtool.h> +#include <linux/slab.h>  #include <linux/mii.h>  #include <linux/usb.h>  #include <linux/usb/usbnet.h> diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c new file mode 100644 index 00000000000..418825d26f9 --- /dev/null +++ b/drivers/net/usb/ipheth.c @@ -0,0 +1,569 @@ +/* + * ipheth.c - Apple iPhone USB Ethernet driver + * + * Copyright (c) 2009 Diego Giagio <diego@giagio.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. Neither the name of GIAGIO.COM nor the names of its contributors + *    may be used to endorse or promote products derived from this software + *    without specific prior written permission. + * + * Alternatively, provided that this notice is retained in full, this + * software may be distributed under the terms of the GNU General + * Public License ("GPL") version 2, in which case the provisions of the + * GPL apply INSTEAD OF those given above. + * + * The provided data structures and external interfaces from this code + * are not restricted to be used by modules with a GPL compatible license. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * + * Attention: iPhone device must be paired, otherwise it won't respond to our + * driver. For more info: http://giagio.com/wiki/moin.cgi/iPhoneEthernetDriver + * + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/usb.h> +#include <linux/workqueue.h> + +#define USB_VENDOR_APPLE        0x05ac +#define USB_PRODUCT_IPHONE      0x1290 +#define USB_PRODUCT_IPHONE_3G   0x1292 +#define USB_PRODUCT_IPHONE_3GS  0x1294 + +#define IPHETH_USBINTF_CLASS    255 +#define IPHETH_USBINTF_SUBCLASS 253 +#define IPHETH_USBINTF_PROTO    1 + +#define IPHETH_BUF_SIZE         1516 +#define IPHETH_TX_TIMEOUT       (5 * HZ) + +#define IPHETH_INTFNUM          2 +#define IPHETH_ALT_INTFNUM      1 + +#define IPHETH_CTRL_ENDP        0x00 +#define IPHETH_CTRL_BUF_SIZE    0x40 +#define IPHETH_CTRL_TIMEOUT     (5 * HZ) + +#define IPHETH_CMD_GET_MACADDR   0x00 +#define IPHETH_CMD_CARRIER_CHECK 0x45 + +#define IPHETH_CARRIER_CHECK_TIMEOUT round_jiffies_relative(1 * HZ) +#define IPHETH_CARRIER_ON       0x04 + +static struct usb_device_id ipheth_table[] = { +	{ USB_DEVICE_AND_INTERFACE_INFO( +		USB_VENDOR_APPLE, USB_PRODUCT_IPHONE, +		IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, +		IPHETH_USBINTF_PROTO) }, +	{ USB_DEVICE_AND_INTERFACE_INFO( +		USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_3G, +		IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, +		IPHETH_USBINTF_PROTO) }, +	{ USB_DEVICE_AND_INTERFACE_INFO( +		USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_3GS, +		IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, +		IPHETH_USBINTF_PROTO) }, +	{ } +}; +MODULE_DEVICE_TABLE(usb, ipheth_table); + +struct ipheth_device { +	struct usb_device *udev; +	struct usb_interface *intf; +	struct net_device *net; +	struct sk_buff *tx_skb; +	struct urb *tx_urb; +	struct urb *rx_urb; +	unsigned char *tx_buf; +	unsigned char *rx_buf; +	unsigned char *ctrl_buf; +	u8 bulk_in; +	u8 bulk_out; +	struct delayed_work carrier_work; +}; + +static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags); + +static int ipheth_alloc_urbs(struct ipheth_device *iphone) +{ +	struct urb *tx_urb = NULL; +	struct urb *rx_urb = NULL; +	u8 *tx_buf = NULL; +	u8 *rx_buf = NULL; + +	tx_urb = usb_alloc_urb(0, GFP_KERNEL); +	if (tx_urb == NULL) +		goto error_nomem; + +	rx_urb = usb_alloc_urb(0, GFP_KERNEL); +	if (rx_urb == NULL) +		goto free_tx_urb; + +	tx_buf = usb_buffer_alloc(iphone->udev, +				  IPHETH_BUF_SIZE, +				  GFP_KERNEL, +				  &tx_urb->transfer_dma); +	if (tx_buf == NULL) +		goto free_rx_urb; + +	rx_buf = usb_buffer_alloc(iphone->udev, +				  IPHETH_BUF_SIZE, +				  GFP_KERNEL, +				  &rx_urb->transfer_dma); +	if (rx_buf == NULL) +		goto free_tx_buf; + + +	iphone->tx_urb = tx_urb; +	iphone->rx_urb = rx_urb; +	iphone->tx_buf = tx_buf; +	iphone->rx_buf = rx_buf; +	return 0; + +free_tx_buf: +	usb_buffer_free(iphone->udev, IPHETH_BUF_SIZE, tx_buf, +			tx_urb->transfer_dma); +free_rx_urb: +	usb_free_urb(rx_urb); +free_tx_urb: +	usb_free_urb(tx_urb); +error_nomem: +	return -ENOMEM; +} + +static void ipheth_free_urbs(struct ipheth_device *iphone) +{ +	usb_buffer_free(iphone->udev, IPHETH_BUF_SIZE, iphone->rx_buf, +			iphone->rx_urb->transfer_dma); +	usb_buffer_free(iphone->udev, IPHETH_BUF_SIZE, iphone->tx_buf, +			iphone->tx_urb->transfer_dma); +	usb_free_urb(iphone->rx_urb); +	usb_free_urb(iphone->tx_urb); +} + +static void ipheth_kill_urbs(struct ipheth_device *dev) +{ +	usb_kill_urb(dev->tx_urb); +	usb_kill_urb(dev->rx_urb); +} + +static void ipheth_rcvbulk_callback(struct urb *urb) +{ +	struct ipheth_device *dev; +	struct sk_buff *skb; +	int status; +	char *buf; +	int len; + +	dev = urb->context; +	if (dev == NULL) +		return; + +	status = urb->status; +	switch (status) { +	case -ENOENT: +	case -ECONNRESET: +	case -ESHUTDOWN: +		return; +	case 0: +		break; +	default: +		err("%s: urb status: %d", __func__, urb->status); +		return; +	} + +	len = urb->actual_length; +	buf = urb->transfer_buffer; + +	skb = dev_alloc_skb(NET_IP_ALIGN + len); +	if (!skb) { +		err("%s: dev_alloc_skb: -ENOMEM", __func__); +		dev->net->stats.rx_dropped++; +		return; +	} + +	skb_reserve(skb, NET_IP_ALIGN); +	memcpy(skb_put(skb, len), buf + NET_IP_ALIGN, len - NET_IP_ALIGN); +	skb->dev = dev->net; +	skb->protocol = eth_type_trans(skb, dev->net); + +	dev->net->stats.rx_packets++; +	dev->net->stats.rx_bytes += len; + +	netif_rx(skb); +	ipheth_rx_submit(dev, GFP_ATOMIC); +} + +static void ipheth_sndbulk_callback(struct urb *urb) +{ +	struct ipheth_device *dev; + +	dev = urb->context; +	if (dev == NULL) +		return; + +	if (urb->status != 0 && +	    urb->status != -ENOENT && +	    urb->status != -ECONNRESET && +	    urb->status != -ESHUTDOWN) +		err("%s: urb status: %d", __func__, urb->status); + +	dev_kfree_skb_irq(dev->tx_skb); +	netif_wake_queue(dev->net); +} + +static int ipheth_carrier_set(struct ipheth_device *dev) +{ +	struct usb_device *udev = dev->udev; +	int retval; + +	retval = usb_control_msg(udev, +			usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP), +			IPHETH_CMD_CARRIER_CHECK, /* request */ +			0xc0, /* request type */ +			0x00, /* value */ +			0x02, /* index */ +			dev->ctrl_buf, IPHETH_CTRL_BUF_SIZE, +			IPHETH_CTRL_TIMEOUT); +	if (retval < 0) { +		err("%s: usb_control_msg: %d", __func__, retval); +		return retval; +	} + +	if (dev->ctrl_buf[0] == IPHETH_CARRIER_ON) +		netif_carrier_on(dev->net); +	else +		netif_carrier_off(dev->net); + +	return 0; +} + +static void ipheth_carrier_check_work(struct work_struct *work) +{ +	struct ipheth_device *dev = container_of(work, struct ipheth_device, +						 carrier_work.work); + +	ipheth_carrier_set(dev); +	schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT); +} + +static int ipheth_get_macaddr(struct ipheth_device *dev) +{ +	struct usb_device *udev = dev->udev; +	struct net_device *net = dev->net; +	int retval; + +	retval = usb_control_msg(udev, +				 usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP), +				 IPHETH_CMD_GET_MACADDR, /* request */ +				 0xc0, /* request type */ +				 0x00, /* value */ +				 0x02, /* index */ +				 dev->ctrl_buf, +				 IPHETH_CTRL_BUF_SIZE, +				 IPHETH_CTRL_TIMEOUT); +	if (retval < 0) { +		err("%s: usb_control_msg: %d", __func__, retval); +	} else if (retval < ETH_ALEN) { +		err("%s: usb_control_msg: short packet: %d bytes", +			__func__, retval); +		retval = -EINVAL; +	} else { +		memcpy(net->dev_addr, dev->ctrl_buf, ETH_ALEN); +		retval = 0; +	} + +	return retval; +} + +static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags) +{ +	struct usb_device *udev = dev->udev; +	int retval; + +	usb_fill_bulk_urb(dev->rx_urb, udev, +			  usb_rcvbulkpipe(udev, dev->bulk_in), +			  dev->rx_buf, IPHETH_BUF_SIZE, +			  ipheth_rcvbulk_callback, +			  dev); +	dev->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + +	retval = usb_submit_urb(dev->rx_urb, mem_flags); +	if (retval) +		err("%s: usb_submit_urb: %d", __func__, retval); +	return retval; +} + +static int ipheth_open(struct net_device *net) +{ +	struct ipheth_device *dev = netdev_priv(net); +	struct usb_device *udev = dev->udev; +	int retval = 0; + +	usb_set_interface(udev, IPHETH_INTFNUM, IPHETH_ALT_INTFNUM); + +	retval = ipheth_carrier_set(dev); +	if (retval) +		return retval; + +	retval = ipheth_rx_submit(dev, GFP_KERNEL); +	if (retval) +		return retval; + +	schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT); +	netif_start_queue(net); +	return retval; +} + +static int ipheth_close(struct net_device *net) +{ +	struct ipheth_device *dev = netdev_priv(net); + +	cancel_delayed_work_sync(&dev->carrier_work); +	netif_stop_queue(net); +	return 0; +} + +static int ipheth_tx(struct sk_buff *skb, struct net_device *net) +{ +	struct ipheth_device *dev = netdev_priv(net); +	struct usb_device *udev = dev->udev; +	int retval; + +	/* Paranoid */ +	if (skb->len > IPHETH_BUF_SIZE) { +		WARN(1, "%s: skb too large: %d bytes", __func__, skb->len); +		dev->net->stats.tx_dropped++; +		dev_kfree_skb_irq(skb); +		return NETDEV_TX_OK; +	} + +	memcpy(dev->tx_buf, skb->data, skb->len); +	if (skb->len < IPHETH_BUF_SIZE) +		memset(dev->tx_buf + skb->len, 0, IPHETH_BUF_SIZE - skb->len); + +	usb_fill_bulk_urb(dev->tx_urb, udev, +			  usb_sndbulkpipe(udev, dev->bulk_out), +			  dev->tx_buf, IPHETH_BUF_SIZE, +			  ipheth_sndbulk_callback, +			  dev); +	dev->tx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + +	retval = usb_submit_urb(dev->tx_urb, GFP_ATOMIC); +	if (retval) { +		err("%s: usb_submit_urb: %d", __func__, retval); +		dev->net->stats.tx_errors++; +		dev_kfree_skb_irq(skb); +	} else { +		dev->tx_skb = skb; + +		dev->net->stats.tx_packets++; +		dev->net->stats.tx_bytes += skb->len; +		netif_stop_queue(net); +	} + +	return NETDEV_TX_OK; +} + +static void ipheth_tx_timeout(struct net_device *net) +{ +	struct ipheth_device *dev = netdev_priv(net); + +	err("%s: TX timeout", __func__); +	dev->net->stats.tx_errors++; +	usb_unlink_urb(dev->tx_urb); +} + +static struct net_device_stats *ipheth_stats(struct net_device *net) +{ +	struct ipheth_device *dev = netdev_priv(net); +	return &dev->net->stats; +} + +static u32 ipheth_ethtool_op_get_link(struct net_device *net) +{ +	struct ipheth_device *dev = netdev_priv(net); +	return netif_carrier_ok(dev->net); +} + +static struct ethtool_ops ops = { +	.get_link = ipheth_ethtool_op_get_link +}; + +static const struct net_device_ops ipheth_netdev_ops = { +	.ndo_open = &ipheth_open, +	.ndo_stop = &ipheth_close, +	.ndo_start_xmit = &ipheth_tx, +	.ndo_tx_timeout = &ipheth_tx_timeout, +	.ndo_get_stats = &ipheth_stats, +}; + +static struct device_type ipheth_type = { +	.name	= "wwan", +}; + +static int ipheth_probe(struct usb_interface *intf, +			const struct usb_device_id *id) +{ +	struct usb_device *udev = interface_to_usbdev(intf); +	struct usb_host_interface *hintf; +	struct usb_endpoint_descriptor *endp; +	struct ipheth_device *dev; +	struct net_device *netdev; +	int i; +	int retval; + +	netdev = alloc_etherdev(sizeof(struct ipheth_device)); +	if (!netdev) +		return -ENOMEM; + +	netdev->netdev_ops = &ipheth_netdev_ops; +	netdev->watchdog_timeo = IPHETH_TX_TIMEOUT; +	strcpy(netdev->name, "wwan%d"); + +	dev = netdev_priv(netdev); +	dev->udev = udev; +	dev->net = netdev; +	dev->intf = intf; + +	/* Set up endpoints */ +	hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM); +	if (hintf == NULL) { +		retval = -ENODEV; +		err("Unable to find alternate settings interface"); +		goto err_endpoints; +	} + +	for (i = 0; i < hintf->desc.bNumEndpoints; i++) { +		endp = &hintf->endpoint[i].desc; +		if (usb_endpoint_is_bulk_in(endp)) +			dev->bulk_in = endp->bEndpointAddress; +		else if (usb_endpoint_is_bulk_out(endp)) +			dev->bulk_out = endp->bEndpointAddress; +	} +	if (!(dev->bulk_in && dev->bulk_out)) { +		retval = -ENODEV; +		err("Unable to find endpoints"); +		goto err_endpoints; +	} + +	dev->ctrl_buf = kmalloc(IPHETH_CTRL_BUF_SIZE, GFP_KERNEL); +	if (dev->ctrl_buf == NULL) { +		retval = -ENOMEM; +		goto err_alloc_ctrl_buf; +	} + +	retval = ipheth_get_macaddr(dev); +	if (retval) +		goto err_get_macaddr; + +	INIT_DELAYED_WORK(&dev->carrier_work, ipheth_carrier_check_work); + +	retval = ipheth_alloc_urbs(dev); +	if (retval) { +		err("error allocating urbs: %d", retval); +		goto err_alloc_urbs; +	} + +	usb_set_intfdata(intf, dev); + +	SET_NETDEV_DEV(netdev, &intf->dev); +	SET_ETHTOOL_OPS(netdev, &ops); +	SET_NETDEV_DEVTYPE(netdev, &ipheth_type); + +	retval = register_netdev(netdev); +	if (retval) { +		err("error registering netdev: %d", retval); +		retval = -EIO; +		goto err_register_netdev; +	} + +	dev_info(&intf->dev, "Apple iPhone USB Ethernet device attached\n"); +	return 0; + +err_register_netdev: +	ipheth_free_urbs(dev); +err_alloc_urbs: +err_get_macaddr: +err_alloc_ctrl_buf: +	kfree(dev->ctrl_buf); +err_endpoints: +	free_netdev(netdev); +	return retval; +} + +static void ipheth_disconnect(struct usb_interface *intf) +{ +	struct ipheth_device *dev; + +	dev = usb_get_intfdata(intf); +	if (dev != NULL) { +		unregister_netdev(dev->net); +		ipheth_kill_urbs(dev); +		ipheth_free_urbs(dev); +		kfree(dev->ctrl_buf); +		free_netdev(dev->net); +	} +	usb_set_intfdata(intf, NULL); +	dev_info(&intf->dev, "Apple iPhone USB Ethernet now disconnected\n"); +} + +static struct usb_driver ipheth_driver = { +	.name =		"ipheth", +	.probe =	ipheth_probe, +	.disconnect =	ipheth_disconnect, +	.id_table =	ipheth_table, +}; + +static int __init ipheth_init(void) +{ +	int retval; + +	retval = usb_register(&ipheth_driver); +	if (retval) { +		err("usb_register failed: %d", retval); +		return retval; +	} +	return 0; +} + +static void __exit ipheth_exit(void) +{ +	usb_deregister(&ipheth_driver); +} + +module_init(ipheth_init); +module_exit(ipheth_exit); + +MODULE_AUTHOR("Diego Giagio <diego@giagio.com>"); +MODULE_DESCRIPTION("Apple iPhone USB Ethernet driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index 52671ea043a..c4c334d9770 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -145,6 +145,7 @@ static struct usb_device_id usb_klsi_table[] = {  	{ USB_DEVICE(0x0707, 0x0100) }, /* SMC 2202USB */  	{ USB_DEVICE(0x07aa, 0x0001) }, /* Correga K.K. */  	{ USB_DEVICE(0x07b8, 0x4000) }, /* D-Link DU-E10 */ +	{ USB_DEVICE(0x07c9, 0xb010) }, /* Allied Telesyn AT-USB10 USB Ethernet Adapter */  	{ USB_DEVICE(0x0846, 0x1001) }, /* NetGear EA-101 */  	{ USB_DEVICE(0x0846, 0x1002) }, /* NetGear EA-101 */  	{ USB_DEVICE(0x085a, 0x0008) }, /* PortGear Ethernet Adapter */ diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index 70978219e98..9f24e3f871e 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -44,6 +44,7 @@  #include <linux/mii.h>  #include <linux/module.h>  #include <linux/netdevice.h> +#include <linux/slab.h>  #include <linux/usb.h>  #include <linux/usb/usbnet.h> diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c index bdcad45954a..961a8ed38d8 100644 --- a/drivers/net/usb/net1080.c +++ b/drivers/net/usb/net1080.c @@ -29,6 +29,7 @@  #include <linux/mii.h>  #include <linux/usb.h>  #include <linux/usb/usbnet.h> +#include <linux/slab.h>  #include <asm/unaligned.h> diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index 4ce331fb1e1..dd8a4adf48c 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -22,6 +22,7 @@  #include <linux/etherdevice.h>  #include <linux/ethtool.h>  #include <linux/workqueue.h> +#include <linux/slab.h>  #include <linux/mii.h>  #include <linux/usb.h>  #include <linux/usb/cdc.h> diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c new file mode 100644 index 00000000000..f1942d69a0d --- /dev/null +++ b/drivers/net/usb/sierra_net.c @@ -0,0 +1,1004 @@ +/* + * USB-to-WWAN Driver for Sierra Wireless modems + * + * Copyright (C) 2008, 2009, 2010 Paxton Smith, Matthew Safar, Rory Filer + *                          <linux@sierrawireless.com> + * + * Portions of this based on the cdc_ether driver by David Brownell (2003-2005) + * and Ole Andre Vadla Ravnas (ActiveSync) (2006). + * + * IMPORTANT DISCLAIMER: This driver is not commercially supported by + * Sierra Wireless. Use at your own risk. + * + * 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 + */ + +#define DRIVER_VERSION "v.2.0" +#define DRIVER_AUTHOR "Paxton Smith, Matthew Safar, Rory Filer" +#define DRIVER_DESC "USB-to-WWAN Driver for Sierra Wireless modems" +static const char driver_name[] = "sierra_net"; + +/* if defined debug messages enabled */ +/*#define	DEBUG*/ + +#include <linux/module.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/mii.h> +#include <linux/sched.h> +#include <linux/timer.h> +#include <linux/usb.h> +#include <linux/usb/cdc.h> +#include <net/ip.h> +#include <net/udp.h> +#include <asm/unaligned.h> +#include <linux/usb/usbnet.h> + +#define SWI_USB_REQUEST_GET_FW_ATTR	0x06 +#define SWI_GET_FW_ATTR_MASK		0x08 + +/* atomic counter partially included in MAC address to make sure 2 devices + * do not end up with the same MAC - concept breaks in case of > 255 ifaces + */ +static	atomic_t iface_counter = ATOMIC_INIT(0); + +/* + * SYNC Timer Delay definition used to set the expiry time + */ +#define SIERRA_NET_SYNCDELAY (2*HZ) + +/* Max. MTU supported. The modem buffers are limited to 1500 */ +#define SIERRA_NET_MAX_SUPPORTED_MTU	1500 + +/* The SIERRA_NET_USBCTL_BUF_LEN defines a buffer size allocated for control + * message reception ... and thus the max. received packet. + * (May be the cause for parse_hip returning -EINVAL) + */ +#define SIERRA_NET_USBCTL_BUF_LEN	1024 + +/* list of interface numbers - used for constructing interface lists */ +struct sierra_net_iface_info { +	const u32 infolen;	/* number of interface numbers on list */ +	const u8  *ifaceinfo;	/* pointer to the array holding the numbers */ +}; + +struct sierra_net_info_data { +	u16 rx_urb_size; +	struct sierra_net_iface_info whitelist; +}; + +/* Private data structure */ +struct sierra_net_data { + +	u8 ethr_hdr_tmpl[ETH_HLEN]; /* ethernet header template for rx'd pkts */ + +	u16 link_up;		/* air link up or down */ +	u8 tx_hdr_template[4];	/* part of HIP hdr for tx'd packets */ + +	u8 sync_msg[4];		/* SYNC message */ +	u8 shdwn_msg[4];	/* Shutdown message */ + +	/* Backpointer to the container */ +	struct usbnet *usbnet; + +	u8 ifnum;	/* interface number */ + +/* Bit masks, must be a power of 2 */ +#define SIERRA_NET_EVENT_RESP_AVAIL    0x01 +#define SIERRA_NET_TIMER_EXPIRY        0x02 +	unsigned long kevent_flags; +	struct work_struct sierra_net_kevent; +	struct timer_list sync_timer; /* For retrying SYNC sequence */ +}; + +struct param { +	int is_present; +	union { +		void  *ptr; +		u32    dword; +		u16    word; +		u8     byte; +	}; +}; + +/* HIP message type */ +#define SIERRA_NET_HIP_EXTENDEDID	0x7F +#define SIERRA_NET_HIP_HSYNC_ID		0x60	/* Modem -> host */ +#define SIERRA_NET_HIP_RESTART_ID	0x62	/* Modem -> host */ +#define SIERRA_NET_HIP_MSYNC_ID		0x20	/* Host -> modem */ +#define SIERRA_NET_HIP_SHUTD_ID		0x26	/* Host -> modem */ + +#define SIERRA_NET_HIP_EXT_IP_IN_ID   0x0202 +#define SIERRA_NET_HIP_EXT_IP_OUT_ID  0x0002 + +/* 3G UMTS Link Sense Indication definitions */ +#define SIERRA_NET_HIP_LSI_UMTSID	0x78 + +/* Reverse Channel Grant Indication HIP message */ +#define SIERRA_NET_HIP_RCGI		0x64 + +/* LSI Protocol types */ +#define SIERRA_NET_PROTOCOL_UMTS      0x01 +/* LSI Coverage */ +#define SIERRA_NET_COVERAGE_NONE      0x00 +#define SIERRA_NET_COVERAGE_NOPACKET  0x01 + +/* LSI Session */ +#define SIERRA_NET_SESSION_IDLE       0x00 +/* LSI Link types */ +#define SIERRA_NET_AS_LINK_TYPE_IPv4  0x00 + +struct lsi_umts { +	u8 protocol; +	u8 unused1; +	__be16 length; +	/* eventually use a union for the rest - assume umts for now */ +	u8 coverage; +	u8 unused2[41]; +	u8 session_state; +	u8 unused3[33]; +	u8 link_type; +	u8 pdp_addr_len; /* NW-supplied PDP address len */ +	u8 pdp_addr[16]; /* NW-supplied PDP address (bigendian)) */ +	u8 unused4[23]; +	u8 dns1_addr_len; /* NW-supplied 1st DNS address len (bigendian) */ +	u8 dns1_addr[16]; /* NW-supplied 1st DNS address */ +	u8 dns2_addr_len; /* NW-supplied 2nd DNS address len */ +	u8 dns2_addr[16]; /* NW-supplied 2nd DNS address (bigendian)*/ +	u8 wins1_addr_len; /* NW-supplied 1st Wins address len */ +	u8 wins1_addr[16]; /* NW-supplied 1st Wins address (bigendian)*/ +	u8 wins2_addr_len; /* NW-supplied 2nd Wins address len */ +	u8 wins2_addr[16]; /* NW-supplied 2nd Wins address (bigendian) */ +	u8 unused5[4]; +	u8 gw_addr_len; /* NW-supplied GW address len */ +	u8 gw_addr[16]; /* NW-supplied GW address (bigendian) */ +	u8 reserved[8]; +} __attribute__ ((packed)); + +#define SIERRA_NET_LSI_COMMON_LEN      4 +#define SIERRA_NET_LSI_UMTS_LEN        (sizeof(struct lsi_umts)) +#define SIERRA_NET_LSI_UMTS_STATUS_LEN \ +	(SIERRA_NET_LSI_UMTS_LEN - SIERRA_NET_LSI_COMMON_LEN) + +/* Forward definitions */ +static void sierra_sync_timer(unsigned long syncdata); +static int sierra_net_change_mtu(struct net_device *net, int new_mtu); + +/* Our own net device operations structure */ +static const struct net_device_ops sierra_net_device_ops = { +	.ndo_open               = usbnet_open, +	.ndo_stop               = usbnet_stop, +	.ndo_start_xmit         = usbnet_start_xmit, +	.ndo_tx_timeout         = usbnet_tx_timeout, +	.ndo_change_mtu         = sierra_net_change_mtu, +	.ndo_set_mac_address    = eth_mac_addr, +	.ndo_validate_addr      = eth_validate_addr, +}; + +/* get private data associated with passed in usbnet device */ +static inline struct sierra_net_data *sierra_net_get_private(struct usbnet *dev) +{ +	return (struct sierra_net_data *)dev->data[0]; +} + +/* set private data associated with passed in usbnet device */ +static inline void sierra_net_set_private(struct usbnet *dev, +			struct sierra_net_data *priv) +{ +	dev->data[0] = (unsigned long)priv; +} + +/* is packet IPv4 */ +static inline int is_ip(struct sk_buff *skb) +{ +	return (skb->protocol == cpu_to_be16(ETH_P_IP)); +} + +/* + * check passed in packet and make sure that: + *  - it is linear (no scatter/gather) + *  - it is ethernet (mac_header properly set) + */ +static int check_ethip_packet(struct sk_buff *skb, struct usbnet *dev) +{ +	skb_reset_mac_header(skb); /* ethernet header */ + +	if (skb_is_nonlinear(skb)) { +		netdev_err(dev->net, "Non linear buffer-dropping\n"); +		return 0; +	} + +	if (!pskb_may_pull(skb, ETH_HLEN)) +		return 0; +	skb->protocol = eth_hdr(skb)->h_proto; + +	return 1; +} + +static const u8 *save16bit(struct param *p, const u8 *datap) +{ +	p->is_present = 1; +	p->word = get_unaligned_be16(datap); +	return datap + sizeof(p->word); +} + +static const u8 *save8bit(struct param *p, const u8 *datap) +{ +	p->is_present = 1; +	p->byte = *datap; +	return datap + sizeof(p->byte); +} + +/*----------------------------------------------------------------------------* + *                              BEGIN HIP                                     * + *----------------------------------------------------------------------------*/ +/* HIP header */ +#define SIERRA_NET_HIP_HDR_LEN 4 +/* Extended HIP header */ +#define SIERRA_NET_HIP_EXT_HDR_LEN 6 + +struct hip_hdr { +	int    hdrlen; +	struct param payload_len; +	struct param msgid; +	struct param msgspecific; +	struct param extmsgid; +}; + +static int parse_hip(const u8 *buf, const u32 buflen, struct hip_hdr *hh) +{ +	const u8 *curp = buf; +	int    padded; + +	if (buflen < SIERRA_NET_HIP_HDR_LEN) +		return -EPROTO; + +	curp = save16bit(&hh->payload_len, curp); +	curp = save8bit(&hh->msgid, curp); +	curp = save8bit(&hh->msgspecific, curp); + +	padded = hh->msgid.byte & 0x80; +	hh->msgid.byte &= 0x7F;			/* 7 bits */ + +	hh->extmsgid.is_present = (hh->msgid.byte == SIERRA_NET_HIP_EXTENDEDID); +	if (hh->extmsgid.is_present) { +		if (buflen < SIERRA_NET_HIP_EXT_HDR_LEN) +			return -EPROTO; + +		hh->payload_len.word &= 0x3FFF; /* 14 bits */ + +		curp = save16bit(&hh->extmsgid, curp); +		hh->extmsgid.word &= 0x03FF;	/* 10 bits */ + +		hh->hdrlen = SIERRA_NET_HIP_EXT_HDR_LEN; +	} else { +		hh->payload_len.word &= 0x07FF;	/* 11 bits */ +		hh->hdrlen = SIERRA_NET_HIP_HDR_LEN; +	} + +	if (padded) { +		hh->hdrlen++; +		hh->payload_len.word--; +	} + +	/* if real packet shorter than the claimed length */ +	if (buflen < (hh->hdrlen + hh->payload_len.word)) +		return -EINVAL; + +	return 0; +} + +static void build_hip(u8 *buf, const u16 payloadlen, +		struct sierra_net_data *priv) +{ +	/* the following doesn't have the full functionality. We +	 * currently build only one kind of header, so it is faster this way +	 */ +	put_unaligned_be16(payloadlen, buf); +	memcpy(buf+2, priv->tx_hdr_template, sizeof(priv->tx_hdr_template)); +} +/*----------------------------------------------------------------------------* + *                              END HIP                                       * + *----------------------------------------------------------------------------*/ + +static int sierra_net_send_cmd(struct usbnet *dev, +		u8 *cmd, int cmdlen, const char * cmd_name) +{ +	struct sierra_net_data *priv = sierra_net_get_private(dev); +	int  status; + +	status = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), +			USB_CDC_SEND_ENCAPSULATED_COMMAND, +			USB_DIR_OUT|USB_TYPE_CLASS|USB_RECIP_INTERFACE,	0, +			priv->ifnum, cmd, cmdlen, USB_CTRL_SET_TIMEOUT); + +	if (status != cmdlen && status != -ENODEV) +		netdev_err(dev->net, "Submit %s failed %d\n", cmd_name, status); + +	return status; +} + +static int sierra_net_send_sync(struct usbnet *dev) +{ +	int  status; +	struct sierra_net_data *priv = sierra_net_get_private(dev); + +	dev_dbg(&dev->udev->dev, "%s", __func__); + +	status = sierra_net_send_cmd(dev, priv->sync_msg, +			sizeof(priv->sync_msg), "SYNC"); + +	return status; +} + +static void sierra_net_set_ctx_index(struct sierra_net_data *priv, u8 ctx_ix) +{ +	dev_dbg(&(priv->usbnet->udev->dev), "%s %d", __func__, ctx_ix); +	priv->tx_hdr_template[0] = 0x3F; +	priv->tx_hdr_template[1] = ctx_ix; +	*((u16 *)&priv->tx_hdr_template[2]) = +		cpu_to_be16(SIERRA_NET_HIP_EXT_IP_OUT_ID); +} + +static inline int sierra_net_is_valid_addrlen(u8 len) +{ +	return (len == sizeof(struct in_addr)); +} + +static int sierra_net_parse_lsi(struct usbnet *dev, char *data, int datalen) +{ +	struct lsi_umts *lsi = (struct lsi_umts *)data; + +	if (datalen < sizeof(struct lsi_umts)) { +		netdev_err(dev->net, "%s: Data length %d, exp %Zu\n", +				__func__, datalen, +				sizeof(struct lsi_umts)); +		return -1; +	} + +	if (lsi->length != cpu_to_be16(SIERRA_NET_LSI_UMTS_STATUS_LEN)) { +		netdev_err(dev->net, "%s: LSI_UMTS_STATUS_LEN %d, exp %u\n", +				__func__, be16_to_cpu(lsi->length), +				(u32)SIERRA_NET_LSI_UMTS_STATUS_LEN); +		return -1; +	} + +	/* Validate the protocol  - only support UMTS for now */ +	if (lsi->protocol != SIERRA_NET_PROTOCOL_UMTS) { +		netdev_err(dev->net, "Protocol unsupported, 0x%02x\n", +			lsi->protocol); +		return -1; +	} + +	/* Validate the link type */ +	if (lsi->link_type != SIERRA_NET_AS_LINK_TYPE_IPv4) { +		netdev_err(dev->net, "Link type unsupported: 0x%02x\n", +			lsi->link_type); +		return -1; +	} + +	/* Validate the coverage */ +	if (lsi->coverage == SIERRA_NET_COVERAGE_NONE +	   || lsi->coverage == SIERRA_NET_COVERAGE_NOPACKET) { +		netdev_err(dev->net, "No coverage, 0x%02x\n", lsi->coverage); +		return 0; +	} + +	/* Validate the session state */ +	if (lsi->session_state == SIERRA_NET_SESSION_IDLE) { +		netdev_err(dev->net, "Session idle, 0x%02x\n", +			lsi->session_state); +		return 0; +	} + +	/* Set link_sense true */ +	return 1; +} + +static void sierra_net_handle_lsi(struct usbnet *dev, char *data, +		struct hip_hdr	*hh) +{ +	struct sierra_net_data *priv = sierra_net_get_private(dev); +	int link_up; + +	link_up = sierra_net_parse_lsi(dev, data + hh->hdrlen, +					hh->payload_len.word); +	if (link_up < 0) { +		netdev_err(dev->net, "Invalid LSI\n"); +		return; +	} +	if (link_up) { +		sierra_net_set_ctx_index(priv, hh->msgspecific.byte); +		priv->link_up = 1; +		netif_carrier_on(dev->net); +	} else { +		priv->link_up = 0; +		netif_carrier_off(dev->net); +	} +} + +static void sierra_net_dosync(struct usbnet *dev) +{ +	int status; +	struct sierra_net_data *priv = sierra_net_get_private(dev); + +	dev_dbg(&dev->udev->dev, "%s", __func__); + +	/* tell modem we are ready */ +	status = sierra_net_send_sync(dev); +	if (status < 0) +		netdev_err(dev->net, +			"Send SYNC failed, status %d\n", status); +	status = sierra_net_send_sync(dev); +	if (status < 0) +		netdev_err(dev->net, +			"Send SYNC failed, status %d\n", status); + +	/* Now, start a timer and make sure we get the Restart Indication */ +	priv->sync_timer.function = sierra_sync_timer; +	priv->sync_timer.data = (unsigned long) dev; +	priv->sync_timer.expires = jiffies + SIERRA_NET_SYNCDELAY; +	add_timer(&priv->sync_timer); +} + +static void sierra_net_kevent(struct work_struct *work) +{ +	struct sierra_net_data *priv = +		container_of(work, struct sierra_net_data, sierra_net_kevent); +	struct usbnet *dev = priv->usbnet; +	int  len; +	int  err; +	u8  *buf; +	u8   ifnum; + +	if (test_bit(SIERRA_NET_EVENT_RESP_AVAIL, &priv->kevent_flags)) { +		clear_bit(SIERRA_NET_EVENT_RESP_AVAIL, &priv->kevent_flags); + +		/* Query the modem for the LSI message */ +		buf = kzalloc(SIERRA_NET_USBCTL_BUF_LEN, GFP_KERNEL); +		if (!buf) { +			netdev_err(dev->net, +				"failed to allocate buf for LS msg\n"); +			return; +		} +		ifnum = priv->ifnum; +		len = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), +				USB_CDC_GET_ENCAPSULATED_RESPONSE, +				USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE, +				0, ifnum, buf, SIERRA_NET_USBCTL_BUF_LEN, +				USB_CTRL_SET_TIMEOUT); + +		if (len < 0) { +			netdev_err(dev->net, +				"usb_control_msg failed, status %d\n", len); +		} else { +			struct hip_hdr	hh; + +			dev_dbg(&dev->udev->dev, "%s: Received status message," +				" %04x bytes", __func__, len); + +			err = parse_hip(buf, len, &hh); +			if (err) { +				netdev_err(dev->net, "%s: Bad packet," +					" parse result %d\n", __func__, err); +				kfree(buf); +				return; +			} + +			/* Validate packet length */ +			if (len != hh.hdrlen + hh.payload_len.word) { +				netdev_err(dev->net, "%s: Bad packet, received" +					" %d, expected %d\n",	__func__, len, +					hh.hdrlen + hh.payload_len.word); +				kfree(buf); +				return; +			} + +			/* Switch on received message types */ +			switch (hh.msgid.byte) { +			case SIERRA_NET_HIP_LSI_UMTSID: +				dev_dbg(&dev->udev->dev, "LSI for ctx:%d", +					hh.msgspecific.byte); +				sierra_net_handle_lsi(dev, buf, &hh); +				break; +			case SIERRA_NET_HIP_RESTART_ID: +				dev_dbg(&dev->udev->dev, "Restart reported: %d," +						" stopping sync timer", +						hh.msgspecific.byte); +				/* Got sync resp - stop timer & clear mask */ +				del_timer_sync(&priv->sync_timer); +				clear_bit(SIERRA_NET_TIMER_EXPIRY, +					  &priv->kevent_flags); +				break; +			case SIERRA_NET_HIP_HSYNC_ID: +				dev_dbg(&dev->udev->dev, "SYNC received"); +				err = sierra_net_send_sync(dev); +				if (err < 0) +					netdev_err(dev->net, +						"Send SYNC failed %d\n", err); +				break; +			case SIERRA_NET_HIP_EXTENDEDID: +				netdev_err(dev->net, "Unrecognized HIP msg, " +					"extmsgid 0x%04x\n", hh.extmsgid.word); +				break; +			case SIERRA_NET_HIP_RCGI: +				/* Ignored */ +				break; +			default: +				netdev_err(dev->net, "Unrecognized HIP msg, " +					"msgid 0x%02x\n", hh.msgid.byte); +				break; +			} +		} +		kfree(buf); +	} +	/* The sync timer bit might be set */ +	if (test_bit(SIERRA_NET_TIMER_EXPIRY, &priv->kevent_flags)) { +		clear_bit(SIERRA_NET_TIMER_EXPIRY, &priv->kevent_flags); +		dev_dbg(&dev->udev->dev, "Deferred sync timer expiry"); +		sierra_net_dosync(priv->usbnet); +	} + +	if (priv->kevent_flags) +		dev_dbg(&dev->udev->dev, "sierra_net_kevent done, " +			"kevent_flags = 0x%lx", priv->kevent_flags); +} + +static void sierra_net_defer_kevent(struct usbnet *dev, int work) +{ +	struct sierra_net_data *priv = sierra_net_get_private(dev); + +	set_bit(work, &priv->kevent_flags); +	schedule_work(&priv->sierra_net_kevent); +} + +/* + * Sync Retransmit Timer Handler. On expiry, kick the work queue + */ +void sierra_sync_timer(unsigned long syncdata) +{ +	struct usbnet *dev = (struct usbnet *)syncdata; + +	dev_dbg(&dev->udev->dev, "%s", __func__); +	/* Kick the tasklet */ +	sierra_net_defer_kevent(dev, SIERRA_NET_TIMER_EXPIRY); +} + +static void sierra_net_status(struct usbnet *dev, struct urb *urb) +{ +	struct usb_cdc_notification *event; + +	dev_dbg(&dev->udev->dev, "%s", __func__); + +	if (urb->actual_length < sizeof *event) +		return; + +	/* Add cases to handle other standard notifications. */ +	event = urb->transfer_buffer; +	switch (event->bNotificationType) { +	case USB_CDC_NOTIFY_NETWORK_CONNECTION: +	case USB_CDC_NOTIFY_SPEED_CHANGE: +		/* USB 305 sends those */ +		break; +	case USB_CDC_NOTIFY_RESPONSE_AVAILABLE: +		sierra_net_defer_kevent(dev, SIERRA_NET_EVENT_RESP_AVAIL); +		break; +	default: +		netdev_err(dev->net, ": unexpected notification %02x!\n", +				event->bNotificationType); +		break; +	} +} + +static void sierra_net_get_drvinfo(struct net_device *net, +		struct ethtool_drvinfo *info) +{ +	/* Inherit standard device info */ +	usbnet_get_drvinfo(net, info); +	strncpy(info->driver, driver_name, sizeof info->driver); +	strncpy(info->version, DRIVER_VERSION, sizeof info->version); +} + +static u32 sierra_net_get_link(struct net_device *net) +{ +	struct usbnet *dev = netdev_priv(net); +	/* Report link is down whenever the interface is down */ +	return sierra_net_get_private(dev)->link_up && netif_running(net); +} + +static struct ethtool_ops sierra_net_ethtool_ops = { +	.get_drvinfo = sierra_net_get_drvinfo, +	.get_link = sierra_net_get_link, +	.get_msglevel = usbnet_get_msglevel, +	.set_msglevel = usbnet_set_msglevel, +	.get_settings = usbnet_get_settings, +	.set_settings = usbnet_set_settings, +	.nway_reset = usbnet_nway_reset, +}; + +/* MTU can not be more than 1500 bytes, enforce it. */ +static int sierra_net_change_mtu(struct net_device *net, int new_mtu) +{ +	if (new_mtu > SIERRA_NET_MAX_SUPPORTED_MTU) +		return -EINVAL; + +	return usbnet_change_mtu(net, new_mtu); +} + +static int is_whitelisted(const u8 ifnum, +			const struct sierra_net_iface_info *whitelist) +{ +	if (whitelist) { +		const u8 *list = whitelist->ifaceinfo; +		int i; + +		for (i = 0; i < whitelist->infolen; i++) { +			if (list[i] == ifnum) +				return 1; +		} +	} +	return 0; +} + +static int sierra_net_get_fw_attr(struct usbnet *dev, u16 *datap) +{ +	int result = 0; +	u16 *attrdata; + +	attrdata = kmalloc(sizeof(*attrdata), GFP_KERNEL); +	if (!attrdata) +		return -ENOMEM; + +	result = usb_control_msg( +			dev->udev, +			usb_rcvctrlpipe(dev->udev, 0), +			/* _u8 vendor specific request */ +			SWI_USB_REQUEST_GET_FW_ATTR, +			USB_DIR_IN | USB_TYPE_VENDOR,	/* __u8 request type */ +			0x0000,		/* __u16 value not used */ +			0x0000,		/* __u16 index  not used */ +			attrdata,	/* char *data */ +			sizeof(*attrdata),		/* __u16 size */ +			USB_CTRL_SET_TIMEOUT);	/* int timeout */ + +	if (result < 0) { +		kfree(attrdata); +		return -EIO; +	} + +	*datap = *attrdata; + +	kfree(attrdata); +	return result; +} + +/* + * collects the bulk endpoints, the status endpoint. + */ +static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf) +{ +	u8	ifacenum; +	u8	numendpoints; +	u16	fwattr = 0; +	int	status; +	struct ethhdr *eth; +	struct sierra_net_data *priv; +	static const u8 sync_tmplate[sizeof(priv->sync_msg)] = { +		0x00, 0x00, SIERRA_NET_HIP_MSYNC_ID, 0x00}; +	static const u8 shdwn_tmplate[sizeof(priv->shdwn_msg)] = { +		0x00, 0x00, SIERRA_NET_HIP_SHUTD_ID, 0x00}; + +	struct sierra_net_info_data *data = +			(struct sierra_net_info_data *)dev->driver_info->data; + +	dev_dbg(&dev->udev->dev, "%s", __func__); + +	ifacenum = intf->cur_altsetting->desc.bInterfaceNumber; +	/* We only accept certain interfaces */ +	if (!is_whitelisted(ifacenum, &data->whitelist)) { +		dev_dbg(&dev->udev->dev, "Ignoring interface: %d", ifacenum); +		return -ENODEV; +	} +	numendpoints = intf->cur_altsetting->desc.bNumEndpoints; +	/* We have three endpoints, bulk in and out, and a status */ +	if (numendpoints != 3) { +		dev_err(&dev->udev->dev, "Expected 3 endpoints, found: %d", +			numendpoints); +		return -ENODEV; +	} +	/* Status endpoint set in usbnet_get_endpoints() */ +	dev->status = NULL; +	status = usbnet_get_endpoints(dev, intf); +	if (status < 0) { +		dev_err(&dev->udev->dev, "Error in usbnet_get_endpoints (%d)", +			status); +		return -ENODEV; +	} +	/* Initialize sierra private data */ +	priv = kzalloc(sizeof *priv, GFP_KERNEL); +	if (!priv) { +		dev_err(&dev->udev->dev, "No memory"); +		return -ENOMEM; +	} + +	priv->usbnet = dev; +	priv->ifnum = ifacenum; +	dev->net->netdev_ops = &sierra_net_device_ops; + +	/* change MAC addr to include, ifacenum, and to be unique */ +	dev->net->dev_addr[ETH_ALEN-2] = atomic_inc_return(&iface_counter); +	dev->net->dev_addr[ETH_ALEN-1] = ifacenum; + +	/* we will have to manufacture ethernet headers, prepare template */ +	eth = (struct ethhdr *)priv->ethr_hdr_tmpl; +	memcpy(ð->h_dest, dev->net->dev_addr, ETH_ALEN); +	eth->h_proto = cpu_to_be16(ETH_P_IP); + +	/* prepare shutdown message template */ +	memcpy(priv->shdwn_msg, shdwn_tmplate, sizeof(priv->shdwn_msg)); +	/* set context index initially to 0 - prepares tx hdr template */ +	sierra_net_set_ctx_index(priv, 0); + +	/* decrease the rx_urb_size and max_tx_size to 4k on USB 1.1 */ +	dev->rx_urb_size  = data->rx_urb_size; +	if (dev->udev->speed != USB_SPEED_HIGH) +		dev->rx_urb_size  = min_t(size_t, 4096, data->rx_urb_size); + +	dev->net->hard_header_len += SIERRA_NET_HIP_EXT_HDR_LEN; +	dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; + +	/* Set up the netdev */ +	dev->net->flags |= IFF_NOARP; +	dev->net->ethtool_ops = &sierra_net_ethtool_ops; +	netif_carrier_off(dev->net); + +	sierra_net_set_private(dev, priv); + +	priv->kevent_flags = 0; + +	/* Use the shared workqueue */ +	INIT_WORK(&priv->sierra_net_kevent, sierra_net_kevent); + +	/* Only need to do this once */ +	init_timer(&priv->sync_timer); + +	/* verify fw attributes */ +	status = sierra_net_get_fw_attr(dev, &fwattr); +	dev_dbg(&dev->udev->dev, "Fw attr: %x\n", fwattr); + +	/* test whether firmware supports DHCP */ +	if (!(status == sizeof(fwattr) && (fwattr & SWI_GET_FW_ATTR_MASK))) { +		/* found incompatible firmware version */ +		dev_err(&dev->udev->dev, "Incompatible driver and firmware" +			" versions\n"); +		kfree(priv); +		return -ENODEV; +	} +	/* prepare sync message from template */ +	memcpy(priv->sync_msg, sync_tmplate, sizeof(priv->sync_msg)); + +	/* initiate the sync sequence */ +	sierra_net_dosync(dev); + +	return 0; +} + +static void sierra_net_unbind(struct usbnet *dev, struct usb_interface *intf) +{ +	int status; +	struct sierra_net_data *priv = sierra_net_get_private(dev); + +	dev_dbg(&dev->udev->dev, "%s", __func__); + +	/* Kill the timer then flush the work queue */ +	del_timer_sync(&priv->sync_timer); + +	flush_scheduled_work(); + +	/* tell modem we are going away */ +	status = sierra_net_send_cmd(dev, priv->shdwn_msg, +			sizeof(priv->shdwn_msg), "Shutdown"); +	if (status < 0) +		netdev_err(dev->net, +			"usb_control_msg failed, status %d\n", status); + +	sierra_net_set_private(dev, NULL); + +	kfree(priv); +} + +static struct sk_buff *sierra_net_skb_clone(struct usbnet *dev, +		struct sk_buff *skb, int len) +{ +	struct sk_buff *new_skb; + +	/* clone skb */ +	new_skb = skb_clone(skb, GFP_ATOMIC); + +	/* remove len bytes from original */ +	skb_pull(skb, len); + +	/* trim next packet to it's length */ +	if (new_skb) { +		skb_trim(new_skb, len); +	} else { +		if (netif_msg_rx_err(dev)) +			netdev_err(dev->net, "failed to get skb\n"); +		dev->net->stats.rx_dropped++; +	} + +	return new_skb; +} + +/* ---------------------------- Receive data path ----------------------*/ +static int sierra_net_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ +	int err; +	struct hip_hdr  hh; +	struct sk_buff *new_skb; + +	dev_dbg(&dev->udev->dev, "%s", __func__); + +	/* could contain multiple packets */ +	while (likely(skb->len)) { +		err = parse_hip(skb->data, skb->len, &hh); +		if (err) { +			if (netif_msg_rx_err(dev)) +				netdev_err(dev->net, "Invalid HIP header %d\n", +					err); +			/* dev->net->stats.rx_errors incremented by caller */ +			dev->net->stats.rx_length_errors++; +			return 0; +		} + +		/* Validate Extended HIP header */ +		if (!hh.extmsgid.is_present +		    || hh.extmsgid.word != SIERRA_NET_HIP_EXT_IP_IN_ID) { +			if (netif_msg_rx_err(dev)) +				netdev_err(dev->net, "HIP/ETH: Invalid pkt\n"); + +			dev->net->stats.rx_frame_errors++; +			/* dev->net->stats.rx_errors incremented by caller */; +			return 0; +		} + +		skb_pull(skb, hh.hdrlen); + +		/* We are going to accept this packet, prepare it */ +		memcpy(skb->data, sierra_net_get_private(dev)->ethr_hdr_tmpl, +			ETH_HLEN); + +		/* Last packet in batch handled by usbnet */ +		if (hh.payload_len.word == skb->len) +			return 1; + +		new_skb = sierra_net_skb_clone(dev, skb, hh.payload_len.word); +		if (new_skb) +			usbnet_skb_return(dev, new_skb); + +	} /* while */ + +	return 0; +} + +/* ---------------------------- Transmit data path ----------------------*/ +struct sk_buff *sierra_net_tx_fixup(struct usbnet *dev, struct sk_buff *skb, +		gfp_t flags) +{ +	struct sierra_net_data *priv = sierra_net_get_private(dev); +	u16 len; +	bool need_tail; + +	dev_dbg(&dev->udev->dev, "%s", __func__); +	if (priv->link_up && check_ethip_packet(skb, dev) && is_ip(skb)) { +		/* enough head room as is? */ +		if (SIERRA_NET_HIP_EXT_HDR_LEN <= skb_headroom(skb)) { +			/* Save the Eth/IP length and set up HIP hdr */ +			len = skb->len; +			skb_push(skb, SIERRA_NET_HIP_EXT_HDR_LEN); +			/* Handle ZLP issue */ +			need_tail = ((len + SIERRA_NET_HIP_EXT_HDR_LEN) +				% dev->maxpacket == 0); +			if (need_tail) { +				if (unlikely(skb_tailroom(skb) == 0)) { +					netdev_err(dev->net, "tx_fixup:" +						"no room for packet\n"); +					dev_kfree_skb_any(skb); +					return NULL; +				} else { +					skb->data[skb->len] = 0; +					__skb_put(skb, 1); +					len = len + 1; +				} +			} +			build_hip(skb->data, len, priv); +			return skb; +		} else { +			/* +			 * compensate in the future if necessary +			 */ +			netdev_err(dev->net, "tx_fixup: no room for HIP\n"); +		} /* headroom */ +	} + +	if (!priv->link_up) +		dev->net->stats.tx_carrier_errors++; + +	/* tx_dropped incremented by usbnet */ + +	/* filter the packet out, release it  */ +	dev_kfree_skb_any(skb); +	return NULL; +} + +static const u8 sierra_net_ifnum_list[] = { 7, 10, 11 }; +static const struct sierra_net_info_data sierra_net_info_data_68A3 = { +	.rx_urb_size = 8 * 1024, +	.whitelist = { +		.infolen = ARRAY_SIZE(sierra_net_ifnum_list), +		.ifaceinfo = sierra_net_ifnum_list +	} +}; + +static const struct driver_info sierra_net_info_68A3 = { +	.description = "Sierra Wireless USB-to-WWAN Modem", +	.flags = FLAG_WWAN | FLAG_SEND_ZLP, +	.bind = sierra_net_bind, +	.unbind = sierra_net_unbind, +	.status = sierra_net_status, +	.rx_fixup = sierra_net_rx_fixup, +	.tx_fixup = sierra_net_tx_fixup, +	.data = (unsigned long)&sierra_net_info_data_68A3, +}; + +static const struct usb_device_id products[] = { +	{USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless USB-to-WWAN modem */ +	.driver_info = (unsigned long) &sierra_net_info_68A3}, + +	{}, /* last item */ +}; +MODULE_DEVICE_TABLE(usb, products); + +/* We are based on usbnet, so let it handle the USB driver specifics */ +static struct usb_driver sierra_net_driver = { +	.name = "sierra_net", +	.id_table = products, +	.probe = usbnet_probe, +	.disconnect = usbnet_disconnect, +	.suspend = usbnet_suspend, +	.resume = usbnet_resume, +	.no_dynamic_id = 1, +}; + +static int __init sierra_net_init(void) +{ +	BUILD_BUG_ON(FIELD_SIZEOF(struct usbnet, data) +				< sizeof(struct cdc_state)); + +	return usb_register(&sierra_net_driver); +} + +static void __exit sierra_net_exit(void) +{ +	usb_deregister(&sierra_net_driver); +} + +module_exit(sierra_net_exit); +module_init(sierra_net_init); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c new file mode 100644 index 00000000000..35b98b1b79e --- /dev/null +++ b/drivers/net/usb/smsc75xx.c @@ -0,0 +1,1289 @@ + /*************************************************************************** + * + * Copyright (C) 2007-2010 SMSC + * + * 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/kmod.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/mii.h> +#include <linux/usb.h> +#include <linux/crc32.h> +#include <linux/usb/usbnet.h> +#include <linux/slab.h> +#include "smsc75xx.h" + +#define SMSC_CHIPNAME			"smsc75xx" +#define SMSC_DRIVER_VERSION		"1.0.0" +#define HS_USB_PKT_SIZE			(512) +#define FS_USB_PKT_SIZE			(64) +#define DEFAULT_HS_BURST_CAP_SIZE	(16 * 1024 + 5 * HS_USB_PKT_SIZE) +#define DEFAULT_FS_BURST_CAP_SIZE	(6 * 1024 + 33 * FS_USB_PKT_SIZE) +#define DEFAULT_BULK_IN_DELAY		(0x00002000) +#define MAX_SINGLE_PACKET_SIZE		(9000) +#define LAN75XX_EEPROM_MAGIC		(0x7500) +#define EEPROM_MAC_OFFSET		(0x01) +#define DEFAULT_TX_CSUM_ENABLE		(true) +#define DEFAULT_RX_CSUM_ENABLE		(true) +#define DEFAULT_TSO_ENABLE		(true) +#define SMSC75XX_INTERNAL_PHY_ID	(1) +#define SMSC75XX_TX_OVERHEAD		(8) +#define MAX_RX_FIFO_SIZE		(20 * 1024) +#define MAX_TX_FIFO_SIZE		(12 * 1024) +#define USB_VENDOR_ID_SMSC		(0x0424) +#define USB_PRODUCT_ID_LAN7500		(0x7500) +#define USB_PRODUCT_ID_LAN7505		(0x7505) + +#define check_warn(ret, fmt, args...) \ +	({ if (ret < 0) netdev_warn(dev->net, fmt, ##args); }) + +#define check_warn_return(ret, fmt, args...) \ +	({ if (ret < 0) { netdev_warn(dev->net, fmt, ##args); return ret; } }) + +#define check_warn_goto_done(ret, fmt, args...) \ +	({ if (ret < 0) { netdev_warn(dev->net, fmt, ##args); goto done; } }) + +struct smsc75xx_priv { +	struct usbnet *dev; +	u32 rfe_ctl; +	u32 multicast_hash_table[DP_SEL_VHF_HASH_LEN]; +	bool use_rx_csum; +	struct mutex dataport_mutex; +	spinlock_t rfe_ctl_lock; +	struct work_struct set_multicast; +}; + +struct usb_context { +	struct usb_ctrlrequest req; +	struct usbnet *dev; +}; + +static int turbo_mode = true; +module_param(turbo_mode, bool, 0644); +MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction"); + +static int __must_check smsc75xx_read_reg(struct usbnet *dev, u32 index, +					  u32 *data) +{ +	u32 *buf = kmalloc(4, GFP_KERNEL); +	int ret; + +	BUG_ON(!dev); + +	if (!buf) +		return -ENOMEM; + +	ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), +		USB_VENDOR_REQUEST_READ_REGISTER, +		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, +		00, index, buf, 4, USB_CTRL_GET_TIMEOUT); + +	if (unlikely(ret < 0)) +		netdev_warn(dev->net, +			"Failed to read register index 0x%08x", index); + +	le32_to_cpus(buf); +	*data = *buf; +	kfree(buf); + +	return ret; +} + +static int __must_check smsc75xx_write_reg(struct usbnet *dev, u32 index, +					   u32 data) +{ +	u32 *buf = kmalloc(4, GFP_KERNEL); +	int ret; + +	BUG_ON(!dev); + +	if (!buf) +		return -ENOMEM; + +	*buf = data; +	cpu_to_le32s(buf); + +	ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), +		USB_VENDOR_REQUEST_WRITE_REGISTER, +		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, +		00, index, buf, 4, USB_CTRL_SET_TIMEOUT); + +	if (unlikely(ret < 0)) +		netdev_warn(dev->net, +			"Failed to write register index 0x%08x", index); + +	kfree(buf); + +	return ret; +} + +/* Loop until the read is completed with timeout + * called with phy_mutex held */ +static int smsc75xx_phy_wait_not_busy(struct usbnet *dev) +{ +	unsigned long start_time = jiffies; +	u32 val; +	int ret; + +	do { +		ret = smsc75xx_read_reg(dev, MII_ACCESS, &val); +		check_warn_return(ret, "Error reading MII_ACCESS"); + +		if (!(val & MII_ACCESS_BUSY)) +			return 0; +	} while (!time_after(jiffies, start_time + HZ)); + +	return -EIO; +} + +static int smsc75xx_mdio_read(struct net_device *netdev, int phy_id, int idx) +{ +	struct usbnet *dev = netdev_priv(netdev); +	u32 val, addr; +	int ret; + +	mutex_lock(&dev->phy_mutex); + +	/* confirm MII not busy */ +	ret = smsc75xx_phy_wait_not_busy(dev); +	check_warn_goto_done(ret, "MII is busy in smsc75xx_mdio_read"); + +	/* set the address, index & direction (read from PHY) */ +	phy_id &= dev->mii.phy_id_mask; +	idx &= dev->mii.reg_num_mask; +	addr = ((phy_id << MII_ACCESS_PHY_ADDR_SHIFT) & MII_ACCESS_PHY_ADDR) +		| ((idx << MII_ACCESS_REG_ADDR_SHIFT) & MII_ACCESS_REG_ADDR) +		| MII_ACCESS_READ; +	ret = smsc75xx_write_reg(dev, MII_ACCESS, addr); +	check_warn_goto_done(ret, "Error writing MII_ACCESS"); + +	ret = smsc75xx_phy_wait_not_busy(dev); +	check_warn_goto_done(ret, "Timed out reading MII reg %02X", idx); + +	ret = smsc75xx_read_reg(dev, MII_DATA, &val); +	check_warn_goto_done(ret, "Error reading MII_DATA"); + +	ret = (u16)(val & 0xFFFF); + +done: +	mutex_unlock(&dev->phy_mutex); +	return ret; +} + +static void smsc75xx_mdio_write(struct net_device *netdev, int phy_id, int idx, +				int regval) +{ +	struct usbnet *dev = netdev_priv(netdev); +	u32 val, addr; +	int ret; + +	mutex_lock(&dev->phy_mutex); + +	/* confirm MII not busy */ +	ret = smsc75xx_phy_wait_not_busy(dev); +	check_warn_goto_done(ret, "MII is busy in smsc75xx_mdio_write"); + +	val = regval; +	ret = smsc75xx_write_reg(dev, MII_DATA, val); +	check_warn_goto_done(ret, "Error writing MII_DATA"); + +	/* set the address, index & direction (write to PHY) */ +	phy_id &= dev->mii.phy_id_mask; +	idx &= dev->mii.reg_num_mask; +	addr = ((phy_id << MII_ACCESS_PHY_ADDR_SHIFT) & MII_ACCESS_PHY_ADDR) +		| ((idx << MII_ACCESS_REG_ADDR_SHIFT) & MII_ACCESS_REG_ADDR) +		| MII_ACCESS_WRITE; +	ret = smsc75xx_write_reg(dev, MII_ACCESS, addr); +	check_warn_goto_done(ret, "Error writing MII_ACCESS"); + +	ret = smsc75xx_phy_wait_not_busy(dev); +	check_warn_goto_done(ret, "Timed out writing MII reg %02X", idx); + +done: +	mutex_unlock(&dev->phy_mutex); +} + +static int smsc75xx_wait_eeprom(struct usbnet *dev) +{ +	unsigned long start_time = jiffies; +	u32 val; +	int ret; + +	do { +		ret = smsc75xx_read_reg(dev, E2P_CMD, &val); +		check_warn_return(ret, "Error reading E2P_CMD"); + +		if (!(val & E2P_CMD_BUSY) || (val & E2P_CMD_TIMEOUT)) +			break; +		udelay(40); +	} while (!time_after(jiffies, start_time + HZ)); + +	if (val & (E2P_CMD_TIMEOUT | E2P_CMD_BUSY)) { +		netdev_warn(dev->net, "EEPROM read operation timeout"); +		return -EIO; +	} + +	return 0; +} + +static int smsc75xx_eeprom_confirm_not_busy(struct usbnet *dev) +{ +	unsigned long start_time = jiffies; +	u32 val; +	int ret; + +	do { +		ret = smsc75xx_read_reg(dev, E2P_CMD, &val); +		check_warn_return(ret, "Error reading E2P_CMD"); + +		if (!(val & E2P_CMD_BUSY)) +			return 0; + +		udelay(40); +	} while (!time_after(jiffies, start_time + HZ)); + +	netdev_warn(dev->net, "EEPROM is busy"); +	return -EIO; +} + +static int smsc75xx_read_eeprom(struct usbnet *dev, u32 offset, u32 length, +				u8 *data) +{ +	u32 val; +	int i, ret; + +	BUG_ON(!dev); +	BUG_ON(!data); + +	ret = smsc75xx_eeprom_confirm_not_busy(dev); +	if (ret) +		return ret; + +	for (i = 0; i < length; i++) { +		val = E2P_CMD_BUSY | E2P_CMD_READ | (offset & E2P_CMD_ADDR); +		ret = smsc75xx_write_reg(dev, E2P_CMD, val); +		check_warn_return(ret, "Error writing E2P_CMD"); + +		ret = smsc75xx_wait_eeprom(dev); +		if (ret < 0) +			return ret; + +		ret = smsc75xx_read_reg(dev, E2P_DATA, &val); +		check_warn_return(ret, "Error reading E2P_DATA"); + +		data[i] = val & 0xFF; +		offset++; +	} + +	return 0; +} + +static int smsc75xx_write_eeprom(struct usbnet *dev, u32 offset, u32 length, +				 u8 *data) +{ +	u32 val; +	int i, ret; + +	BUG_ON(!dev); +	BUG_ON(!data); + +	ret = smsc75xx_eeprom_confirm_not_busy(dev); +	if (ret) +		return ret; + +	/* Issue write/erase enable command */ +	val = E2P_CMD_BUSY | E2P_CMD_EWEN; +	ret = smsc75xx_write_reg(dev, E2P_CMD, val); +	check_warn_return(ret, "Error writing E2P_CMD"); + +	ret = smsc75xx_wait_eeprom(dev); +	if (ret < 0) +		return ret; + +	for (i = 0; i < length; i++) { + +		/* Fill data register */ +		val = data[i]; +		ret = smsc75xx_write_reg(dev, E2P_DATA, val); +		check_warn_return(ret, "Error writing E2P_DATA"); + +		/* Send "write" command */ +		val = E2P_CMD_BUSY | E2P_CMD_WRITE | (offset & E2P_CMD_ADDR); +		ret = smsc75xx_write_reg(dev, E2P_CMD, val); +		check_warn_return(ret, "Error writing E2P_CMD"); + +		ret = smsc75xx_wait_eeprom(dev); +		if (ret < 0) +			return ret; + +		offset++; +	} + +	return 0; +} + +static int smsc75xx_dataport_wait_not_busy(struct usbnet *dev) +{ +	int i, ret; + +	for (i = 0; i < 100; i++) { +		u32 dp_sel; +		ret = smsc75xx_read_reg(dev, DP_SEL, &dp_sel); +		check_warn_return(ret, "Error reading DP_SEL"); + +		if (dp_sel & DP_SEL_DPRDY) +			return 0; + +		udelay(40); +	} + +	netdev_warn(dev->net, "smsc75xx_dataport_wait_not_busy timed out"); + +	return -EIO; +} + +static int smsc75xx_dataport_write(struct usbnet *dev, u32 ram_select, u32 addr, +				   u32 length, u32 *buf) +{ +	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); +	u32 dp_sel; +	int i, ret; + +	mutex_lock(&pdata->dataport_mutex); + +	ret = smsc75xx_dataport_wait_not_busy(dev); +	check_warn_goto_done(ret, "smsc75xx_dataport_write busy on entry"); + +	ret = smsc75xx_read_reg(dev, DP_SEL, &dp_sel); +	check_warn_goto_done(ret, "Error reading DP_SEL"); + +	dp_sel &= ~DP_SEL_RSEL; +	dp_sel |= ram_select; +	ret = smsc75xx_write_reg(dev, DP_SEL, dp_sel); +	check_warn_goto_done(ret, "Error writing DP_SEL"); + +	for (i = 0; i < length; i++) { +		ret = smsc75xx_write_reg(dev, DP_ADDR, addr + i); +		check_warn_goto_done(ret, "Error writing DP_ADDR"); + +		ret = smsc75xx_write_reg(dev, DP_DATA, buf[i]); +		check_warn_goto_done(ret, "Error writing DP_DATA"); + +		ret = smsc75xx_write_reg(dev, DP_CMD, DP_CMD_WRITE); +		check_warn_goto_done(ret, "Error writing DP_CMD"); + +		ret = smsc75xx_dataport_wait_not_busy(dev); +		check_warn_goto_done(ret, "smsc75xx_dataport_write timeout"); +	} + +done: +	mutex_unlock(&pdata->dataport_mutex); +	return ret; +} + +/* returns hash bit number for given MAC address */ +static u32 smsc75xx_hash(char addr[ETH_ALEN]) +{ +	return (ether_crc(ETH_ALEN, addr) >> 23) & 0x1ff; +} + +static void smsc75xx_deferred_multicast_write(struct work_struct *param) +{ +	struct smsc75xx_priv *pdata = +		container_of(param, struct smsc75xx_priv, set_multicast); +	struct usbnet *dev = pdata->dev; +	int ret; + +	netif_dbg(dev, drv, dev->net, "deferred multicast write 0x%08x", +		pdata->rfe_ctl); + +	smsc75xx_dataport_write(dev, DP_SEL_VHF, DP_SEL_VHF_VLAN_LEN, +		DP_SEL_VHF_HASH_LEN, pdata->multicast_hash_table); + +	ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); +	check_warn(ret, "Error writing RFE_CRL"); +} + +static void smsc75xx_set_multicast(struct net_device *netdev) +{ +	struct usbnet *dev = netdev_priv(netdev); +	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); +	unsigned long flags; +	int i; + +	spin_lock_irqsave(&pdata->rfe_ctl_lock, flags); + +	pdata->rfe_ctl &= +		~(RFE_CTL_AU | RFE_CTL_AM | RFE_CTL_DPF | RFE_CTL_MHF); +	pdata->rfe_ctl |= RFE_CTL_AB; + +	for (i = 0; i < DP_SEL_VHF_HASH_LEN; i++) +		pdata->multicast_hash_table[i] = 0; + +	if (dev->net->flags & IFF_PROMISC) { +		netif_dbg(dev, drv, dev->net, "promiscuous mode enabled"); +		pdata->rfe_ctl |= RFE_CTL_AM | RFE_CTL_AU; +	} else if (dev->net->flags & IFF_ALLMULTI) { +		netif_dbg(dev, drv, dev->net, "receive all multicast enabled"); +		pdata->rfe_ctl |= RFE_CTL_AM | RFE_CTL_DPF; +	} else if (!netdev_mc_empty(dev->net)) { +		struct dev_mc_list *mc_list; + +		netif_dbg(dev, drv, dev->net, "receive multicast hash filter"); + +		pdata->rfe_ctl |= RFE_CTL_MHF | RFE_CTL_DPF; + +		netdev_for_each_mc_addr(mc_list, netdev) { +			u32 bitnum = smsc75xx_hash(mc_list->dmi_addr); +			pdata->multicast_hash_table[bitnum / 32] |= +				(1 << (bitnum % 32)); +		} +	} else { +		netif_dbg(dev, drv, dev->net, "receive own packets only"); +		pdata->rfe_ctl |= RFE_CTL_DPF; +	} + +	spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); + +	/* defer register writes to a sleepable context */ +	schedule_work(&pdata->set_multicast); +} + +static int smsc75xx_update_flowcontrol(struct usbnet *dev, u8 duplex, +					    u16 lcladv, u16 rmtadv) +{ +	u32 flow = 0, fct_flow = 0; +	int ret; + +	if (duplex == DUPLEX_FULL) { +		u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); + +		if (cap & FLOW_CTRL_TX) { +			flow = (FLOW_TX_FCEN | 0xFFFF); +			/* set fct_flow thresholds to 20% and 80% */ +			fct_flow = (8 << 8) | 32; +		} + +		if (cap & FLOW_CTRL_RX) +			flow |= FLOW_RX_FCEN; + +		netif_dbg(dev, link, dev->net, "rx pause %s, tx pause %s", +			(cap & FLOW_CTRL_RX ? "enabled" : "disabled"), +			(cap & FLOW_CTRL_TX ? "enabled" : "disabled")); +	} else { +		netif_dbg(dev, link, dev->net, "half duplex"); +	} + +	ret = smsc75xx_write_reg(dev, FLOW, flow); +	check_warn_return(ret, "Error writing FLOW"); + +	ret = smsc75xx_write_reg(dev, FCT_FLOW, fct_flow); +	check_warn_return(ret, "Error writing FCT_FLOW"); + +	return 0; +} + +static int smsc75xx_link_reset(struct usbnet *dev) +{ +	struct mii_if_info *mii = &dev->mii; +	struct ethtool_cmd ecmd; +	u16 lcladv, rmtadv; +	int ret; + +	/* clear interrupt status */ +	ret = smsc75xx_mdio_read(dev->net, mii->phy_id, PHY_INT_SRC); +	check_warn_return(ret, "Error reading PHY_INT_SRC"); + +	ret = smsc75xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL); +	check_warn_return(ret, "Error writing INT_STS"); + +	mii_check_media(mii, 1, 1); +	mii_ethtool_gset(&dev->mii, &ecmd); +	lcladv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); +	rmtadv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_LPA); + +	netif_dbg(dev, link, dev->net, "speed: %d duplex: %d lcladv: %04x" +		" rmtadv: %04x", ecmd.speed, ecmd.duplex, lcladv, rmtadv); + +	return smsc75xx_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv); +} + +static void smsc75xx_status(struct usbnet *dev, struct urb *urb) +{ +	u32 intdata; + +	if (urb->actual_length != 4) { +		netdev_warn(dev->net, +			"unexpected urb length %d", urb->actual_length); +		return; +	} + +	memcpy(&intdata, urb->transfer_buffer, 4); +	le32_to_cpus(&intdata); + +	netif_dbg(dev, link, dev->net, "intdata: 0x%08X", intdata); + +	if (intdata & INT_ENP_PHY_INT) +		usbnet_defer_kevent(dev, EVENT_LINK_RESET); +	else +		netdev_warn(dev->net, +			"unexpected interrupt, intdata=0x%08X", intdata); +} + +/* Enable or disable Rx checksum offload engine */ +static int smsc75xx_set_rx_csum_offload(struct usbnet *dev) +{ +	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); +	unsigned long flags; +	int ret; + +	spin_lock_irqsave(&pdata->rfe_ctl_lock, flags); + +	if (pdata->use_rx_csum) +		pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM; +	else +		pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM); + +	spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); + +	ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); +	check_warn_return(ret, "Error writing RFE_CTL"); + +	return 0; +} + +static int smsc75xx_ethtool_get_eeprom_len(struct net_device *net) +{ +	return MAX_EEPROM_SIZE; +} + +static int smsc75xx_ethtool_get_eeprom(struct net_device *netdev, +				       struct ethtool_eeprom *ee, u8 *data) +{ +	struct usbnet *dev = netdev_priv(netdev); + +	ee->magic = LAN75XX_EEPROM_MAGIC; + +	return smsc75xx_read_eeprom(dev, ee->offset, ee->len, data); +} + +static int smsc75xx_ethtool_set_eeprom(struct net_device *netdev, +				       struct ethtool_eeprom *ee, u8 *data) +{ +	struct usbnet *dev = netdev_priv(netdev); + +	if (ee->magic != LAN75XX_EEPROM_MAGIC) { +		netdev_warn(dev->net, +			"EEPROM: magic value mismatch: 0x%x", ee->magic); +		return -EINVAL; +	} + +	return smsc75xx_write_eeprom(dev, ee->offset, ee->len, data); +} + +static u32 smsc75xx_ethtool_get_rx_csum(struct net_device *netdev) +{ +	struct usbnet *dev = netdev_priv(netdev); +	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); + +	return pdata->use_rx_csum; +} + +static int smsc75xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val) +{ +	struct usbnet *dev = netdev_priv(netdev); +	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); + +	pdata->use_rx_csum = !!val; + +	return smsc75xx_set_rx_csum_offload(dev); +} + +static int smsc75xx_ethtool_set_tso(struct net_device *netdev, u32 data) +{ +	if (data) +		netdev->features |= NETIF_F_TSO | NETIF_F_TSO6; +	else +		netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); + +	return 0; +} + +static const struct ethtool_ops smsc75xx_ethtool_ops = { +	.get_link	= usbnet_get_link, +	.nway_reset	= usbnet_nway_reset, +	.get_drvinfo	= usbnet_get_drvinfo, +	.get_msglevel	= usbnet_get_msglevel, +	.set_msglevel	= usbnet_set_msglevel, +	.get_settings	= usbnet_get_settings, +	.set_settings	= usbnet_set_settings, +	.get_eeprom_len	= smsc75xx_ethtool_get_eeprom_len, +	.get_eeprom	= smsc75xx_ethtool_get_eeprom, +	.set_eeprom	= smsc75xx_ethtool_set_eeprom, +	.get_tx_csum	= ethtool_op_get_tx_csum, +	.set_tx_csum	= ethtool_op_set_tx_hw_csum, +	.get_rx_csum	= smsc75xx_ethtool_get_rx_csum, +	.set_rx_csum	= smsc75xx_ethtool_set_rx_csum, +	.get_tso	= ethtool_op_get_tso, +	.set_tso	= smsc75xx_ethtool_set_tso, +}; + +static int smsc75xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) +{ +	struct usbnet *dev = netdev_priv(netdev); + +	if (!netif_running(netdev)) +		return -EINVAL; + +	return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); +} + +static void smsc75xx_init_mac_address(struct usbnet *dev) +{ +	/* try reading mac address from EEPROM */ +	if (smsc75xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, +			dev->net->dev_addr) == 0) { +		if (is_valid_ether_addr(dev->net->dev_addr)) { +			/* eeprom values are valid so use them */ +			netif_dbg(dev, ifup, dev->net, +				"MAC address read from EEPROM"); +			return; +		} +	} + +	/* no eeprom, or eeprom values are invalid. generate random MAC */ +	random_ether_addr(dev->net->dev_addr); +	netif_dbg(dev, ifup, dev->net, "MAC address set to random_ether_addr"); +} + +static int smsc75xx_set_mac_address(struct usbnet *dev) +{ +	u32 addr_lo = dev->net->dev_addr[0] | dev->net->dev_addr[1] << 8 | +		dev->net->dev_addr[2] << 16 | dev->net->dev_addr[3] << 24; +	u32 addr_hi = dev->net->dev_addr[4] | dev->net->dev_addr[5] << 8; + +	int ret = smsc75xx_write_reg(dev, RX_ADDRH, addr_hi); +	check_warn_return(ret, "Failed to write RX_ADDRH: %d", ret); + +	ret = smsc75xx_write_reg(dev, RX_ADDRL, addr_lo); +	check_warn_return(ret, "Failed to write RX_ADDRL: %d", ret); + +	addr_hi |= ADDR_FILTX_FB_VALID; +	ret = smsc75xx_write_reg(dev, ADDR_FILTX, addr_hi); +	check_warn_return(ret, "Failed to write ADDR_FILTX: %d", ret); + +	ret = smsc75xx_write_reg(dev, ADDR_FILTX + 4, addr_lo); +	check_warn_return(ret, "Failed to write ADDR_FILTX+4: %d", ret); + +	return 0; +} + +static int smsc75xx_phy_initialize(struct usbnet *dev) +{ +	int bmcr, timeout = 0; + +	/* Initialize MII structure */ +	dev->mii.dev = dev->net; +	dev->mii.mdio_read = smsc75xx_mdio_read; +	dev->mii.mdio_write = smsc75xx_mdio_write; +	dev->mii.phy_id_mask = 0x1f; +	dev->mii.reg_num_mask = 0x1f; +	dev->mii.phy_id = SMSC75XX_INTERNAL_PHY_ID; + +	/* reset phy and wait for reset to complete */ +	smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); + +	do { +		msleep(10); +		bmcr = smsc75xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR); +		check_warn_return(bmcr, "Error reading MII_BMCR"); +		timeout++; +	} while ((bmcr & MII_BMCR) && (timeout < 100)); + +	if (timeout >= 100) { +		netdev_warn(dev->net, "timeout on PHY Reset"); +		return -EIO; +	} + +	smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, +		ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | +		ADVERTISE_PAUSE_ASYM); + +	/* read to clear */ +	smsc75xx_mdio_read(dev->net, dev->mii.phy_id, PHY_INT_SRC); +	check_warn_return(bmcr, "Error reading PHY_INT_SRC"); + +	smsc75xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_MASK, +		PHY_INT_MASK_DEFAULT); +	mii_nway_restart(&dev->mii); + +	netif_dbg(dev, ifup, dev->net, "phy initialised successfully"); +	return 0; +} + +static int smsc75xx_set_rx_max_frame_length(struct usbnet *dev, int size) +{ +	int ret = 0; +	u32 buf; +	bool rxenabled; + +	ret = smsc75xx_read_reg(dev, MAC_RX, &buf); +	check_warn_return(ret, "Failed to read MAC_RX: %d", ret); + +	rxenabled = ((buf & MAC_RX_RXEN) != 0); + +	if (rxenabled) { +		buf &= ~MAC_RX_RXEN; +		ret = smsc75xx_write_reg(dev, MAC_RX, buf); +		check_warn_return(ret, "Failed to write MAC_RX: %d", ret); +	} + +	/* add 4 to size for FCS */ +	buf &= ~MAC_RX_MAX_SIZE; +	buf |= (((size + 4) << MAC_RX_MAX_SIZE_SHIFT) & MAC_RX_MAX_SIZE); + +	ret = smsc75xx_write_reg(dev, MAC_RX, buf); +	check_warn_return(ret, "Failed to write MAC_RX: %d", ret); + +	if (rxenabled) { +		buf |= MAC_RX_RXEN; +		ret = smsc75xx_write_reg(dev, MAC_RX, buf); +		check_warn_return(ret, "Failed to write MAC_RX: %d", ret); +	} + +	return 0; +} + +static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu) +{ +	struct usbnet *dev = netdev_priv(netdev); + +	int ret = smsc75xx_set_rx_max_frame_length(dev, new_mtu); +	check_warn_return(ret, "Failed to set mac rx frame length"); + +	return usbnet_change_mtu(netdev, new_mtu); +} + +static int smsc75xx_reset(struct usbnet *dev) +{ +	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); +	u32 buf; +	int ret = 0, timeout; + +	netif_dbg(dev, ifup, dev->net, "entering smsc75xx_reset"); + +	ret = smsc75xx_read_reg(dev, HW_CFG, &buf); +	check_warn_return(ret, "Failed to read HW_CFG: %d", ret); + +	buf |= HW_CFG_LRST; + +	ret = smsc75xx_write_reg(dev, HW_CFG, buf); +	check_warn_return(ret, "Failed to write HW_CFG: %d", ret); + +	timeout = 0; +	do { +		msleep(10); +		ret = smsc75xx_read_reg(dev, HW_CFG, &buf); +		check_warn_return(ret, "Failed to read HW_CFG: %d", ret); +		timeout++; +	} while ((buf & HW_CFG_LRST) && (timeout < 100)); + +	if (timeout >= 100) { +		netdev_warn(dev->net, "timeout on completion of Lite Reset"); +		return -EIO; +	} + +	netif_dbg(dev, ifup, dev->net, "Lite reset complete, resetting PHY"); + +	ret = smsc75xx_read_reg(dev, PMT_CTL, &buf); +	check_warn_return(ret, "Failed to read PMT_CTL: %d", ret); + +	buf |= PMT_CTL_PHY_RST; + +	ret = smsc75xx_write_reg(dev, PMT_CTL, buf); +	check_warn_return(ret, "Failed to write PMT_CTL: %d", ret); + +	timeout = 0; +	do { +		msleep(10); +		ret = smsc75xx_read_reg(dev, PMT_CTL, &buf); +		check_warn_return(ret, "Failed to read PMT_CTL: %d", ret); +		timeout++; +	} while ((buf & PMT_CTL_PHY_RST) && (timeout < 100)); + +	if (timeout >= 100) { +		netdev_warn(dev->net, "timeout waiting for PHY Reset"); +		return -EIO; +	} + +	netif_dbg(dev, ifup, dev->net, "PHY reset complete"); + +	smsc75xx_init_mac_address(dev); + +	ret = smsc75xx_set_mac_address(dev); +	check_warn_return(ret, "Failed to set mac address"); + +	netif_dbg(dev, ifup, dev->net, "MAC Address: %pM", dev->net->dev_addr); + +	ret = smsc75xx_read_reg(dev, HW_CFG, &buf); +	check_warn_return(ret, "Failed to read HW_CFG: %d", ret); + +	netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG : 0x%08x", buf); + +	buf |= HW_CFG_BIR; + +	ret = smsc75xx_write_reg(dev, HW_CFG, buf); +	check_warn_return(ret, "Failed to write HW_CFG: %d", ret); + +	ret = smsc75xx_read_reg(dev, HW_CFG, &buf); +	check_warn_return(ret, "Failed to read HW_CFG: %d", ret); + +	netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG after " +			"writing HW_CFG_BIR: 0x%08x", buf); + +	if (!turbo_mode) { +		buf = 0; +		dev->rx_urb_size = MAX_SINGLE_PACKET_SIZE; +	} else if (dev->udev->speed == USB_SPEED_HIGH) { +		buf = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE; +		dev->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE; +	} else { +		buf = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE; +		dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE; +	} + +	netif_dbg(dev, ifup, dev->net, "rx_urb_size=%ld", +		(ulong)dev->rx_urb_size); + +	ret = smsc75xx_write_reg(dev, BURST_CAP, buf); +	check_warn_return(ret, "Failed to write BURST_CAP: %d", ret); + +	ret = smsc75xx_read_reg(dev, BURST_CAP, &buf); +	check_warn_return(ret, "Failed to read BURST_CAP: %d", ret); + +	netif_dbg(dev, ifup, dev->net, +		"Read Value from BURST_CAP after writing: 0x%08x", buf); + +	ret = smsc75xx_write_reg(dev, BULK_IN_DLY, DEFAULT_BULK_IN_DELAY); +	check_warn_return(ret, "Failed to write BULK_IN_DLY: %d", ret); + +	ret = smsc75xx_read_reg(dev, BULK_IN_DLY, &buf); +	check_warn_return(ret, "Failed to read BULK_IN_DLY: %d", ret); + +	netif_dbg(dev, ifup, dev->net, +		"Read Value from BULK_IN_DLY after writing: 0x%08x", buf); + +	if (turbo_mode) { +		ret = smsc75xx_read_reg(dev, HW_CFG, &buf); +		check_warn_return(ret, "Failed to read HW_CFG: %d", ret); + +		netif_dbg(dev, ifup, dev->net, "HW_CFG: 0x%08x", buf); + +		buf |= (HW_CFG_MEF | HW_CFG_BCE); + +		ret = smsc75xx_write_reg(dev, HW_CFG, buf); +		check_warn_return(ret, "Failed to write HW_CFG: %d", ret); + +		ret = smsc75xx_read_reg(dev, HW_CFG, &buf); +		check_warn_return(ret, "Failed to read HW_CFG: %d", ret); + +		netif_dbg(dev, ifup, dev->net, "HW_CFG: 0x%08x", buf); +	} + +	/* set FIFO sizes */ +	buf = (MAX_RX_FIFO_SIZE - 512) / 512; +	ret = smsc75xx_write_reg(dev, FCT_RX_FIFO_END, buf); +	check_warn_return(ret, "Failed to write FCT_RX_FIFO_END: %d", ret); + +	netif_dbg(dev, ifup, dev->net, "FCT_RX_FIFO_END set to 0x%08x", buf); + +	buf = (MAX_TX_FIFO_SIZE - 512) / 512; +	ret = smsc75xx_write_reg(dev, FCT_TX_FIFO_END, buf); +	check_warn_return(ret, "Failed to write FCT_TX_FIFO_END: %d", ret); + +	netif_dbg(dev, ifup, dev->net, "FCT_TX_FIFO_END set to 0x%08x", buf); + +	ret = smsc75xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL); +	check_warn_return(ret, "Failed to write INT_STS: %d", ret); + +	ret = smsc75xx_read_reg(dev, ID_REV, &buf); +	check_warn_return(ret, "Failed to read ID_REV: %d", ret); + +	netif_dbg(dev, ifup, dev->net, "ID_REV = 0x%08x", buf); + +	/* Configure GPIO pins as LED outputs */ +	ret = smsc75xx_read_reg(dev, LED_GPIO_CFG, &buf); +	check_warn_return(ret, "Failed to read LED_GPIO_CFG: %d", ret); + +	buf &= ~(LED_GPIO_CFG_LED2_FUN_SEL | LED_GPIO_CFG_LED10_FUN_SEL); +	buf |= LED_GPIO_CFG_LEDGPIO_EN | LED_GPIO_CFG_LED2_FUN_SEL; + +	ret = smsc75xx_write_reg(dev, LED_GPIO_CFG, buf); +	check_warn_return(ret, "Failed to write LED_GPIO_CFG: %d", ret); + +	ret = smsc75xx_write_reg(dev, FLOW, 0); +	check_warn_return(ret, "Failed to write FLOW: %d", ret); + +	ret = smsc75xx_write_reg(dev, FCT_FLOW, 0); +	check_warn_return(ret, "Failed to write FCT_FLOW: %d", ret); + +	/* Don't need rfe_ctl_lock during initialisation */ +	ret = smsc75xx_read_reg(dev, RFE_CTL, &pdata->rfe_ctl); +	check_warn_return(ret, "Failed to read RFE_CTL: %d", ret); + +	pdata->rfe_ctl |= RFE_CTL_AB | RFE_CTL_DPF; + +	ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); +	check_warn_return(ret, "Failed to write RFE_CTL: %d", ret); + +	ret = smsc75xx_read_reg(dev, RFE_CTL, &pdata->rfe_ctl); +	check_warn_return(ret, "Failed to read RFE_CTL: %d", ret); + +	netif_dbg(dev, ifup, dev->net, "RFE_CTL set to 0x%08x", pdata->rfe_ctl); + +	/* Enable or disable checksum offload engines */ +	ethtool_op_set_tx_hw_csum(dev->net, DEFAULT_TX_CSUM_ENABLE); +	ret = smsc75xx_set_rx_csum_offload(dev); +	check_warn_return(ret, "Failed to set rx csum offload: %d", ret); + +	smsc75xx_ethtool_set_tso(dev->net, DEFAULT_TSO_ENABLE); + +	smsc75xx_set_multicast(dev->net); + +	ret = smsc75xx_phy_initialize(dev); +	check_warn_return(ret, "Failed to initialize PHY: %d", ret); + +	ret = smsc75xx_read_reg(dev, INT_EP_CTL, &buf); +	check_warn_return(ret, "Failed to read INT_EP_CTL: %d", ret); + +	/* enable PHY interrupts */ +	buf |= INT_ENP_PHY_INT; + +	ret = smsc75xx_write_reg(dev, INT_EP_CTL, buf); +	check_warn_return(ret, "Failed to write INT_EP_CTL: %d", ret); + +	ret = smsc75xx_read_reg(dev, MAC_TX, &buf); +	check_warn_return(ret, "Failed to read MAC_TX: %d", ret); + +	buf |= MAC_TX_TXEN; + +	ret = smsc75xx_write_reg(dev, MAC_TX, buf); +	check_warn_return(ret, "Failed to write MAC_TX: %d", ret); + +	netif_dbg(dev, ifup, dev->net, "MAC_TX set to 0x%08x", buf); + +	ret = smsc75xx_read_reg(dev, FCT_TX_CTL, &buf); +	check_warn_return(ret, "Failed to read FCT_TX_CTL: %d", ret); + +	buf |= FCT_TX_CTL_EN; + +	ret = smsc75xx_write_reg(dev, FCT_TX_CTL, buf); +	check_warn_return(ret, "Failed to write FCT_TX_CTL: %d", ret); + +	netif_dbg(dev, ifup, dev->net, "FCT_TX_CTL set to 0x%08x", buf); + +	ret = smsc75xx_set_rx_max_frame_length(dev, 1514); +	check_warn_return(ret, "Failed to set max rx frame length"); + +	ret = smsc75xx_read_reg(dev, MAC_RX, &buf); +	check_warn_return(ret, "Failed to read MAC_RX: %d", ret); + +	buf |= MAC_RX_RXEN; + +	ret = smsc75xx_write_reg(dev, MAC_RX, buf); +	check_warn_return(ret, "Failed to write MAC_RX: %d", ret); + +	netif_dbg(dev, ifup, dev->net, "MAC_RX set to 0x%08x", buf); + +	ret = smsc75xx_read_reg(dev, FCT_RX_CTL, &buf); +	check_warn_return(ret, "Failed to read FCT_RX_CTL: %d", ret); + +	buf |= FCT_RX_CTL_EN; + +	ret = smsc75xx_write_reg(dev, FCT_RX_CTL, buf); +	check_warn_return(ret, "Failed to write FCT_RX_CTL: %d", ret); + +	netif_dbg(dev, ifup, dev->net, "FCT_RX_CTL set to 0x%08x", buf); + +	netif_dbg(dev, ifup, dev->net, "smsc75xx_reset, return 0"); +	return 0; +} + +static const struct net_device_ops smsc75xx_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		= smsc75xx_change_mtu, +	.ndo_set_mac_address 	= eth_mac_addr, +	.ndo_validate_addr	= eth_validate_addr, +	.ndo_do_ioctl 		= smsc75xx_ioctl, +	.ndo_set_multicast_list = smsc75xx_set_multicast, +}; + +static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf) +{ +	struct smsc75xx_priv *pdata = NULL; +	int ret; + +	printk(KERN_INFO SMSC_CHIPNAME " v" SMSC_DRIVER_VERSION "\n"); + +	ret = usbnet_get_endpoints(dev, intf); +	check_warn_return(ret, "usbnet_get_endpoints failed: %d", ret); + +	dev->data[0] = (unsigned long)kzalloc(sizeof(struct smsc75xx_priv), +		GFP_KERNEL); + +	pdata = (struct smsc75xx_priv *)(dev->data[0]); +	if (!pdata) { +		netdev_warn(dev->net, "Unable to allocate smsc75xx_priv"); +		return -ENOMEM; +	} + +	pdata->dev = dev; + +	spin_lock_init(&pdata->rfe_ctl_lock); +	mutex_init(&pdata->dataport_mutex); + +	INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write); + +	pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE; + +	/* We have to advertise SG otherwise TSO cannot be enabled */ +	dev->net->features |= NETIF_F_SG; + +	/* Init all registers */ +	ret = smsc75xx_reset(dev); + +	dev->net->netdev_ops = &smsc75xx_netdev_ops; +	dev->net->ethtool_ops = &smsc75xx_ethtool_ops; +	dev->net->flags |= IFF_MULTICAST; +	dev->net->hard_header_len += SMSC75XX_TX_OVERHEAD; +	return 0; +} + +static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf) +{ +	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); +	if (pdata) { +		netif_dbg(dev, ifdown, dev->net, "free pdata"); +		kfree(pdata); +		pdata = NULL; +		dev->data[0] = 0; +	} +} + +static void smsc75xx_rx_csum_offload(struct sk_buff *skb, u32 rx_cmd_a, +				     u32 rx_cmd_b) +{ +	if (unlikely(rx_cmd_a & RX_CMD_A_LCSM)) { +		skb->ip_summed = CHECKSUM_NONE; +	} else { +		skb->csum = ntohs((u16)(rx_cmd_b >> RX_CMD_B_CSUM_SHIFT)); +		skb->ip_summed = CHECKSUM_COMPLETE; +	} +} + +static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ +	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); + +	while (skb->len > 0) { +		u32 rx_cmd_a, rx_cmd_b, align_count, size; +		struct sk_buff *ax_skb; +		unsigned char *packet; + +		memcpy(&rx_cmd_a, skb->data, sizeof(rx_cmd_a)); +		le32_to_cpus(&rx_cmd_a); +		skb_pull(skb, 4); + +		memcpy(&rx_cmd_b, skb->data, sizeof(rx_cmd_b)); +		le32_to_cpus(&rx_cmd_b); +		skb_pull(skb, 4 + NET_IP_ALIGN); + +		packet = skb->data; + +		/* get the packet length */ +		size = (rx_cmd_a & RX_CMD_A_LEN) - NET_IP_ALIGN; +		align_count = (4 - ((size + NET_IP_ALIGN) % 4)) % 4; + +		if (unlikely(rx_cmd_a & RX_CMD_A_RED)) { +			netif_dbg(dev, rx_err, dev->net, +				"Error rx_cmd_a=0x%08x", rx_cmd_a); +			dev->net->stats.rx_errors++; +			dev->net->stats.rx_dropped++; + +			if (rx_cmd_a & RX_CMD_A_FCS) +				dev->net->stats.rx_crc_errors++; +			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))) { +				netif_dbg(dev, rx_err, dev->net, +					"size err rx_cmd_a=0x%08x", rx_cmd_a); +				return 0; +			} + +			/* last frame in this batch */ +			if (skb->len == size) { +				if (pdata->use_rx_csum) +					smsc75xx_rx_csum_offload(skb, rx_cmd_a, +						rx_cmd_b); +				else +					skb->ip_summed = CHECKSUM_NONE; + +				skb_trim(skb, skb->len - 4); /* remove fcs */ +				skb->truesize = size + sizeof(struct sk_buff); + +				return 1; +			} + +			ax_skb = skb_clone(skb, GFP_ATOMIC); +			if (unlikely(!ax_skb)) { +				netdev_warn(dev->net, "Error allocating skb"); +				return 0; +			} + +			ax_skb->len = size; +			ax_skb->data = packet; +			skb_set_tail_pointer(ax_skb, size); + +			if (pdata->use_rx_csum) +				smsc75xx_rx_csum_offload(ax_skb, rx_cmd_a, +					rx_cmd_b); +			else +				ax_skb->ip_summed = CHECKSUM_NONE; + +			skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ +			ax_skb->truesize = size + sizeof(struct sk_buff); + +			usbnet_skb_return(dev, ax_skb); +		} + +		skb_pull(skb, size); + +		/* padding bytes before the next frame starts */ +		if (skb->len) +			skb_pull(skb, align_count); +	} + +	if (unlikely(skb->len < 0)) { +		netdev_warn(dev->net, "invalid rx length<0 %d", skb->len); +		return 0; +	} + +	return 1; +} + +static struct sk_buff *smsc75xx_tx_fixup(struct usbnet *dev, +					 struct sk_buff *skb, gfp_t flags) +{ +	u32 tx_cmd_a, tx_cmd_b; + +	skb_linearize(skb); + +	if (skb_headroom(skb) < SMSC75XX_TX_OVERHEAD) { +		struct sk_buff *skb2 = +			skb_copy_expand(skb, SMSC75XX_TX_OVERHEAD, 0, flags); +		dev_kfree_skb_any(skb); +		skb = skb2; +		if (!skb) +			return NULL; +	} + +	tx_cmd_a = (u32)(skb->len & TX_CMD_A_LEN) | TX_CMD_A_FCS; + +	if (skb->ip_summed == CHECKSUM_PARTIAL) +		tx_cmd_a |= TX_CMD_A_IPE | TX_CMD_A_TPE; + +	if (skb_is_gso(skb)) { +		u16 mss = max(skb_shinfo(skb)->gso_size, TX_MSS_MIN); +		tx_cmd_b = (mss << TX_CMD_B_MSS_SHIFT) & TX_CMD_B_MSS; + +		tx_cmd_a |= TX_CMD_A_LSO; +	} else { +		tx_cmd_b = 0; +	} + +	skb_push(skb, 4); +	cpu_to_le32s(&tx_cmd_b); +	memcpy(skb->data, &tx_cmd_b, 4); + +	skb_push(skb, 4); +	cpu_to_le32s(&tx_cmd_a); +	memcpy(skb->data, &tx_cmd_a, 4); + +	return skb; +} + +static const struct driver_info smsc75xx_info = { +	.description	= "smsc75xx USB 2.0 Gigabit Ethernet", +	.bind		= smsc75xx_bind, +	.unbind		= smsc75xx_unbind, +	.link_reset	= smsc75xx_link_reset, +	.reset		= smsc75xx_reset, +	.rx_fixup	= smsc75xx_rx_fixup, +	.tx_fixup	= smsc75xx_tx_fixup, +	.status		= smsc75xx_status, +	.flags		= FLAG_ETHER | FLAG_SEND_ZLP, +}; + +static const struct usb_device_id products[] = { +	{ +		/* SMSC7500 USB Gigabit Ethernet Device */ +		USB_DEVICE(USB_VENDOR_ID_SMSC, USB_PRODUCT_ID_LAN7500), +		.driver_info = (unsigned long) &smsc75xx_info, +	}, +	{ +		/* SMSC7500 USB Gigabit Ethernet Device */ +		USB_DEVICE(USB_VENDOR_ID_SMSC, USB_PRODUCT_ID_LAN7505), +		.driver_info = (unsigned long) &smsc75xx_info, +	}, +	{ },		/* END */ +}; +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver smsc75xx_driver = { +	.name		= SMSC_CHIPNAME, +	.id_table	= products, +	.probe		= usbnet_probe, +	.suspend	= usbnet_suspend, +	.resume		= usbnet_resume, +	.disconnect	= usbnet_disconnect, +}; + +static int __init smsc75xx_init(void) +{ +	return usb_register(&smsc75xx_driver); +} +module_init(smsc75xx_init); + +static void __exit smsc75xx_exit(void) +{ +	usb_deregister(&smsc75xx_driver); +} +module_exit(smsc75xx_exit); + +MODULE_AUTHOR("Nancy Lin"); +MODULE_AUTHOR("Steve Glendinning <steve.glendinning@smsc.com>"); +MODULE_DESCRIPTION("SMSC75XX USB 2.0 Gigabit Ethernet Devices"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/usb/smsc75xx.h b/drivers/net/usb/smsc75xx.h new file mode 100644 index 00000000000..16e98c77834 --- /dev/null +++ b/drivers/net/usb/smsc75xx.h @@ -0,0 +1,421 @@ + /*************************************************************************** + * + * Copyright (C) 2007-2010 SMSC + * + * 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. + * + *****************************************************************************/ + +#ifndef _SMSC75XX_H +#define _SMSC75XX_H + +/* Tx command words */ +#define TX_CMD_A_LSO			(0x08000000) +#define TX_CMD_A_IPE			(0x04000000) +#define TX_CMD_A_TPE			(0x02000000) +#define TX_CMD_A_IVTG			(0x01000000) +#define TX_CMD_A_RVTG			(0x00800000) +#define TX_CMD_A_FCS			(0x00400000) +#define TX_CMD_A_LEN			(0x000FFFFF) + +#define TX_CMD_B_MSS			(0x3FFF0000) +#define TX_CMD_B_MSS_SHIFT		(16) +#define TX_MSS_MIN			((u16)8) +#define TX_CMD_B_VTAG			(0x0000FFFF) + +/* Rx command words */ +#define RX_CMD_A_ICE			(0x80000000) +#define RX_CMD_A_TCE			(0x40000000) +#define RX_CMD_A_IPV			(0x20000000) +#define RX_CMD_A_PID			(0x18000000) +#define RX_CMD_A_PID_NIP		(0x00000000) +#define RX_CMD_A_PID_TCP		(0x08000000) +#define RX_CMD_A_PID_UDP		(0x10000000) +#define RX_CMD_A_PID_PP			(0x18000000) +#define RX_CMD_A_PFF			(0x04000000) +#define RX_CMD_A_BAM			(0x02000000) +#define RX_CMD_A_MAM			(0x01000000) +#define RX_CMD_A_FVTG			(0x00800000) +#define RX_CMD_A_RED			(0x00400000) +#define RX_CMD_A_RWT			(0x00200000) +#define RX_CMD_A_RUNT			(0x00100000) +#define RX_CMD_A_LONG			(0x00080000) +#define RX_CMD_A_RXE			(0x00040000) +#define RX_CMD_A_DRB			(0x00020000) +#define RX_CMD_A_FCS			(0x00010000) +#define RX_CMD_A_UAM			(0x00008000) +#define RX_CMD_A_LCSM			(0x00004000) +#define RX_CMD_A_LEN			(0x00003FFF) + +#define RX_CMD_B_CSUM			(0xFFFF0000) +#define RX_CMD_B_CSUM_SHIFT		(16) +#define RX_CMD_B_VTAG			(0x0000FFFF) + +/* SCSRs */ +#define ID_REV				(0x0000) + +#define FPGA_REV			(0x0004) + +#define BOND_CTL			(0x0008) + +#define INT_STS				(0x000C) +#define INT_STS_RDFO_INT		(0x00400000) +#define INT_STS_TXE_INT			(0x00200000) +#define INT_STS_MACRTO_INT		(0x00100000) +#define INT_STS_TX_DIS_INT		(0x00080000) +#define INT_STS_RX_DIS_INT		(0x00040000) +#define INT_STS_PHY_INT_		(0x00020000) +#define INT_STS_MAC_ERR_INT		(0x00008000) +#define INT_STS_TDFU			(0x00004000) +#define INT_STS_TDFO			(0x00002000) +#define INT_STS_GPIOS			(0x00000FFF) +#define INT_STS_CLEAR_ALL		(0xFFFFFFFF) + +#define HW_CFG				(0x0010) +#define HW_CFG_SMDET_STS		(0x00008000) +#define HW_CFG_SMDET_EN			(0x00004000) +#define HW_CFG_EEM			(0x00002000) +#define HW_CFG_RST_PROTECT		(0x00001000) +#define HW_CFG_PORT_SWAP		(0x00000800) +#define HW_CFG_PHY_BOOST		(0x00000600) +#define HW_CFG_PHY_BOOST_NORMAL		(0x00000000) +#define HW_CFG_PHY_BOOST_4		(0x00002000) +#define HW_CFG_PHY_BOOST_8		(0x00004000) +#define HW_CFG_PHY_BOOST_12		(0x00006000) +#define HW_CFG_LEDB			(0x00000100) +#define HW_CFG_BIR			(0x00000080) +#define HW_CFG_SBP			(0x00000040) +#define HW_CFG_IME			(0x00000020) +#define HW_CFG_MEF			(0x00000010) +#define HW_CFG_ETC			(0x00000008) +#define HW_CFG_BCE			(0x00000004) +#define HW_CFG_LRST			(0x00000002) +#define HW_CFG_SRST			(0x00000001) + +#define PMT_CTL				(0x0014) +#define PMT_CTL_PHY_PWRUP		(0x00000400) +#define PMT_CTL_RES_CLR_WKP_EN		(0x00000100) +#define PMT_CTL_DEV_RDY			(0x00000080) +#define PMT_CTL_SUS_MODE		(0x00000060) +#define PMT_CTL_SUS_MODE_0		(0x00000000) +#define PMT_CTL_SUS_MODE_1		(0x00000020) +#define PMT_CTL_SUS_MODE_2		(0x00000040) +#define PMT_CTL_SUS_MODE_3		(0x00000060) +#define PMT_CTL_PHY_RST			(0x00000010) +#define PMT_CTL_WOL_EN			(0x00000008) +#define PMT_CTL_ED_EN			(0x00000004) +#define PMT_CTL_WUPS			(0x00000003) +#define PMT_CTL_WUPS_NO			(0x00000000) +#define PMT_CTL_WUPS_ED			(0x00000001) +#define PMT_CTL_WUPS_WOL		(0x00000002) +#define PMT_CTL_WUPS_MULTI		(0x00000003) + +#define LED_GPIO_CFG			(0x0018) +#define LED_GPIO_CFG_LED2_FUN_SEL	(0x80000000) +#define LED_GPIO_CFG_LED10_FUN_SEL	(0x40000000) +#define LED_GPIO_CFG_LEDGPIO_EN		(0x0000F000) +#define LED_GPIO_CFG_LEDGPIO_EN_0	(0x00001000) +#define LED_GPIO_CFG_LEDGPIO_EN_1	(0x00002000) +#define LED_GPIO_CFG_LEDGPIO_EN_2	(0x00004000) +#define LED_GPIO_CFG_LEDGPIO_EN_3	(0x00008000) +#define LED_GPIO_CFG_GPBUF		(0x00000F00) +#define LED_GPIO_CFG_GPBUF_0		(0x00000100) +#define LED_GPIO_CFG_GPBUF_1		(0x00000200) +#define LED_GPIO_CFG_GPBUF_2		(0x00000400) +#define LED_GPIO_CFG_GPBUF_3		(0x00000800) +#define LED_GPIO_CFG_GPDIR		(0x000000F0) +#define LED_GPIO_CFG_GPDIR_0		(0x00000010) +#define LED_GPIO_CFG_GPDIR_1		(0x00000020) +#define LED_GPIO_CFG_GPDIR_2		(0x00000040) +#define LED_GPIO_CFG_GPDIR_3		(0x00000080) +#define LED_GPIO_CFG_GPDATA		(0x0000000F) +#define LED_GPIO_CFG_GPDATA_0		(0x00000001) +#define LED_GPIO_CFG_GPDATA_1		(0x00000002) +#define LED_GPIO_CFG_GPDATA_2		(0x00000004) +#define LED_GPIO_CFG_GPDATA_3		(0x00000008) + +#define GPIO_CFG			(0x001C) +#define GPIO_CFG_SHIFT			(24) +#define GPIO_CFG_GPEN			(0xFF000000) +#define GPIO_CFG_GPBUF			(0x00FF0000) +#define GPIO_CFG_GPDIR			(0x0000FF00) +#define GPIO_CFG_GPDATA			(0x000000FF) + +#define GPIO_WAKE			(0x0020) +#define GPIO_WAKE_PHY_LINKUP_EN		(0x80000000) +#define GPIO_WAKE_POL			(0x0FFF0000) +#define GPIO_WAKE_POL_SHIFT		(16) +#define GPIO_WAKE_WK			(0x00000FFF) + +#define DP_SEL				(0x0024) +#define DP_SEL_DPRDY			(0x80000000) +#define DP_SEL_RSEL			(0x0000000F) +#define DP_SEL_URX			(0x00000000) +#define DP_SEL_VHF			(0x00000001) +#define DP_SEL_VHF_HASH_LEN		(16) +#define DP_SEL_VHF_VLAN_LEN		(128) +#define DP_SEL_LSO_HEAD			(0x00000002) +#define DP_SEL_FCT_RX			(0x00000003) +#define DP_SEL_FCT_TX			(0x00000004) +#define DP_SEL_DESCRIPTOR		(0x00000005) +#define DP_SEL_WOL			(0x00000006) + +#define DP_CMD				(0x0028) +#define DP_CMD_WRITE			(0x01) +#define DP_CMD_READ			(0x00) + +#define DP_ADDR				(0x002C) + +#define DP_DATA				(0x0030) + +#define BURST_CAP			(0x0034) +#define BURST_CAP_MASK			(0x0000000F) + +#define INT_EP_CTL			(0x0038) +#define INT_EP_CTL_INTEP_ON		(0x80000000) +#define INT_EP_CTL_RDFO_EN		(0x00400000) +#define INT_EP_CTL_TXE_EN		(0x00200000) +#define INT_EP_CTL_MACROTO_EN		(0x00100000) +#define INT_EP_CTL_TX_DIS_EN		(0x00080000) +#define INT_EP_CTL_RX_DIS_EN		(0x00040000) +#define INT_EP_CTL_PHY_EN_		(0x00020000) +#define INT_EP_CTL_MAC_ERR_EN		(0x00008000) +#define INT_EP_CTL_TDFU_EN		(0x00004000) +#define INT_EP_CTL_TDFO_EN		(0x00002000) +#define INT_EP_CTL_RX_FIFO_EN		(0x00001000) +#define INT_EP_CTL_GPIOX_EN		(0x00000FFF) + +#define BULK_IN_DLY			(0x003C) +#define BULK_IN_DLY_MASK		(0xFFFF) + +#define E2P_CMD				(0x0040) +#define E2P_CMD_BUSY			(0x80000000) +#define E2P_CMD_MASK			(0x70000000) +#define E2P_CMD_READ			(0x00000000) +#define E2P_CMD_EWDS			(0x10000000) +#define E2P_CMD_EWEN			(0x20000000) +#define E2P_CMD_WRITE			(0x30000000) +#define E2P_CMD_WRAL			(0x40000000) +#define E2P_CMD_ERASE			(0x50000000) +#define E2P_CMD_ERAL			(0x60000000) +#define E2P_CMD_RELOAD			(0x70000000) +#define E2P_CMD_TIMEOUT			(0x00000400) +#define E2P_CMD_LOADED			(0x00000200) +#define E2P_CMD_ADDR			(0x000001FF) + +#define MAX_EEPROM_SIZE			(512) + +#define E2P_DATA			(0x0044) +#define E2P_DATA_MASK_			(0x000000FF) + +#define RFE_CTL				(0x0060) +#define RFE_CTL_TCPUDP_CKM		(0x00001000) +#define RFE_CTL_IP_CKM			(0x00000800) +#define RFE_CTL_AB			(0x00000400) +#define RFE_CTL_AM			(0x00000200) +#define RFE_CTL_AU			(0x00000100) +#define RFE_CTL_VS			(0x00000080) +#define RFE_CTL_UF			(0x00000040) +#define RFE_CTL_VF			(0x00000020) +#define RFE_CTL_SPF			(0x00000010) +#define RFE_CTL_MHF			(0x00000008) +#define RFE_CTL_DHF			(0x00000004) +#define RFE_CTL_DPF			(0x00000002) +#define RFE_CTL_RST_RF			(0x00000001) + +#define VLAN_TYPE			(0x0064) +#define VLAN_TYPE_MASK			(0x0000FFFF) + +#define FCT_RX_CTL			(0x0090) +#define FCT_RX_CTL_EN			(0x80000000) +#define FCT_RX_CTL_RST			(0x40000000) +#define FCT_RX_CTL_SBF			(0x02000000) +#define FCT_RX_CTL_OVERFLOW		(0x01000000) +#define FCT_RX_CTL_FRM_DROP		(0x00800000) +#define FCT_RX_CTL_RX_NOT_EMPTY		(0x00400000) +#define FCT_RX_CTL_RX_EMPTY		(0x00200000) +#define FCT_RX_CTL_RX_DISABLED		(0x00100000) +#define FCT_RX_CTL_RXUSED		(0x0000FFFF) + +#define FCT_TX_CTL			(0x0094) +#define FCT_TX_CTL_EN			(0x80000000) +#define FCT_TX_CTL_RST			(0x40000000) +#define FCT_TX_CTL_TX_NOT_EMPTY		(0x00400000) +#define FCT_TX_CTL_TX_EMPTY		(0x00200000) +#define FCT_TX_CTL_TX_DISABLED		(0x00100000) +#define FCT_TX_CTL_TXUSED		(0x0000FFFF) + +#define FCT_RX_FIFO_END			(0x0098) +#define FCT_RX_FIFO_END_MASK		(0x0000007F) + +#define FCT_TX_FIFO_END			(0x009C) +#define FCT_TX_FIFO_END_MASK		(0x0000003F) + +#define FCT_FLOW			(0x00A0) +#define FCT_FLOW_THRESHOLD_OFF		(0x00007F00) +#define FCT_FLOW_THRESHOLD_OFF_SHIFT	(8) +#define FCT_FLOW_THRESHOLD_ON		(0x0000007F) + +/* MAC CSRs */ +#define MAC_CR				(0x100) +#define MAC_CR_ADP			(0x00002000) +#define MAC_CR_ADD			(0x00001000) +#define MAC_CR_ASD			(0x00000800) +#define MAC_CR_INT_LOOP			(0x00000400) +#define MAC_CR_BOLMT			(0x000000C0) +#define MAC_CR_FDPX			(0x00000008) +#define MAC_CR_CFG			(0x00000006) +#define MAC_CR_CFG_10			(0x00000000) +#define MAC_CR_CFG_100			(0x00000002) +#define MAC_CR_CFG_1000			(0x00000004) +#define MAC_CR_RST			(0x00000001) + +#define MAC_RX				(0x104) +#define MAC_RX_MAX_SIZE			(0x3FFF0000) +#define MAC_RX_MAX_SIZE_SHIFT		(16) +#define MAC_RX_FCS_STRIP		(0x00000010) +#define MAC_RX_FSE			(0x00000004) +#define MAC_RX_RXD			(0x00000002) +#define MAC_RX_RXEN			(0x00000001) + +#define MAC_TX				(0x108) +#define MAC_TX_BFCS			(0x00000004) +#define MAC_TX_TXD			(0x00000002) +#define MAC_TX_TXEN			(0x00000001) + +#define FLOW				(0x10C) +#define FLOW_FORCE_FC			(0x80000000) +#define FLOW_TX_FCEN			(0x40000000) +#define FLOW_RX_FCEN			(0x20000000) +#define FLOW_FPF			(0x10000000) +#define FLOW_PAUSE_TIME			(0x0000FFFF) + +#define RAND_SEED			(0x110) +#define RAND_SEED_MASK			(0x0000FFFF) + +#define ERR_STS				(0x114) +#define ERR_STS_FCS_ERR			(0x00000100) +#define ERR_STS_LFRM_ERR		(0x00000080) +#define ERR_STS_RUNT_ERR		(0x00000040) +#define ERR_STS_COLLISION_ERR		(0x00000010) +#define ERR_STS_ALIGN_ERR		(0x00000008) +#define ERR_STS_URUN_ERR		(0x00000004) + +#define RX_ADDRH			(0x118) +#define RX_ADDRH_MASK			(0x0000FFFF) + +#define RX_ADDRL			(0x11C) + +#define MII_ACCESS			(0x120) +#define MII_ACCESS_PHY_ADDR		(0x0000F800) +#define MII_ACCESS_PHY_ADDR_SHIFT	(11) +#define MII_ACCESS_REG_ADDR		(0x000007C0) +#define MII_ACCESS_REG_ADDR_SHIFT	(6) +#define MII_ACCESS_READ			(0x00000000) +#define MII_ACCESS_WRITE		(0x00000002) +#define MII_ACCESS_BUSY			(0x00000001) + +#define MII_DATA			(0x124) +#define MII_DATA_MASK			(0x0000FFFF) + +#define WUCSR				(0x140) +#define WUCSR_PFDA_FR			(0x00000080) +#define WUCSR_WUFR			(0x00000040) +#define WUCSR_MPR			(0x00000020) +#define WUCSR_BCAST_FR			(0x00000010) +#define WUCSR_PFDA_EN			(0x00000008) +#define WUCSR_WUEN			(0x00000004) +#define WUCSR_MPEN			(0x00000002) +#define WUCSR_BCST_EN			(0x00000001) + +#define WUF_CFGX			(0x144) +#define WUF_CFGX_EN			(0x80000000) +#define WUF_CFGX_ATYPE			(0x03000000) +#define WUF_CFGX_ATYPE_UNICAST		(0x00000000) +#define WUF_CFGX_ATYPE_MULTICAST	(0x02000000) +#define WUF_CFGX_ATYPE_ALL		(0x03000000) +#define WUF_CFGX_PATTERN_OFFSET		(0x007F0000) +#define WUF_CFGX_PATTERN_OFFSET_SHIFT	(16) +#define WUF_CFGX_CRC16			(0x0000FFFF) +#define WUF_NUM				(8) + +#define WUF_MASKX			(0x170) +#define WUF_MASKX_AVALID		(0x80000000) +#define WUF_MASKX_ATYPE			(0x40000000) + +#define ADDR_FILTX			(0x300) +#define ADDR_FILTX_FB_VALID		(0x80000000) +#define ADDR_FILTX_FB_TYPE		(0x40000000) +#define ADDR_FILTX_FB_ADDRHI		(0x0000FFFF) +#define ADDR_FILTX_SB_ADDRLO		(0xFFFFFFFF) + +#define WUCSR2				(0x500) +#define WUCSR2_NS_RCD			(0x00000040) +#define WUCSR2_ARP_RCD			(0x00000020) +#define WUCSR2_TCPSYN_RCD		(0x00000010) +#define WUCSR2_NS_OFFLOAD		(0x00000004) +#define WUCSR2_ARP_OFFLOAD		(0x00000002) +#define WUCSR2_TCPSYN_OFFLOAD		(0x00000001) + +#define WOL_FIFO_STS			(0x504) + +#define IPV6_ADDRX			(0x510) + +#define IPV4_ADDRX			(0x590) + + +/* Vendor-specific PHY Definitions */ + +/* Mode Control/Status Register */ +#define PHY_MODE_CTRL_STS		(17) +#define MODE_CTRL_STS_EDPWRDOWN		((u16)0x2000) +#define MODE_CTRL_STS_ENERGYON		((u16)0x0002) + +#define PHY_INT_SRC			(29) +#define PHY_INT_SRC_ENERGY_ON		((u16)0x0080) +#define PHY_INT_SRC_ANEG_COMP		((u16)0x0040) +#define PHY_INT_SRC_REMOTE_FAULT	((u16)0x0020) +#define PHY_INT_SRC_LINK_DOWN		((u16)0x0010) + +#define PHY_INT_MASK			(30) +#define PHY_INT_MASK_ENERGY_ON		((u16)0x0080) +#define PHY_INT_MASK_ANEG_COMP		((u16)0x0040) +#define PHY_INT_MASK_REMOTE_FAULT	((u16)0x0020) +#define PHY_INT_MASK_LINK_DOWN		((u16)0x0010) +#define PHY_INT_MASK_DEFAULT		(PHY_INT_MASK_ANEG_COMP | \ +					 PHY_INT_MASK_LINK_DOWN) + +#define PHY_SPECIAL			(31) +#define PHY_SPECIAL_SPD			((u16)0x001C) +#define PHY_SPECIAL_SPD_10HALF		((u16)0x0004) +#define PHY_SPECIAL_SPD_10FULL		((u16)0x0014) +#define PHY_SPECIAL_SPD_100HALF		((u16)0x0008) +#define PHY_SPECIAL_SPD_100FULL		((u16)0x0018) + +/* USB Vendor Requests */ +#define USB_VENDOR_REQUEST_WRITE_REGISTER	0xA0 +#define USB_VENDOR_REQUEST_READ_REGISTER	0xA1 +#define USB_VENDOR_REQUEST_GET_STATS		0xA2 + +/* Interrupt Endpoint status word bitfields */ +#define INT_ENP_RDFO_INT		((u32)BIT(22)) +#define INT_ENP_TXE_INT			((u32)BIT(21)) +#define INT_ENP_TX_DIS_INT		((u32)BIT(19)) +#define INT_ENP_RX_DIS_INT		((u32)BIT(18)) +#define INT_ENP_PHY_INT			((u32)BIT(17)) +#define INT_ENP_MAC_ERR_INT		((u32)BIT(15)) +#define INT_ENP_RX_FIFO_DATA_INT	((u32)BIT(12)) + +#endif /* _SMSC75XX_H */ diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index df9179a1c93..3135af63d37 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -28,6 +28,7 @@  #include <linux/usb.h>  #include <linux/crc32.h>  #include <linux/usb/usbnet.h> +#include <linux/slab.h>  #include "smsc95xx.h"  #define SMSC_CHIPNAME			"smsc95xx" @@ -709,6 +710,8 @@ static void smsc95xx_start_rx_path(struct usbnet *dev)  static int smsc95xx_phy_initialize(struct usbnet *dev)  { +	int bmcr, timeout = 0; +  	/* Initialize MII structure */  	dev->mii.dev = dev->net;  	dev->mii.mdio_read = smsc95xx_mdio_read; @@ -717,7 +720,20 @@ static int smsc95xx_phy_initialize(struct usbnet *dev)  	dev->mii.reg_num_mask = 0x1f;  	dev->mii.phy_id = SMSC95XX_INTERNAL_PHY_ID; +	/* reset phy and wait for reset to complete */  	smsc95xx_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); + +	do { +		msleep(10); +		bmcr = smsc95xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR); +		timeout++; +	} while ((bmcr & MII_BMCR) && (timeout < 100)); + +	if (timeout >= 100) { +		netdev_warn(dev->net, "timeout on PHY Reset"); +		return -EIO; +	} +  	smsc95xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,  		ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP |  		ADVERTISE_PAUSE_ASYM); @@ -1174,9 +1190,21 @@ static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev,  	}  	if (csum) { -		u32 csum_preamble = smsc95xx_calc_csum_preamble(skb); -		skb_push(skb, 4); -		memcpy(skb->data, &csum_preamble, 4); +		if (skb->len <= 45) { +			/* workaround - hardware tx checksum does not work +			 * properly with extremely small packets */ +			long csstart = skb->csum_start - skb_headroom(skb); +			__wsum calc = csum_partial(skb->data + csstart, +				skb->len - csstart, 0); +			*((__sum16 *)(skb->data + csstart +				+ skb->csum_offset)) = csum_fold(calc); + +			csum = false; +		} else { +			u32 csum_preamble = smsc95xx_calc_csum_preamble(skb); +			skb_push(skb, 4); +			memcpy(skb->data, &csum_preamble, 4); +		}  	}  	skb_push(skb, 4); diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 17b6a62d206..7177abc78dc 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -43,6 +43,7 @@  #include <linux/mii.h>  #include <linux/usb.h>  #include <linux/usb/usbnet.h> +#include <linux/slab.h>  #define DRIVER_VERSION		"22-Aug-2005" diff --git a/drivers/net/veth.c b/drivers/net/veth.c index b583d4968ad..f9f0730b53d 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -9,6 +9,7 @@   */  #include <linux/netdevice.h> +#include <linux/slab.h>  #include <linux/ethtool.h>  #include <linux/etherdevice.h> diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 50f881aa393..388751aa66e 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -89,7 +89,6 @@ static const int multicast_filter_limit = 32;  #include <linux/timer.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/pci.h>  #include <linux/dma-mapping.h> diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 3a486f3bad3..bc278d4ee89 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -812,7 +812,7 @@ static void set_mii_flow_control(struct velocity_info *vptr)  	case FLOW_CNTL_TX_RX:  		MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); -		MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); +		MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);  		break;  	case FLOW_CNTL_DISABLE: diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 25dc77ccbf5..b0577dd1a42 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -25,6 +25,7 @@  #include <linux/virtio_net.h>  #include <linux/scatterlist.h>  #include <linux/if_vlan.h> +#include <linux/slab.h>  static int napi_weight = 128;  module_param(napi_weight, int, 0444); @@ -326,6 +327,7 @@ static int add_recvbuf_small(struct virtnet_info *vi, gfp_t gfp)  	struct scatterlist sg[2];  	int err; +	sg_init_table(sg, 2);  	skb = netdev_alloc_skb_ip_align(vi->dev, MAX_PACKET_LEN);  	if (unlikely(!skb))  		return -ENOMEM; @@ -351,6 +353,7 @@ static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp)  	char *p;  	int i, err, offset; +	sg_init_table(sg, MAX_SKB_FRAGS + 2);  	/* page in sg[MAX_SKB_FRAGS + 1] is list tail */  	for (i = MAX_SKB_FRAGS + 1; i > 1; --i) {  		first = get_a_page(vi, gfp); diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c index 32a75fa935e..a21a25d218b 100644 --- a/drivers/net/vxge/vxge-config.c +++ b/drivers/net/vxge/vxge-config.c @@ -15,6 +15,7 @@  #include <linux/etherdevice.h>  #include <linux/pci.h>  #include <linux/pci_hotplug.h> +#include <linux/slab.h>  #include "vxge-traffic.h"  #include "vxge-config.h" diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h index e7877df092f..13f5416307f 100644 --- a/drivers/net/vxge/vxge-config.h +++ b/drivers/net/vxge/vxge-config.h @@ -14,6 +14,7 @@  #ifndef VXGE_CONFIG_H  #define VXGE_CONFIG_H  #include <linux/list.h> +#include <linux/slab.h>  #ifndef VXGE_CACHE_LINE_SIZE  #define VXGE_CACHE_LINE_SIZE 128 diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/vxge/vxge-ethtool.c index c6736b97263..aaf374cfd32 100644 --- a/drivers/net/vxge/vxge-ethtool.c +++ b/drivers/net/vxge/vxge-ethtool.c @@ -12,6 +12,7 @@   * Copyright(c) 2002-2009 Neterion Inc.   ******************************************************************************/  #include<linux/ethtool.h> +#include <linux/slab.h>  #include <linux/pci.h>  #include <linux/etherdevice.h> diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 46a7c9e689e..ba6d0da78c3 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -43,6 +43,7 @@  #include <linux/if_vlan.h>  #include <linux/pci.h> +#include <linux/slab.h>  #include <linux/tcp.h>  #include <net/ip.h>  #include <linux/netdevice.h> diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index f88c07c1319..a4859f7a7cc 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -89,6 +89,7 @@  #include <linux/pci.h>  #include <linux/kernel.h>  #include <linux/mm.h> +#include <linux/slab.h>  #include <asm/system.h>  #include <asm/cache.h> diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 40d724a8e02..e087b9a6daa 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -20,6 +20,7 @@  #include <linux/version.h>  #include <linux/pci.h>  #include <linux/sched.h> +#include <linux/slab.h>  #include <linux/ioport.h>  #include <linux/init.h>  #include <linux/if.h> diff --git a/drivers/net/wan/hd64570.c b/drivers/net/wan/hd64570.c index 80114c93bae..4dde2ea4a18 100644 --- a/drivers/net/wan/hd64570.c +++ b/drivers/net/wan/hd64570.c @@ -37,7 +37,6 @@  #include <linux/module.h>  #include <linux/netdevice.h>  #include <linux/skbuff.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/types.h>  #include <asm/io.h> diff --git a/drivers/net/wan/hd64572.c b/drivers/net/wan/hd64572.c index 84f01373e11..aad9ed45c25 100644 --- a/drivers/net/wan/hd64572.c +++ b/drivers/net/wan/hd64572.c @@ -37,7 +37,6 @@  #include <linux/module.h>  #include <linux/netdevice.h>  #include <linux/skbuff.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/types.h>  #include <asm/io.h> diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c index 1ceccf1ca6c..ee7083fbea5 100644 --- a/drivers/net/wan/hdlc_cisco.c +++ b/drivers/net/wan/hdlc_cisco.c @@ -20,7 +20,6 @@  #include <linux/poll.h>  #include <linux/rtnetlink.h>  #include <linux/skbuff.h> -#include <linux/slab.h>  #undef DEBUG_HARD_HEADER diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index b9b9d6b01c0..941f053e650 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -628,9 +628,15 @@ static void ppp_stop(struct net_device *dev)  	ppp_cp_event(dev, PID_LCP, STOP, 0, 0, 0, NULL);  } +static void ppp_close(struct net_device *dev) +{ +	ppp_tx_flush(); +} +  static struct hdlc_proto proto = {  	.start		= ppp_start,  	.stop		= ppp_stop, +	.close		= ppp_close,  	.type_trans	= ppp_type_trans,  	.ioctl		= ppp_ioctl,  	.netif_rx	= ppp_rx, diff --git a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c index 19f51fdd552..5dc153e8a29 100644 --- a/drivers/net/wan/hdlc_raw.c +++ b/drivers/net/wan/hdlc_raw.c @@ -20,7 +20,6 @@  #include <linux/poll.h>  #include <linux/rtnetlink.h>  #include <linux/skbuff.h> -#include <linux/slab.h>  static int raw_ioctl(struct net_device *dev, struct ifreq *ifr); diff --git a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c index 1b30fcc2414..05c9b0b9623 100644 --- a/drivers/net/wan/hdlc_raw_eth.c +++ b/drivers/net/wan/hdlc_raw_eth.c @@ -11,6 +11,7 @@  #include <linux/errno.h>  #include <linux/etherdevice.h> +#include <linux/gfp.h>  #include <linux/hdlc.h>  #include <linux/if_arp.h>  #include <linux/inetdevice.h> @@ -21,7 +22,6 @@  #include <linux/poll.h>  #include <linux/rtnetlink.h>  #include <linux/skbuff.h> -#include <linux/slab.h>  static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr); diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c index 6e1ca256eff..c7adbb79f7c 100644 --- a/drivers/net/wan/hdlc_x25.c +++ b/drivers/net/wan/hdlc_x25.c @@ -10,6 +10,7 @@   */  #include <linux/errno.h> +#include <linux/gfp.h>  #include <linux/hdlc.h>  #include <linux/if_arp.h>  #include <linux/inetdevice.h> @@ -21,7 +22,6 @@  #include <linux/poll.h>  #include <linux/rtnetlink.h>  #include <linux/skbuff.h> -#include <linux/slab.h>  #include <net/x25device.h>  static int x25_ioctl(struct net_device *dev, struct ifreq *ifr); diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c index 74164d29524..48edc5f4dac 100644 --- a/drivers/net/wan/hostess_sv11.c +++ b/drivers/net/wan/hostess_sv11.c @@ -30,6 +30,7 @@  #include <linux/delay.h>  #include <linux/hdlc.h>  #include <linux/ioport.h> +#include <linux/slab.h>  #include <net/arp.h>  #include <asm/irq.h> diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c index c705046d861..0c2cdde686a 100644 --- a/drivers/net/wan/ixp4xx_hss.c +++ b/drivers/net/wan/ixp4xx_hss.c @@ -18,6 +18,7 @@  #include <linux/kernel.h>  #include <linux/platform_device.h>  #include <linux/poll.h> +#include <linux/slab.h>  #include <mach/npe.h>  #include <mach/qmgr.h> diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c index d1e3c673e9b..98e2f99903d 100644 --- a/drivers/net/wan/lapbether.c +++ b/drivers/net/wan/lapbether.c @@ -24,6 +24,7 @@  #include <linux/types.h>  #include <linux/socket.h>  #include <linux/in.h> +#include <linux/slab.h>  #include <linux/kernel.h>  #include <linux/string.h>  #include <linux/net.h> diff --git a/drivers/net/wan/lmc/lmc_media.c b/drivers/net/wan/lmc/lmc_media.c index f327674fc93..5920c996fcd 100644 --- a/drivers/net/wan/lmc/lmc_media.c +++ b/drivers/net/wan/lmc/lmc_media.c @@ -6,7 +6,6 @@  #include <linux/ptrace.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/in.h>  #include <linux/if_arp.h> diff --git a/drivers/net/wan/lmc/lmc_proto.c b/drivers/net/wan/lmc/lmc_proto.c index 044a48175c4..f600075e84a 100644 --- a/drivers/net/wan/lmc/lmc_proto.c +++ b/drivers/net/wan/lmc/lmc_proto.c @@ -25,7 +25,6 @@  #include <linux/ptrace.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/in.h>  #include <linux/if_arp.h> diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c index f4f1c00d0d2..3f744c64309 100644 --- a/drivers/net/wan/pc300_drv.c +++ b/drivers/net/wan/pc300_drv.c @@ -228,6 +228,7 @@ static char rcsid[] =  #include <linux/etherdevice.h>  #include <linux/spinlock.h>  #include <linux/if.h> +#include <linux/slab.h>  #include <net/arp.h>  #include <asm/io.h> diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index 25477b5cde4..cff13a9597c 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -43,7 +43,6 @@  #include <linux/fcntl.h>  #include <linux/ioport.h>  #include <linux/interrupt.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/netdevice.h> diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c index 61249f489e3..e91457d6023 100644 --- a/drivers/net/wan/sealevel.c +++ b/drivers/net/wan/sealevel.c @@ -23,6 +23,7 @@  #include <linux/hdlc.h>  #include <linux/ioport.h>  #include <linux/init.h> +#include <linux/slab.h>  #include <net/arp.h>  #include <asm/irq.h> diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index b9f520b7db6..80d5c5834a0 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -34,6 +34,7 @@  #include <linux/init.h>  #include <linux/rtnetlink.h>  #include <linux/compat.h> +#include <linux/slab.h>  #include "x25_asy.h"  #include <net/x25device.h> diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c index 0be7ec7299d..fbf5e843d48 100644 --- a/drivers/net/wan/z85230.c +++ b/drivers/net/wan/z85230.c @@ -47,6 +47,7 @@  #include <linux/hdlc.h>  #include <linux/ioport.h>  #include <linux/init.h> +#include <linux/gfp.h>  #include <asm/dma.h>  #include <asm/io.h>  #define RT_LOCK diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c index 94494554039..6180772dcc0 100644 --- a/drivers/net/wimax/i2400m/control.c +++ b/drivers/net/wimax/i2400m/control.c @@ -76,6 +76,7 @@  #include <stdarg.h>  #include "i2400m.h"  #include <linux/kernel.h> +#include <linux/slab.h>  #include <linux/wimax/i2400m.h> diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index 6cead321bc1..94dc83c3969 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c @@ -69,6 +69,7 @@  #include <linux/module.h>  #include <linux/moduleparam.h>  #include <linux/suspend.h> +#include <linux/slab.h>  #define D_SUBMODULE driver  #include "debug-levels.h" diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c index 25c24f0368d..3f283bff0ff 100644 --- a/drivers/net/wimax/i2400m/fw.c +++ b/drivers/net/wimax/i2400m/fw.c @@ -156,6 +156,7 @@   */  #include <linux/firmware.h>  #include <linux/sched.h> +#include <linux/slab.h>  #include <linux/usb.h>  #include "i2400m.h" diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c index 599aa4eb9ba..b811c2f1f5e 100644 --- a/drivers/net/wimax/i2400m/netdev.c +++ b/drivers/net/wimax/i2400m/netdev.c @@ -73,6 +73,7 @@   *                        alloc_netdev.   */  #include <linux/if_arp.h> +#include <linux/slab.h>  #include <linux/netdevice.h>  #include <linux/ethtool.h>  #include "i2400m.h" diff --git a/drivers/net/wimax/i2400m/op-rfkill.c b/drivers/net/wimax/i2400m/op-rfkill.c index 43927b5d7ad..035e4cf3e6e 100644 --- a/drivers/net/wimax/i2400m/op-rfkill.c +++ b/drivers/net/wimax/i2400m/op-rfkill.c @@ -34,6 +34,7 @@   */  #include "i2400m.h"  #include <linux/wimax/i2400m.h> +#include <linux/slab.h> diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c index 7ddb173fd4a..fa2e11e5b4b 100644 --- a/drivers/net/wimax/i2400m/rx.c +++ b/drivers/net/wimax/i2400m/rx.c @@ -144,6 +144,7 @@   *       i2400m_msg_size_check   *       wimax_msg   */ +#include <linux/slab.h>  #include <linux/kernel.h>  #include <linux/if_arp.h>  #include <linux/netdevice.h> diff --git a/drivers/net/wimax/i2400m/sdio-rx.c b/drivers/net/wimax/i2400m/sdio-rx.c index 8adf6c9b6f8..d619da33f20 100644 --- a/drivers/net/wimax/i2400m/sdio-rx.c +++ b/drivers/net/wimax/i2400m/sdio-rx.c @@ -65,6 +65,7 @@  #include <linux/skbuff.h>  #include <linux/mmc/sdio.h>  #include <linux/mmc/sdio_func.h> +#include <linux/slab.h>  #include "i2400m-sdio.h"  #define D_SUBMODULE rx diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c index 14f876b1358..7632f80954e 100644 --- a/drivers/net/wimax/i2400m/sdio.c +++ b/drivers/net/wimax/i2400m/sdio.c @@ -48,6 +48,7 @@   *     __i2400ms_send_barker()   */ +#include <linux/slab.h>  #include <linux/debugfs.h>  #include <linux/mmc/sdio_ids.h>  #include <linux/mmc/sdio.h> diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c index 54480e8947f..b0cb90624cf 100644 --- a/drivers/net/wimax/i2400m/tx.c +++ b/drivers/net/wimax/i2400m/tx.c @@ -244,6 +244,7 @@   *                               (FIFO empty).   */  #include <linux/netdevice.h> +#include <linux/slab.h>  #include "i2400m.h" diff --git a/drivers/net/wimax/i2400m/usb-fw.c b/drivers/net/wimax/i2400m/usb-fw.c index ce6b9938fde..b58ec56b86f 100644 --- a/drivers/net/wimax/i2400m/usb-fw.c +++ b/drivers/net/wimax/i2400m/usb-fw.c @@ -73,6 +73,7 @@   *   i2400m_notif_submit   */  #include <linux/usb.h> +#include <linux/gfp.h>  #include "i2400m-usb.h" diff --git a/drivers/net/wimax/i2400m/usb-notif.c b/drivers/net/wimax/i2400m/usb-notif.c index f88d1c6e35c..7b6a1d98bd7 100644 --- a/drivers/net/wimax/i2400m/usb-notif.c +++ b/drivers/net/wimax/i2400m/usb-notif.c @@ -56,6 +56,7 @@   *     i2400mu_rx_kick()   */  #include <linux/usb.h> +#include <linux/slab.h>  #include "i2400m-usb.h" diff --git a/drivers/net/wimax/i2400m/usb-rx.c b/drivers/net/wimax/i2400m/usb-rx.c index ba1b02362df..a26483a812a 100644 --- a/drivers/net/wimax/i2400m/usb-rx.c +++ b/drivers/net/wimax/i2400m/usb-rx.c @@ -83,6 +83,7 @@   * i2400mu_rx_release()            called from i2400mu_bus_dev_stop()   */  #include <linux/workqueue.h> +#include <linux/slab.h>  #include <linux/usb.h>  #include "i2400m-usb.h" diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c index 99f04c47589..d8c4d6497fd 100644 --- a/drivers/net/wimax/i2400m/usb.c +++ b/drivers/net/wimax/i2400m/usb.c @@ -66,6 +66,7 @@  #include "i2400m-usb.h"  #include <linux/wimax/i2400m.h>  #include <linux/debugfs.h> +#include <linux/slab.h>  #define D_SUBMODULE usb diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 547912e6843..ab61d2b558d 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -18,6 +18,7 @@  #include <linux/init.h>  #include <linux/if.h>  #include <linux/skbuff.h> +#include <linux/slab.h>  #include <linux/etherdevice.h>  #include <linux/pci.h>  #include <linux/delay.h> diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 257c734733d..c5369298099 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -38,6 +38,7 @@   */  #include <linux/init.h> +#include <linux/slab.h>  #include <linux/module.h>  #include <linux/etherdevice.h>  #include <net/mac80211.h> diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index 4e30197afff..99a6da464bd 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -38,6 +38,7 @@   */  #include <linux/module.h> +#include <linux/slab.h>  #include <linux/usb.h>  #include <linux/firmware.h>  #include <linux/etherdevice.h> @@ -94,6 +95,8 @@ static struct usb_device_id ar9170_usb_ids[] = {  	{ USB_DEVICE(0x04bb, 0x093f) },  	/* AVM FRITZ!WLAN USB Stick N */  	{ USB_DEVICE(0x057C, 0x8401) }, +	/* NEC WL300NU-G */ +	{ USB_DEVICE(0x0409, 0x0249) },  	/* AVM FRITZ!WLAN USB Stick N 2.4 */  	{ USB_DEVICE(0x057C, 0x8402), .driver_info = AR9170_REQ_FW1_ONLY }, @@ -416,7 +419,7 @@ static int ar9170_usb_exec_cmd(struct ar9170 *ar, enum ar9170_cmd cmd,  	spin_unlock_irqrestore(&aru->common.cmdlock, flags);  	usb_fill_int_urb(urb, aru->udev, -			 usb_sndbulkpipe(aru->udev, AR9170_EP_CMD), +			 usb_sndintpipe(aru->udev, AR9170_EP_CMD),  			 aru->common.cmdbuf, plen + 4,  			 ar9170_usb_tx_urb_complete, NULL, 1); diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 42284445b75..dc0786cc263 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -21,6 +21,7 @@  \*************************************/  #include <linux/pci.h> +#include <linux/slab.h>  #include "ath5k.h"  #include "reg.h"  #include "debug.h" diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 8dce0077b02..3abbe7513ab 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -50,6 +50,7 @@  #include <linux/pci.h>  #include <linux/ethtool.h>  #include <linux/uaccess.h> +#include <linux/slab.h>  #include <net/ieee80211_radiotap.h> diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index 10b52262b23..67665cdc7af 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -21,6 +21,8 @@  * EEPROM access functions and helpers *  \*************************************/ +#include <linux/slab.h> +  #include "ath5k.h"  #include "reg.h"  #include "debug.h" diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index eff3323efb4..68e2bccd90d 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -23,6 +23,7 @@  #define _ATH5K_PHY  #include <linux/delay.h> +#include <linux/slab.h>  #include "ath5k.h"  #include "reg.h" diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 42d2a506845..081e0085ed4 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -14,6 +14,7 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ +#include <linux/slab.h>  #include <asm/unaligned.h>  #include "ath9k.h" diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 2e767cf22f1..78b571129c9 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -15,6 +15,7 @@   */  #include <linux/io.h> +#include <linux/slab.h>  #include <asm/unaligned.h>  #include "hw.h" diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 623c2f88498..3d4d897add6 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -14,6 +14,8 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ +#include <linux/slab.h> +  #include "ath9k.h"  static char *dev_info = "ath9k"; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 67ca4e5a601..115e1aeedb5 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1532,8 +1532,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)  		all_wiphys_idle =  ath9k_all_wiphys_idle(sc);  		ath9k_set_wiphy_idle(aphy, idle); -		if (!idle && all_wiphys_idle) -			enable_radio = true; +		enable_radio = (!idle && all_wiphys_idle);  		/*  		 * After we unlock here its possible another wiphy diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index c3b59390fe3..2547b3c4a26 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -39,6 +39,8 @@   * AR9287 - 11n single-band 1x1 MIMO for USB   */ +#include <linux/slab.h> +  #include "hw.h"  /** diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 0e79e58cf4c..244e1c62917 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -15,6 +15,8 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ +#include <linux/slab.h> +  #include "ath9k.h"  static const struct ath_rate_table ar5416_11na_ratetable = { diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index a43fbf84dab..00c0e21a4af 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c @@ -14,6 +14,8 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ +#include <linux/slab.h> +  #include "ath9k.h"  struct ath9k_vif_iter_data { diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index b2c8207f7bc..294b486bc3e 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1353,25 +1353,6 @@ static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)  	return htype;  } -static bool is_pae(struct sk_buff *skb) -{ -	struct ieee80211_hdr *hdr; -	__le16 fc; - -	hdr = (struct ieee80211_hdr *)skb->data; -	fc = hdr->frame_control; - -	if (ieee80211_is_data(fc)) { -		if (ieee80211_is_nullfunc(fc) || -		    /* Port Access Entity (IEEE 802.1X) */ -		    (skb->protocol == cpu_to_be16(ETH_P_PAE))) { -			return true; -		} -	} - -	return false; -} -  static int get_hw_crypto_keytype(struct sk_buff *skb)  {  	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); @@ -1696,7 +1677,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,  			goto tx_done;  		} -		if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && !is_pae(skb)) { +		if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {  			/*  			 * Try aggregation if it's a unicast data frame  			 * and the destination is HT capable. diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 04abd1f556b..00489c40be0 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -15,7 +15,6 @@   */  #include <linux/kernel.h> -#include <linux/slab.h>  #include <net/cfg80211.h>  #include <net/mac80211.h>  #include "regd.h" diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index be7abf8916a..fa40fdfea71 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -38,6 +38,7 @@  #include <linux/delay.h>  #include <linux/skbuff.h>  #include <linux/etherdevice.h> +#include <linux/slab.h>  #include <asm/div64.h> diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c index 976104f634a..94e4f1378fc 100644 --- a/drivers/net/wireless/b43/lo.c +++ b/drivers/net/wireless/b43/lo.c @@ -34,6 +34,7 @@  #include <linux/delay.h>  #include <linux/sched.h> +#include <linux/slab.h>  static struct b43_lo_calib *b43_find_lo_calib(struct b43_txpower_lo_control *lo, diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 1521b1e78d2..9a374ef83a2 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -42,6 +42,7 @@  #include <linux/skbuff.h>  #include <linux/io.h>  #include <linux/dma-mapping.h> +#include <linux/slab.h>  #include <asm/unaligned.h>  #include "b43.h" diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c index 984174bc7b0..609e7051e01 100644 --- a/drivers/net/wireless/b43/pcmcia.c +++ b/drivers/net/wireless/b43/pcmcia.c @@ -24,6 +24,7 @@  #include "pcmcia.h"  #include <linux/ssb/ssb.h> +#include <linux/slab.h>  #include <pcmcia/cs_types.h>  #include <pcmcia/cs.h> diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index d90217c3a70..b6428ec16dd 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c @@ -26,6 +26,8 @@  */ +#include <linux/slab.h> +  #include "b43.h"  #include "phy_a.h"  #include "phy_common.h" diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 382826a8da8..29bf34ced86 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -33,6 +33,7 @@  #include "main.h"  #include <linux/bitrev.h> +#include <linux/slab.h>  static const s8 b43_tssi2dbm_g_table[] = { diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 185219e0a55..c6afe9d9459 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -23,6 +23,8 @@  */ +#include <linux/slab.h> +  #include "b43.h"  #include "main.h"  #include "phy_lp.h" diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 795bb1e3345..9c7cd282e46 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -23,6 +23,7 @@  */  #include <linux/delay.h> +#include <linux/slab.h>  #include <linux/types.h>  #include "b43.h" diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index a6062c3e89a..aa12273ae71 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -31,6 +31,7 @@  #include <linux/delay.h>  #include <linux/sched.h> +#include <linux/slab.h>  static u16 generate_cookie(struct b43_pio_txqueue *q, diff --git a/drivers/net/wireless/b43/sdio.c b/drivers/net/wireless/b43/sdio.c index 0d3ac64147a..4e56b7bbceb 100644 --- a/drivers/net/wireless/b43/sdio.c +++ b/drivers/net/wireless/b43/sdio.c @@ -16,6 +16,7 @@  #include <linux/mmc/card.h>  #include <linux/mmc/sdio_func.h>  #include <linux/mmc/sdio_ids.h> +#include <linux/slab.h>  #include <linux/ssb/ssb.h>  #include "sdio.h" diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index 8b9387c6ff3..e91520d0312 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -37,6 +37,7 @@  #include <linux/pci.h>  #include <linux/delay.h>  #include <linux/skbuff.h> +#include <linux/slab.h>  #include <net/dst.h>  /* 32bit DMA ops. */ diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 1d070be5a67..bb2dd9329aa 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -40,6 +40,7 @@  #include <linux/sched.h>  #include <linux/skbuff.h>  #include <linux/dma-mapping.h> +#include <linux/slab.h>  #include <net/dst.h>  #include <asm/unaligned.h> diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c index aaf227203a9..35033dd342c 100644 --- a/drivers/net/wireless/b43legacy/phy.c +++ b/drivers/net/wireless/b43legacy/phy.c @@ -32,6 +32,7 @@  #include <linux/delay.h>  #include <linux/pci.h>  #include <linux/sched.h> +#include <linux/slab.h>  #include <linux/types.h>  #include "b43legacy.h" diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c index 017c0e9c37e..b033b0ed4ca 100644 --- a/drivers/net/wireless/b43legacy/pio.c +++ b/drivers/net/wireless/b43legacy/pio.c @@ -29,6 +29,7 @@  #include "xmit.h"  #include <linux/delay.h> +#include <linux/slab.h>  static void tx_start(struct b43legacy_pioqueue *queue) diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c index 3816df96a66..f4c56121d38 100644 --- a/drivers/net/wireless/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c @@ -1,4 +1,5 @@  #include <linux/etherdevice.h> +#include <linux/slab.h>  #include <net/lib80211.h>  #include <linux/if_arp.h> diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index 90108b698f1..c34a3b7f129 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -1,3 +1,5 @@ +#include <linux/slab.h> +  #include "hostap_80211.h"  #include "hostap_common.h"  #include "hostap_wlan.h" diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index a2a203c90ba..7e72ac1de49 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -20,6 +20,7 @@  #include <linux/delay.h>  #include <linux/random.h>  #include <linux/if_arp.h> +#include <linux/slab.h>  #include "hostap_wlan.h"  #include "hostap.h" diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index d19748d90aa..a36501dbbe0 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -3,6 +3,7 @@  #include <linux/module.h>  #include <linux/init.h>  #include <linux/if.h> +#include <linux/slab.h>  #include <linux/wait.h>  #include <linux/timer.h>  #include <linux/skbuff.h> diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c index 4dfb40a84c9..d737091cf6a 100644 --- a/drivers/net/wireless/hostap/hostap_info.c +++ b/drivers/net/wireless/hostap/hostap_info.c @@ -2,6 +2,7 @@  #include <linux/if_arp.h>  #include <linux/sched.h> +#include <linux/slab.h>  #include "hostap_wlan.h"  #include "hostap.h"  #include "hostap_ap.h" diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index 9419cebca8a..9a082308a9d 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -1,5 +1,6 @@  /* ioctl() (mostly Linux Wireless Extensions) routines for Host AP driver */ +#include <linux/slab.h>  #include <linux/types.h>  #include <linux/sched.h>  #include <linux/ethtool.h> diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c index 4d97ae37499..d24dc7dc072 100644 --- a/drivers/net/wireless/hostap/hostap_pci.c +++ b/drivers/net/wireless/hostap/hostap_pci.c @@ -9,6 +9,7 @@  #include <linux/if.h>  #include <linux/skbuff.h>  #include <linux/netdevice.h> +#include <linux/slab.h>  #include <linux/workqueue.h>  #include <linux/wireless.h>  #include <net/iw_handler.h> diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c index fc04ccdc5be..33e79037770 100644 --- a/drivers/net/wireless/hostap/hostap_plx.c +++ b/drivers/net/wireless/hostap/hostap_plx.c @@ -12,6 +12,7 @@  #include <linux/if.h>  #include <linux/skbuff.h>  #include <linux/netdevice.h> +#include <linux/slab.h>  #include <linux/workqueue.h>  #include <linux/wireless.h>  #include <net/iw_handler.h> diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 5c7aa1b1eb5..8d72e3d1958 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -31,6 +31,7 @@  ******************************************************************************/  #include <linux/sched.h> +#include <linux/slab.h>  #include "ipw2200.h" diff --git a/drivers/net/wireless/ipw2x00/libipw_geo.c b/drivers/net/wireless/ipw2x00/libipw_geo.c index 65e8c175a4a..c9fe3c99cb0 100644 --- a/drivers/net/wireless/ipw2x00/libipw_geo.c +++ b/drivers/net/wireless/ipw2x00/libipw_geo.c @@ -34,7 +34,6 @@  #include <linux/netdevice.h>  #include <linux/proc_fs.h>  #include <linux/skbuff.h> -#include <linux/slab.h>  #include <linux/tcp.h>  #include <linux/types.h>  #include <linux/wireless.h> diff --git a/drivers/net/wireless/ipw2x00/libipw_rx.c b/drivers/net/wireless/ipw2x00/libipw_rx.c index 282b1f7ff1e..39a34da52d5 100644 --- a/drivers/net/wireless/ipw2x00/libipw_rx.c +++ b/drivers/net/wireless/ipw2x00/libipw_rx.c @@ -17,6 +17,7 @@  #include <linux/errno.h>  #include <linux/if_arp.h>  #include <linux/in6.h> +#include <linux/gfp.h>  #include <linux/in.h>  #include <linux/ip.h>  #include <linux/kernel.h> @@ -24,7 +25,6 @@  #include <linux/netdevice.h>  #include <linux/proc_fs.h>  #include <linux/skbuff.h> -#include <linux/slab.h>  #include <linux/tcp.h>  #include <linux/types.h>  #include <linux/wireless.h> diff --git a/drivers/net/wireless/ipw2x00/libipw_wx.c b/drivers/net/wireless/ipw2x00/libipw_wx.c index 4d89f66f53b..3633c6682e4 100644 --- a/drivers/net/wireless/ipw2x00/libipw_wx.c +++ b/drivers/net/wireless/ipw2x00/libipw_wx.c @@ -31,6 +31,7 @@  ******************************************************************************/  #include <linux/kmod.h> +#include <linux/slab.h>  #include <linux/module.h>  #include <linux/jiffies.h> diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 47909f94271..902c4d4293e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -27,6 +27,7 @@  #include <linux/kernel.h>  #include <linux/init.h>  #include <linux/skbuff.h> +#include <linux/slab.h>  #include <linux/wireless.h>  #include <net/mac80211.h> diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index e0678d92105..0728054a22d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -27,6 +27,7 @@  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/init.h> +#include <linux/slab.h>  #include <linux/pci.h>  #include <linux/dma-mapping.h>  #include <linux/delay.h> diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 1bd2cd83602..8972166386c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2015,7 +2015,9 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,  			IWL_DEBUG_TX_REPLY(priv, "Retry scheduler reclaim scd_ssn "  					   "%d index %d\n", scd_ssn , index);  			freed = iwl_tx_queue_reclaim(priv, txq_id, index); -			iwl_free_tfds_in_queue(priv, sta_id, tid, freed); +			if (qc) +				iwl_free_tfds_in_queue(priv, sta_id, +						       tid, freed);  			if (priv->mac80211_registered &&  			    (iwl_queue_space(&txq->q) > txq->q.low_mark) && @@ -2042,13 +2044,14 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,  		freed = iwl_tx_queue_reclaim(priv, txq_id, index);  		if (qc && likely(sta_id != IWL_INVALID_STATION)) -			priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; +			iwl_free_tfds_in_queue(priv, sta_id, tid, freed); +		else if (sta_id == IWL_INVALID_STATION) +			IWL_DEBUG_TX_REPLY(priv, "Station not known\n");  		if (priv->mac80211_registered &&  		    (iwl_queue_space(&txq->q) > txq->q.low_mark))  			iwl_wake_queue(priv, txq_id);  	} -  	if (qc && likely(sta_id != IWL_INVALID_STATION))  		iwl_txq_check_empty(priv, sta_id, tid, txq_id); diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index c4844adff92..92b3e64fc14 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -259,7 +259,7 @@ static struct iwl_lib_ops iwl6000_lib = {  			EEPROM_5000_REG_BAND_3_CHANNELS,  			EEPROM_5000_REG_BAND_4_CHANNELS,  			EEPROM_5000_REG_BAND_5_CHANNELS, -			EEPROM_5000_REG_BAND_24_HT40_CHANNELS, +			EEPROM_6000_REG_BAND_24_HT40_CHANNELS,  			EEPROM_5000_REG_BAND_52_HT40_CHANNELS  		},  		.verify_signature  = iwlcore_eeprom_verify_signature, @@ -323,7 +323,7 @@ static struct iwl_lib_ops iwl6050_lib = {  			EEPROM_5000_REG_BAND_3_CHANNELS,  			EEPROM_5000_REG_BAND_4_CHANNELS,  			EEPROM_5000_REG_BAND_5_CHANNELS, -			EEPROM_5000_REG_BAND_24_HT40_CHANNELS, +			EEPROM_6000_REG_BAND_24_HT40_CHANNELS,  			EEPROM_5000_REG_BAND_52_HT40_CHANNELS  		},  		.verify_signature  = iwlcore_eeprom_verify_signature, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 8bf7c20b9d3..1460116d329 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -26,6 +26,7 @@  #include <linux/kernel.h>  #include <linux/init.h>  #include <linux/skbuff.h> +#include <linux/slab.h>  #include <linux/wireless.h>  #include <net/mac80211.h> @@ -345,6 +346,17 @@ static inline int get_num_of_ant_from_rate(u32 rate_n_flags)  	       !!(rate_n_flags & RATE_MCS_ANT_C_MSK);  } +/* + * Static function to get the expected throughput from an iwl_scale_tbl_info + * that wraps a NULL pointer check + */ +static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index) +{ +	if (tbl->expected_tpt) +		return tbl->expected_tpt[rs_index]; +	return 0; +} +  /**   * rs_collect_tx_data - Update the success/failure sliding window   * @@ -352,19 +364,21 @@ static inline int get_num_of_ant_from_rate(u32 rate_n_flags)   * at this rate.  window->data contains the bitmask of successful   * packets.   */ -static int rs_collect_tx_data(struct iwl_rate_scale_data *windows, -			      int scale_index, s32 tpt, int attempts, -			      int successes) +static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, +			      int scale_index, int attempts, int successes)  {  	struct iwl_rate_scale_data *window = NULL;  	static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1)); -	s32 fail_count; +	s32 fail_count, tpt;  	if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)  		return -EINVAL;  	/* Select window for current tx bit rate */ -	window = &(windows[scale_index]); +	window = &(tbl->win[scale_index]); + +	/* Get expected throughput */ +	tpt = get_expected_tpt(tbl, scale_index);  	/*  	 * Keep track of only the latest 62 tx frame attempts in this rate's @@ -738,16 +752,6 @@ static bool table_type_matches(struct iwl_scale_tbl_info *a,  	return (a->lq_type == b->lq_type) && (a->ant_type == b->ant_type) &&  		(a->is_SGI == b->is_SGI);  } -/* - * Static function to get the expected throughput from an iwl_scale_tbl_info - * that wraps a NULL pointer check - */ -static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index) -{ -	if (tbl->expected_tpt) -		return tbl->expected_tpt[rs_index]; -	return 0; -}  /*   * mac80211 sends us Tx status @@ -764,12 +768,10 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;  	struct iwl_priv *priv = (struct iwl_priv *)priv_r;  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -	struct iwl_rate_scale_data *window = NULL;  	enum mac80211_rate_control_flags mac_flags;  	u32 tx_rate;  	struct iwl_scale_tbl_info tbl_type; -	struct iwl_scale_tbl_info *curr_tbl, *other_tbl; -	s32 tpt = 0; +	struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;  	IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n"); @@ -852,7 +854,6 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,  		IWL_DEBUG_RATE(priv, "Neither active nor search matches tx rate\n");  		return;  	} -	window = (struct iwl_rate_scale_data *)&(curr_tbl->win[0]);  	/*  	 * Updating the frame history depends on whether packets were @@ -865,8 +866,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,  		tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags);  		rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type,  				&rs_index); -		tpt = get_expected_tpt(curr_tbl, rs_index); -		rs_collect_tx_data(window, rs_index, tpt, +		rs_collect_tx_data(curr_tbl, rs_index,  				   info->status.ampdu_ack_len,  				   info->status.ampdu_ack_map); @@ -896,19 +896,13 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,  			 * table as active/search.  			 */  			if (table_type_matches(&tbl_type, curr_tbl)) -				tpt = get_expected_tpt(curr_tbl, rs_index); +				tmp_tbl = curr_tbl;  			else if (table_type_matches(&tbl_type, other_tbl)) -				tpt = get_expected_tpt(other_tbl, rs_index); +				tmp_tbl = other_tbl;  			else  				continue; - -			/* Constants mean 1 transmission, 0 successes */ -			if (i < retries) -				rs_collect_tx_data(window, rs_index, tpt, 1, -						0); -			else -				rs_collect_tx_data(window, rs_index, tpt, 1, -						legacy_success); +			rs_collect_tx_data(tmp_tbl, rs_index, 1, +					   i < retries ? 0 : legacy_success);  		}  		/* Update success/fail counts if not searching for new mode */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 818367b57ba..bdff56583e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -31,6 +31,7 @@  #include <linux/module.h>  #include <linux/init.h>  #include <linux/pci.h> +#include <linux/slab.h>  #include <linux/dma-mapping.h>  #include <linux/delay.h>  #include <linux/sched.h> @@ -1258,7 +1259,15 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)  	/* Ack/clear/reset pending uCode interrupts.  	 * Note:  Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,  	 */ -	iwl_write32(priv, CSR_INT, priv->inta); +	/* There is a hardware bug in the interrupt mask function that some +	 * interrupts (i.e. CSR_INT_BIT_SCD) can still be generated even if +	 * they are disabled in the CSR_INT_MASK register. Furthermore the +	 * ICT interrupt handling mechanism has another bug that might cause +	 * these unmasked interrupts fail to be detected. We workaround the +	 * hardware bugs here by ACKing all the possible interrupts so that +	 * interrupt coalescing can still be achieved. +	 */ +	iwl_write32(priv, CSR_INT, priv->inta | ~priv->inta_mask);  	inta = priv->inta; @@ -2644,7 +2653,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv)  		BIT(NL80211_IFTYPE_STATION) |  		BIT(NL80211_IFTYPE_ADHOC); -	hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY | +	hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |  			    WIPHY_FLAG_DISABLE_BEACON_HINTS;  	/* @@ -3322,6 +3331,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)  	cancel_delayed_work_sync(&priv->init_alive_start);  	cancel_delayed_work(&priv->scan_check); +	cancel_work_sync(&priv->start_internal_scan);  	cancel_delayed_work(&priv->alive_start);  	cancel_work_sync(&priv->beacon_update);  	del_timer_sync(&priv->statistics_periodic); diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 845831ac053..8b516c5ff0b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -60,6 +60,7 @@   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   *****************************************************************************/ +#include <linux/slab.h>  #include <net/mac80211.h>  #include "iwl-dev.h" @@ -807,6 +808,18 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,  		}  	} +	/* +	 * The above algorithm sometimes fails when the ucode +	 * reports 0 for all chains. It's not clear why that +	 * happens to start with, but it is then causing trouble +	 * because this can make us enable more chains than the +	 * hardware really has. +	 * +	 * To be safe, simply mask out any chains that we know +	 * are not on the device. +	 */ +	active_chains &= priv->hw_params.valid_rx_ant; +  	num_tx_chains = 0;  	for (i = 0; i < NUM_RX_CHAINS; i++) {  		/* loops on all the bits of diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 112149e9b31..049b652bcb5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -30,6 +30,7 @@  #include <linux/module.h>  #include <linux/etherdevice.h>  #include <linux/sched.h> +#include <linux/slab.h>  #include <net/mac80211.h>  #include "iwl-eeprom.h" @@ -307,10 +308,13 @@ int iwl_hw_nic_init(struct iwl_priv *priv)  	spin_unlock_irqrestore(&priv->lock, flags); -	/* Allocate and init all Tx and Command queues */ -	ret = iwl_txq_ctx_reset(priv); -	if (ret) -		return ret; +	/* Allocate or reset and init all Tx and Command queues */ +	if (!priv->txq) { +		ret = iwl_txq_ctx_alloc(priv); +		if (ret) +			return ret; +	} else +		iwl_txq_ctx_reset(priv);  	set_bit(STATUS_INIT, &priv->status); @@ -3354,7 +3358,6 @@ static void iwl_force_rf_reset(struct iwl_priv *priv)  	 */  	IWL_DEBUG_INFO(priv, "perform radio reset.\n");  	iwl_internal_short_hw_scan(priv); -	return;  } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 4ef7739f9e8..36940a9ec6b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -442,7 +442,8 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);  /*****************************************************  * TX  ******************************************************/ -int iwl_txq_ctx_reset(struct iwl_priv *priv); +int iwl_txq_ctx_alloc(struct iwl_priv *priv); +void iwl_txq_ctx_reset(struct iwl_priv *priv);  void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);  int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,  				 struct iwl_tx_queue *txq, @@ -456,6 +457,8 @@ void iwl_free_tfds_in_queue(struct iwl_priv *priv,  void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);  int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,  		      int slots_num, u32 txq_id); +void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq, +			int slots_num, u32 txq_id);  void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id);  int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn);  int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid); @@ -503,7 +506,7 @@ void iwl_init_scan_params(struct iwl_priv *priv);  int iwl_scan_cancel(struct iwl_priv *priv);  int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);  int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req); -int iwl_internal_short_hw_scan(struct iwl_priv *priv); +void iwl_internal_short_hw_scan(struct iwl_priv *priv);  int iwl_force_reset(struct iwl_priv *priv, int mode);  u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,  		       const u8 *ie, int ie_len, int left); diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 7bf44f14679..b6e1b0ebe23 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -26,6 +26,7 @@   * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497   *****************************************************************************/ +#include <linux/slab.h>  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/debugfs.h> diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 6054c5fba0c..ef1720a852e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1296,6 +1296,7 @@ struct iwl_priv {  	struct work_struct tt_work;  	struct work_struct ct_enter;  	struct work_struct ct_exit; +	struct work_struct start_internal_scan;  	struct tasklet_struct irq_tasklet; diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c index 36580d8d8b8..2ffc2edbf4f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c @@ -28,6 +28,8 @@  /* sparse doesn't like tracepoint macros */  #ifndef __CHECKER__ +#include "iwl-dev.h" +  #define CREATE_TRACE_POINTS  #include "iwl-devtrace.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index ff4d012ce26..ae7319bb3a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -28,7 +28,6 @@  #define __IWLWIFI_DEVICE_TRACE  #include <linux/tracepoint.h> -#include "iwl-dev.h"  #if !defined(CONFIG_IWLWIFI_DEVICE_TRACING) || defined(__CHECKER__)  #undef TRACE_EVENT diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index fd37152abae..fb5bb487f3b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -63,6 +63,7 @@  #include <linux/kernel.h>  #include <linux/module.h> +#include <linux/slab.h>  #include <linux/init.h>  #include <net/mac80211.h> diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 4e1ba824dc5..8171c701e4e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -203,6 +203,10 @@ struct iwl_eeprom_enhanced_txpwr {  #define EEPROM_5000_REG_BAND_52_HT40_CHANNELS  ((0x92)\  		| INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 22  bytes */ +/* 6000 regulatory - indirect access */ +#define EEPROM_6000_REG_BAND_24_HT40_CHANNELS  ((0x80)\ +		| INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 14  bytes */ +  /* 6000 and up regulatory tx power - indirect access */  /* max. elements per section */  #define EEPROM_MAX_TXPOWER_SECTION_ELEMENTS	(8) diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index c719baf2585..16eb3ced9b3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -31,6 +31,7 @@  #include <linux/io.h> +#include "iwl-dev.h"  #include "iwl-debug.h"  #include "iwl-devtrace.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 1a1a9f081cc..548dac2f6a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -29,6 +29,7 @@  #include <linux/kernel.h>  #include <linux/module.h> +#include <linux/slab.h>  #include <linux/init.h>  #include <net/mac80211.h> diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index df257bc15f4..e5eb339107d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -28,6 +28,7 @@   *****************************************************************************/  #include <linux/etherdevice.h> +#include <linux/slab.h>  #include <net/mac80211.h>  #include <asm/unaligned.h>  #include "iwl-eeprom.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index bd2f7c42056..12e455a4b90 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -25,6 +25,7 @@   *  Intel Linux Wireless <ilw@linux.intel.com>   * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497   *****************************************************************************/ +#include <linux/slab.h>  #include <linux/types.h>  #include <linux/etherdevice.h>  #include <net/mac80211.h> @@ -469,6 +470,8 @@ EXPORT_SYMBOL(iwl_init_scan_params);  static int iwl_scan_initiate(struct iwl_priv *priv)  { +	WARN_ON(!mutex_is_locked(&priv->mutex)); +  	IWL_DEBUG_INFO(priv, "Starting scan...\n");  	set_bit(STATUS_SCANNING, &priv->status);  	priv->is_internal_short_scan = false; @@ -546,24 +549,31 @@ EXPORT_SYMBOL(iwl_mac_hw_scan);   * internal short scan, this function should only been called while associated.   * It will reset and tune the radio to prevent possible RF related problem   */ -int iwl_internal_short_hw_scan(struct iwl_priv *priv) +void iwl_internal_short_hw_scan(struct iwl_priv *priv)  { -	int ret = 0; +	queue_work(priv->workqueue, &priv->start_internal_scan); +} + +static void iwl_bg_start_internal_scan(struct work_struct *work) +{ +	struct iwl_priv *priv = +		container_of(work, struct iwl_priv, start_internal_scan); + +	mutex_lock(&priv->mutex);  	if (!iwl_is_ready_rf(priv)) { -		ret = -EIO;  		IWL_DEBUG_SCAN(priv, "not ready or exit pending\n"); -		goto out; +		goto unlock;  	} +  	if (test_bit(STATUS_SCANNING, &priv->status)) {  		IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); -		ret = -EAGAIN; -		goto out; +		goto unlock;  	} +  	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {  		IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n"); -		ret = -EAGAIN; -		goto out; +		goto unlock;  	}  	priv->scan_bands = 0; @@ -576,9 +586,8 @@ int iwl_internal_short_hw_scan(struct iwl_priv *priv)  	set_bit(STATUS_SCANNING, &priv->status);  	priv->is_internal_short_scan = true;  	queue_work(priv->workqueue, &priv->request_scan); - -out: -	return ret; + unlock: +	mutex_unlock(&priv->mutex);  }  EXPORT_SYMBOL(iwl_internal_short_hw_scan); @@ -964,6 +973,7 @@ void iwl_setup_scan_deferred_work(struct iwl_priv *priv)  	INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);  	INIT_WORK(&priv->request_scan, iwl_bg_request_scan);  	INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan); +	INIT_WORK(&priv->start_internal_scan, iwl_bg_start_internal_scan);  	INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);  }  EXPORT_SYMBOL(iwl_setup_scan_deferred_work); diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 1ed5206721e..8dd0c036d54 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -29,6 +29,7 @@  #include <linux/etherdevice.h>  #include <linux/sched.h> +#include <linux/slab.h>  #include <net/mac80211.h>  #include "iwl-eeprom.h"  #include "iwl-dev.h" @@ -124,7 +125,7 @@ void iwl_free_tfds_in_queue(struct iwl_priv *priv,  	if (priv->stations[sta_id].tid[tid].tfds_in_queue >= freed)  		priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;  	else { -		IWL_ERR(priv, "free more than tfds_in_queue (%u:%d)\n", +		IWL_DEBUG_TX(priv, "free more than tfds_in_queue (%u:%d)\n",  			priv->stations[sta_id].tid[tid].tfds_in_queue,  			freed);  		priv->stations[sta_id].tid[tid].tfds_in_queue = 0; @@ -193,10 +194,34 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)  	struct iwl_queue *q = &txq->q;  	struct device *dev = &priv->pci_dev->dev;  	int i; +	bool huge = false;  	if (q->n_bd == 0)  		return; +	for (; q->read_ptr != q->write_ptr; +	     q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { +		/* we have no way to tell if it is a huge cmd ATM */ +		i = get_cmd_index(q, q->read_ptr, 0); + +		if (txq->meta[i].flags & CMD_SIZE_HUGE) { +			huge = true; +			continue; +		} + +		pci_unmap_single(priv->pci_dev, +				 pci_unmap_addr(&txq->meta[i], mapping), +				 pci_unmap_len(&txq->meta[i], len), +				 PCI_DMA_BIDIRECTIONAL); +	} +	if (huge) { +		i = q->n_window; +		pci_unmap_single(priv->pci_dev, +				 pci_unmap_addr(&txq->meta[i], mapping), +				 pci_unmap_len(&txq->meta[i], len), +				 PCI_DMA_BIDIRECTIONAL); +	} +  	/* De-alloc array of command/tx buffers */  	for (i = 0; i <= TFD_CMD_SLOTS; i++)  		kfree(txq->cmd[i]); @@ -409,6 +434,26 @@ out_free_arrays:  }  EXPORT_SYMBOL(iwl_tx_queue_init); +void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq, +			int slots_num, u32 txq_id) +{ +	int actual_slots = slots_num; + +	if (txq_id == IWL_CMD_QUEUE_NUM) +		actual_slots++; + +	memset(txq->meta, 0, sizeof(struct iwl_cmd_meta) * actual_slots); + +	txq->need_update = 0; + +	/* Initialize queue's high/low-water marks, and head/tail indexes */ +	iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); + +	/* Tell device where to find queue */ +	priv->cfg->ops->lib->txq_init(priv, txq); +} +EXPORT_SYMBOL(iwl_tx_queue_reset); +  /**   * iwl_hw_txq_ctx_free - Free TXQ Context   * @@ -420,8 +465,7 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv)  	/* Tx queues */  	if (priv->txq) { -		for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; -		     txq_id++) +		for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)  			if (txq_id == IWL_CMD_QUEUE_NUM)  				iwl_cmd_queue_free(priv);  			else @@ -437,15 +481,15 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv)  EXPORT_SYMBOL(iwl_hw_txq_ctx_free);  /** - * iwl_txq_ctx_reset - Reset TX queue context - * Destroys all DMA structures and initialize them again + * iwl_txq_ctx_alloc - allocate TX queue context + * Allocate all Tx DMA structures and initialize them   *   * @param priv   * @return error code   */ -int iwl_txq_ctx_reset(struct iwl_priv *priv) +int iwl_txq_ctx_alloc(struct iwl_priv *priv)  { -	int ret = 0; +	int ret;  	int txq_id, slots_num;  	unsigned long flags; @@ -503,8 +547,31 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)  	return ret;  } +void iwl_txq_ctx_reset(struct iwl_priv *priv) +{ +	int txq_id, slots_num; +	unsigned long flags; + +	spin_lock_irqsave(&priv->lock, flags); + +	/* Turn off all Tx DMA fifos */ +	priv->cfg->ops->lib->txq_set_sched(priv, 0); + +	/* Tell NIC where to find the "keep warm" buffer */ +	iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4); + +	spin_unlock_irqrestore(&priv->lock, flags); + +	/* Alloc and init all Tx queues, including the command queue (#4) */ +	for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { +		slots_num = txq_id == IWL_CMD_QUEUE_NUM ? +			    TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; +		iwl_tx_queue_reset(priv, &priv->txq[txq_id], slots_num, txq_id); +	} +} +  /** - * iwl_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory + * iwl_txq_ctx_stop - Stop all Tx DMA channels   */  void iwl_txq_ctx_stop(struct iwl_priv *priv)  { @@ -524,9 +591,6 @@ void iwl_txq_ctx_stop(struct iwl_priv *priv)  				    1000);  	}  	spin_unlock_irqrestore(&priv->lock, flags); - -	/* Deallocate memory for all Tx queues */ -	iwl_hw_txq_ctx_free(priv);  }  EXPORT_SYMBOL(iwl_txq_ctx_stop); @@ -1049,6 +1113,14 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)  	spin_lock_irqsave(&priv->hcmd_lock, flags); +	/* If this is a huge cmd, mark the huge flag also on the meta.flags +	 * of the _original_ cmd. This is used for DMA mapping clean up. +	 */ +	if (cmd->flags & CMD_SIZE_HUGE) { +		idx = get_cmd_index(q, q->write_ptr, 0); +		txq->meta[idx].flags = CMD_SIZE_HUGE; +	} +  	idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE);  	out_cmd = txq->cmd[idx];  	out_meta = &txq->meta[idx]; @@ -1226,6 +1298,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)  	bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME);  	struct iwl_device_cmd *cmd;  	struct iwl_cmd_meta *meta; +	struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];  	/* If a Tx command is being handled and it isn't in the actual  	 * command queue then there a command routing bug has been introduced @@ -1239,9 +1312,17 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)  		return;  	} -	cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); -	cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; -	meta = &priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_index]; +	/* If this is a huge cmd, clear the huge flag on the meta.flags +	 * of the _original_ cmd. So that iwl_cmd_queue_free won't unmap +	 * the DMA buffer for the scan (huge) command. +	 */ +	if (huge) { +		cmd_index = get_cmd_index(&txq->q, index, 0); +		txq->meta[cmd_index].flags = 0; +	} +	cmd_index = get_cmd_index(&txq->q, index, huge); +	cmd = txq->cmd[cmd_index]; +	meta = &txq->meta[cmd_index];  	pci_unmap_single(priv->pci_dev,  			 pci_unmap_addr(meta, mapping), @@ -1263,6 +1344,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)  			       get_cmd_string(cmd->hdr.cmd));  		wake_up_interruptible(&priv->wait_command_queue);  	} +	meta->flags = 0;  }  EXPORT_SYMBOL(iwl_tx_cmd_complete); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 54daa38ecba..b55e4f39a9e 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -31,6 +31,7 @@  #include <linux/module.h>  #include <linux/init.h>  #include <linux/pci.h> +#include <linux/slab.h>  #include <linux/dma-mapping.h>  #include <linux/delay.h>  #include <linux/sched.h> @@ -1955,7 +1956,7 @@ static void iwl3945_init_hw_rates(struct iwl_priv *priv,  {  	int i; -	for (i = 0; i < IWL_RATE_COUNT; i++) { +	for (i = 0; i < IWL_RATE_COUNT_LEGACY; i++) {  		rates[i].bitrate = iwl3945_rates[i].ieee * 5;  		rates[i].hw_value = i; /* Rate scaling will work on indexes */  		rates[i].hw_value_short = i; @@ -3921,7 +3922,7 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)  		BIT(NL80211_IFTYPE_STATION) |  		BIT(NL80211_IFTYPE_ADHOC); -	hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY | +	hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |  			    WIPHY_FLAG_DISABLE_BEACON_HINTS;  	hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945; diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 7c4f44a9c3e..a1d45cce0eb 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -27,6 +27,7 @@  #include <linux/etherdevice.h>  #include <linux/wireless.h>  #include <linux/ieee80211.h> +#include <linux/slab.h>  #include <net/cfg80211.h>  #include "iwm.h" diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 1e41ad0fcad..42df7262f9f 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -41,6 +41,7 @@  #include <linux/etherdevice.h>  #include <linux/ieee80211.h>  #include <linux/sched.h> +#include <linux/slab.h>  #include "iwm.h"  #include "bus.h" diff --git a/drivers/net/wireless/iwmc3200wifi/debugfs.c b/drivers/net/wireless/iwmc3200wifi/debugfs.c index c29c994de0e..cbb81befdb5 100644 --- a/drivers/net/wireless/iwmc3200wifi/debugfs.c +++ b/drivers/net/wireless/iwmc3200wifi/debugfs.c @@ -21,6 +21,7 @@   *   */ +#include <linux/slab.h>  #include <linux/kernel.h>  #include <linux/bitops.h>  #include <linux/debugfs.h> diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.c b/drivers/net/wireless/iwmc3200wifi/eeprom.c index 8091421ee5e..e80e776b74f 100644 --- a/drivers/net/wireless/iwmc3200wifi/eeprom.c +++ b/drivers/net/wireless/iwmc3200wifi/eeprom.c @@ -37,6 +37,7 @@   */  #include <linux/kernel.h> +#include <linux/slab.h>  #include "iwm.h"  #include "umac.h" diff --git a/drivers/net/wireless/iwmc3200wifi/hal.c b/drivers/net/wireless/iwmc3200wifi/hal.c index d13c8853ee8..229de990379 100644 --- a/drivers/net/wireless/iwmc3200wifi/hal.c +++ b/drivers/net/wireless/iwmc3200wifi/hal.c @@ -98,6 +98,7 @@   */  #include <linux/kernel.h>  #include <linux/netdevice.h> +#include <linux/slab.h>  #include "iwm.h"  #include "bus.h" diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 7f34d6dd3c4..23856d359e1 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -41,6 +41,7 @@  #include <linux/sched.h>  #include <linux/ieee80211.h>  #include <linux/wireless.h> +#include <linux/slab.h>  #include "iwm.h"  #include "debug.h" diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c index c4c0d23c63e..13a69ebf2a9 100644 --- a/drivers/net/wireless/iwmc3200wifi/netdev.c +++ b/drivers/net/wireless/iwmc3200wifi/netdev.c @@ -46,6 +46,7 @@   *              -> sdio_disable_func()   */  #include <linux/netdevice.h> +#include <linux/slab.h>  #include "iwm.h"  #include "commands.h" diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 8456b4dbd14..3257d4fad83 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -44,6 +44,7 @@  #include <linux/ieee80211.h>  #include <linux/if_arp.h>  #include <linux/list.h> +#include <linux/slab.h>  #include <net/iw_handler.h>  #include "iwm.h" diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c index a7ec7eac913..1eafd6dec3f 100644 --- a/drivers/net/wireless/iwmc3200wifi/sdio.c +++ b/drivers/net/wireless/iwmc3200wifi/sdio.c @@ -63,6 +63,7 @@   */  #include <linux/kernel.h> +#include <linux/slab.h>  #include <linux/netdevice.h>  #include <linux/debugfs.h>  #include <linux/mmc/sdio_ids.h> diff --git a/drivers/net/wireless/iwmc3200wifi/tx.c b/drivers/net/wireless/iwmc3200wifi/tx.c index 55905f02309..f6a02f123f3 100644 --- a/drivers/net/wireless/iwmc3200wifi/tx.c +++ b/drivers/net/wireless/iwmc3200wifi/tx.c @@ -64,6 +64,7 @@   * (i.e. half of the max size). [iwm_tx_worker]   */ +#include <linux/slab.h>  #include <linux/skbuff.h>  #include <linux/netdevice.h>  #include <linux/ieee80211.h> diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index f03d5e4e59c..12a2ef9dace 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -4,6 +4,7 @@  #include <linux/etherdevice.h>  #include <linux/ieee80211.h>  #include <linux/if_arp.h> +#include <linux/slab.h>  #include <net/lib80211.h>  #include "assoc.h" diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 4396dccd12a..ce7bec402a3 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -6,6 +6,7 @@   *   */ +#include <linux/slab.h>  #include <net/cfg80211.h>  #include "cfg.h" @@ -172,6 +173,8 @@ int lbs_cfg_register(struct lbs_private *priv)  	if (ret < 0)  		lbs_pr_err("cannot register wiphy device\n"); +	priv->wiphy_registered = true; +  	ret = register_netdev(priv->dev);  	if (ret)  		lbs_pr_err("cannot register network device\n"); @@ -190,9 +193,11 @@ void lbs_cfg_free(struct lbs_private *priv)  	if (!wdev)  		return; -	if (wdev->wiphy) { +	if (priv->wiphy_registered)  		wiphy_unregister(wdev->wiphy); + +	if (wdev->wiphy)  		wiphy_free(wdev->wiphy); -	} +  	kfree(wdev);  } diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 82371ef3952..cdb9b9650d7 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -5,6 +5,7 @@  #include <linux/kfifo.h>  #include <linux/sched.h> +#include <linux/slab.h>  #include "host.h"  #include "decl.h" diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index e7470442f76..88f7131d66e 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -2,6 +2,7 @@    * This file contains the handling of command    * responses as well as events generated by firmware.    */ +#include <linux/slab.h>  #include <linux/delay.h>  #include <linux/sched.h>  #include <linux/if_arp.h> diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 587b0cb0088..a48ccaffb28 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -4,6 +4,7 @@  #include <linux/delay.h>  #include <linux/mm.h>  #include <linux/string.h> +#include <linux/slab.h>  #include <net/iw_handler.h>  #include <net/lib80211.h> diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 6977ee82021..6875e1498bd 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -36,6 +36,7 @@ struct lbs_private {  	/* CFG80211 */  	struct wireless_dev *wdev; +	bool wiphy_registered;  	/* Mesh */  	struct net_device *mesh_dev; /* Virtual device */ diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 1f6cb58dd66..6d55439a7b9 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -22,6 +22,7 @@  */  #include <linux/module.h> +#include <linux/slab.h>  #include <linux/delay.h>  #include <linux/moduleparam.h>  #include <linux/firmware.h> diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 7a73f625273..7d1a3c6b6ce 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -28,6 +28,7 @@  #include <linux/kernel.h>  #include <linux/moduleparam.h> +#include <linux/slab.h>  #include <linux/firmware.h>  #include <linux/netdevice.h>  #include <linux/delay.h> diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 3ea03f259ee..fe3f08028eb 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -24,6 +24,7 @@  #include <linux/list.h>  #include <linux/netdevice.h>  #include <linux/semaphore.h> +#include <linux/slab.h>  #include <linux/spi/libertas_spi.h>  #include <linux/spi/spi.h> diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 65e174595d1..fcea5741ba6 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -5,6 +5,7 @@  #include <linux/moduleparam.h>  #include <linux/firmware.h>  #include <linux/netdevice.h> +#include <linux/slab.h>  #include <linux/usb.h>  #ifdef CONFIG_OLPC diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 28a1c9d1627..598080414b1 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -13,6 +13,7 @@  #include <linux/kfifo.h>  #include <linux/stddef.h>  #include <linux/ieee80211.h> +#include <linux/slab.h>  #include <net/iw_handler.h>  #include <net/cfg80211.h> diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 2daf8ffdb7e..784dae71470 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -2,6 +2,7 @@    * This file contains the handling of RX in wlan driver.    */  #include <linux/etherdevice.h> +#include <linux/slab.h>  #include <linux/types.h>  #include "host.h" diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 220361e69cd..24cd54b3a80 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -4,6 +4,7 @@    * IOCTL handlers as well as command preperation and response routines    *  for sending scan commands to the firmware.    */ +#include <linux/slab.h>  #include <linux/types.h>  #include <linux/kernel.h>  #include <linux/etherdevice.h> diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 71f88a08e09..9b555884b08 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -2,6 +2,7 @@    * This file contains ioctl functions    */  #include <linux/ctype.h> +#include <linux/slab.h>  #include <linux/delay.h>  #include <linux/if.h>  #include <linux/if_arp.h> diff --git a/drivers/net/wireless/libertas_tf/cmd.c b/drivers/net/wireless/libertas_tf/cmd.c index 28790e03dc4..b620daf59ef 100644 --- a/drivers/net/wireless/libertas_tf/cmd.c +++ b/drivers/net/wireless/libertas_tf/cmd.c @@ -7,6 +7,8 @@   *  the Free Software Foundation; either version 2 of the License, or (at   *  your option) any later version.   */ +#include <linux/slab.h> +  #include "libertas_tf.h"  static const struct channel_range channel_ranges[] = { diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c index 3691c307e67..8cc9db60c14 100644 --- a/drivers/net/wireless/libertas_tf/if_usb.c +++ b/drivers/net/wireless/libertas_tf/if_usb.c @@ -11,6 +11,7 @@  #include <linux/moduleparam.h>  #include <linux/firmware.h>  #include <linux/netdevice.h> +#include <linux/slab.h>  #include <linux/usb.h>  #define DRV_NAME "lbtf_usb" diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index 6ab30033c26..7945ff5aa33 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -7,6 +7,8 @@   *  the Free Software Foundation; either version 2 of the License, or (at   *  your option) any later version.   */ +#include <linux/slab.h> +  #include "libertas_tf.h"  #include "linux/etherdevice.h" diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 6ea77e95277..7cd5f56662f 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -14,6 +14,7 @@   */  #include <linux/list.h> +#include <linux/slab.h>  #include <linux/spinlock.h>  #include <net/dst.h>  #include <net/xfrm.h> diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index ac65e13eb0d..12fdcb25fd3 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -19,6 +19,7 @@  #include <linux/delay.h>  #include <linux/completion.h>  #include <linux/etherdevice.h> +#include <linux/slab.h>  #include <net/mac80211.h>  #include <linux/moduleparam.h>  #include <linux/firmware.h> @@ -3851,6 +3852,7 @@ MODULE_FIRMWARE("mwl8k/helper_8366.fw");  MODULE_FIRMWARE("mwl8k/fmimage_8366.fw");  static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { +	{ PCI_VDEVICE(MARVELL, 0x2a0a), .driver_data = MWL8363, },  	{ PCI_VDEVICE(MARVELL, 0x2a0c), .driver_data = MWL8363, },  	{ PCI_VDEVICE(MARVELL, 0x2a24), .driver_data = MWL8363, },  	{ PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, }, diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c index cfa72962052..5ea0f7cf85b 100644 --- a/drivers/net/wireless/orinoco/fw.c +++ b/drivers/net/wireless/orinoco/fw.c @@ -3,6 +3,7 @@   * See copyright notice in main.c   */  #include <linux/kernel.h> +#include <linux/slab.h>  #include <linux/firmware.h>  #include <linux/device.h> diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index b42634c614b..413e9ab6cab 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -78,6 +78,7 @@  #include <linux/module.h>  #include <linux/kernel.h> +#include <linux/slab.h>  #include <linux/init.h>  #include <linux/delay.h>  #include <linux/device.h> diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c index d2f10e9c216..330d42d4533 100644 --- a/drivers/net/wireless/orinoco/scan.c +++ b/drivers/net/wireless/orinoco/scan.c @@ -3,6 +3,7 @@   * See copyright notice in main.c   */ +#include <linux/gfp.h>  #include <linux/kernel.h>  #include <linux/string.h>  #include <linux/ieee80211.h> diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 31ca241f775..fbcc6e1a2e1 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -2,6 +2,7 @@   *   * See copyright notice in main.c   */ +#include <linux/slab.h>  #include <linux/kernel.h>  #include <linux/if_arp.h>  #include <linux/wireless.h> diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c index 8e3818f6832..187e263b045 100644 --- a/drivers/net/wireless/p54/eeprom.c +++ b/drivers/net/wireless/p54/eeprom.c @@ -20,6 +20,7 @@  #include <linux/firmware.h>  #include <linux/etherdevice.h>  #include <linux/sort.h> +#include <linux/slab.h>  #include <net/mac80211.h> diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c index e7b9e9cb39f..c43a5d461ab 100644 --- a/drivers/net/wireless/p54/fwio.c +++ b/drivers/net/wireless/p54/fwio.c @@ -17,6 +17,7 @@   */  #include <linux/init.h> +#include <linux/slab.h>  #include <linux/firmware.h>  #include <linux/etherdevice.h> diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 4f752a21495..a7cb9eb759a 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -17,6 +17,7 @@   */  #include <linux/init.h> +#include <linux/slab.h>  #include <linux/firmware.h>  #include <linux/etherdevice.h> diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index ed4bdffdd63..c24067f1a0c 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -15,6 +15,7 @@  #include <linux/init.h>  #include <linux/pci.h> +#include <linux/slab.h>  #include <linux/firmware.h>  #include <linux/etherdevice.h>  #include <linux/delay.h> @@ -245,7 +246,7 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index,  	u32 idx, i;  	i = (*index) % ring_limit; -	(*index) = idx = le32_to_cpu(ring_control->device_idx[1]); +	(*index) = idx = le32_to_cpu(ring_control->device_idx[ring_index]);  	idx %= ring_limit;  	while (i != idx) { diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index afd26bf0664..c8f09da1f84 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -29,6 +29,7 @@  #include <linux/spi/spi.h>  #include <linux/etherdevice.h>  #include <linux/gpio.h> +#include <linux/slab.h>  #include "p54spi.h"  #include "p54spi_eeprom.h" diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index b3c4fbd80d8..743a6c68b29 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -15,6 +15,7 @@  #include <linux/init.h>  #include <linux/usb.h>  #include <linux/pci.h> +#include <linux/slab.h>  #include <linux/firmware.h>  #include <linux/etherdevice.h>  #include <linux/delay.h> @@ -35,6 +36,7 @@ MODULE_FIRMWARE("isl3887usb");  static struct usb_device_id p54u_table[] __devinitdata = {  	/* Version 1 devices (pci chip + net2280) */  	{USB_DEVICE(0x0506, 0x0a11)},	/* 3COM 3CRWE254G72 */ +	{USB_DEVICE(0x06b9, 0x0120)},	/* Thomson SpeedTouch 120g */  	{USB_DEVICE(0x0707, 0xee06)},	/* SMC 2862W-G */  	{USB_DEVICE(0x07aa, 0x001c)},	/* Corega CG-WLUSB2GT */  	{USB_DEVICE(0x083a, 0x4501)},	/* Accton 802.11g WN4501 USB */ diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index f7f5c793514..a45818ebfdf 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -23,6 +23,7 @@  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/if_arp.h> +#include <linux/slab.h>  #include <linux/pci.h>  #include <asm/uaccess.h> diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index a3ba3539db0..689d59a13d5 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -19,6 +19,7 @@   */  #include <linux/module.h> +#include <linux/slab.h>  #include <linux/netdevice.h>  #include <linux/ethtool.h> diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c index 872b64783e7..ac99eaaeabc 100644 --- a/drivers/net/wireless/prism54/islpci_eth.c +++ b/drivers/net/wireless/prism54/islpci_eth.c @@ -17,6 +17,7 @@   */  #include <linux/module.h> +#include <linux/gfp.h>  #include <linux/pci.h>  #include <linux/delay.h> diff --git a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c index 69d2f882fd0..adb289723a9 100644 --- a/drivers/net/wireless/prism54/islpci_mgt.c +++ b/drivers/net/wireless/prism54/islpci_mgt.c @@ -21,6 +21,7 @@  #include <linux/module.h>  #include <linux/pci.h>  #include <linux/sched.h> +#include <linux/slab.h>  #include <asm/io.h>  #include <asm/system.h> diff --git a/drivers/net/wireless/prism54/islpci_mgt.h b/drivers/net/wireless/prism54/islpci_mgt.h index 87a1734663d..0b27e50fe0d 100644 --- a/drivers/net/wireless/prism54/islpci_mgt.h +++ b/drivers/net/wireless/prism54/islpci_mgt.h @@ -22,6 +22,7 @@  #include <linux/wireless.h>  #include <linux/skbuff.h> +#include <linux/slab.h>  /*   *  Function definitions diff --git a/drivers/net/wireless/prism54/oid_mgt.c b/drivers/net/wireless/prism54/oid_mgt.c index 1187e6112a6..d66933d70fb 100644 --- a/drivers/net/wireless/prism54/oid_mgt.c +++ b/drivers/net/wireless/prism54/oid_mgt.c @@ -17,6 +17,7 @@   */  #include <linux/kernel.h> +#include <linux/slab.h>  #include "prismcompat.h"  #include "islpci_dev.h" diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 84c530aa52f..11865ea2187 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -35,7 +35,6 @@  #include <linux/proc_fs.h>  #include <linux/ptrace.h>  #include <linux/seq_file.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/timer.h>  #include <linux/init.h> diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 2887047069f..1de5b22d3ef 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -41,6 +41,7 @@  #include <linux/if_arp.h>  #include <linux/ctype.h>  #include <linux/spinlock.h> +#include <linux/slab.h>  #include <net/iw_handler.h>  #include <net/cfg80211.h>  #include <linux/usb/usbnet.h> diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index c22b04042d5..5f5204b8289 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -31,6 +31,7 @@  #include <linux/module.h>  #include <linux/pci.h>  #include <linux/eeprom_93cx6.h> +#include <linux/slab.h>  #include "rt2x00.h"  #include "rt2x00pci.h" diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 52bbcf1bd17..2a73f593aab 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -31,6 +31,7 @@  #include <linux/module.h>  #include <linux/pci.h>  #include <linux/eeprom_93cx6.h> +#include <linux/slab.h>  #include "rt2x00.h"  #include "rt2x00pci.h" diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 9b04964dece..8ebb705fe10 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -29,6 +29,7 @@  #include <linux/init.h>  #include <linux/kernel.h>  #include <linux/module.h> +#include <linux/slab.h>  #include <linux/usb.h>  #include "rt2x00.h" @@ -1643,6 +1644,11 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)  	unsigned int i;  	/* +	 * Disable powersaving as default. +	 */ +	rt2x00dev->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + +	/*  	 * Initialize all hw fields.  	 */  	rt2x00dev->hw->flags = diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 18d4d8e4ae6..c015ce9fdd0 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -35,6 +35,7 @@  #include <linux/kernel.h>  #include <linux/module.h> +#include <linux/slab.h>  #include "rt2x00.h"  #if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE) @@ -812,9 +813,9 @@ static void rt2800_config_channel_rt3x(struct rt2x00_dev *rt2x00dev,  	rt2800_rfcsr_write(rt2x00dev, 24,  			      rt2x00dev->calibration[conf_is_ht40(conf)]); -	rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); +	rt2800_rfcsr_read(rt2x00dev, 7, &rfcsr);  	rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); -	rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); +	rt2800_rfcsr_write(rt2x00dev, 7, rfcsr);  }  static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 28a1c46ec4e..9569fb4e5bc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -28,6 +28,7 @@  #include <linux/module.h>  #include <linux/poll.h>  #include <linux/sched.h> +#include <linux/slab.h>  #include <linux/uaccess.h>  #include "rt2x00.h" diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index dd5ab8fe232..eda73ba735a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -25,6 +25,7 @@  #include <linux/kernel.h>  #include <linux/module.h> +#include <linux/slab.h>  #include "rt2x00.h"  #include "rt2x00lib.h" diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 047123b766f..cf3f1c0c438 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -27,6 +27,7 @@  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/pci.h> +#include <linux/slab.h>  #include "rt2x00.h"  #include "rt2x00pci.h" diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 5b6b789cad3..a0bd36fc4d2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -24,6 +24,7 @@  	Abstract: rt2x00 queue specific routines.   */ +#include <linux/slab.h>  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/dma-mapping.h> diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.c b/drivers/net/wireless/rt2x00/rt2x00soc.c index 111c0ff5c6c..fc98063de71 100644 --- a/drivers/net/wireless/rt2x00/rt2x00soc.c +++ b/drivers/net/wireless/rt2x00/rt2x00soc.c @@ -28,6 +28,7 @@  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/platform_device.h> +#include <linux/slab.h>  #include "rt2x00.h"  #include "rt2x00soc.h" diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 0a751e73aa0..f9a7f8b1741 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -25,6 +25,7 @@  #include <linux/kernel.h>  #include <linux/module.h> +#include <linux/slab.h>  #include <linux/usb.h>  #include <linux/bug.h> diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 17747274217..432e75f960b 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -30,6 +30,7 @@  #include <linux/init.h>  #include <linux/kernel.h>  #include <linux/module.h> +#include <linux/slab.h>  #include <linux/pci.h>  #include <linux/eeprom_93cx6.h> diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 290d70bc5d2..bb58d797fb7 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -30,6 +30,7 @@  #include <linux/init.h>  #include <linux/kernel.h>  #include <linux/module.h> +#include <linux/slab.h>  #include <linux/usb.h>  #include "rt2x00.h" diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index 2b928ecf47b..2131a442831 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -17,6 +17,7 @@  #include <linux/init.h>  #include <linux/pci.h> +#include <linux/slab.h>  #include <linux/delay.h>  #include <linux/etherdevice.h>  #include <linux/eeprom_93cx6.h> diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 0fb850e0c65..1d30792973f 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -22,6 +22,7 @@  #include <linux/init.h>  #include <linux/usb.h> +#include <linux/slab.h>  #include <linux/delay.h>  #include <linux/etherdevice.h>  #include <linux/eeprom_93cx6.h> diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index beff084040b..91891f92807 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -1,6 +1,7 @@  #include "wl1251_acx.h"  #include <linux/module.h> +#include <linux/slab.h>  #include <linux/crc7.h>  #include "wl1251.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index 28a80867408..d5ac79aeaa7 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -22,6 +22,7 @@   */  #include <linux/gpio.h> +#include <linux/slab.h>  #include "wl1251_reg.h"  #include "wl1251_boot.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index 0320b478bb3..a37b30cef48 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -1,6 +1,7 @@  #include "wl1251_cmd.h"  #include <linux/module.h> +#include <linux/slab.h>  #include <linux/crc7.h>  #include "wl1251.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.c b/drivers/net/wireless/wl12xx/wl1251_debugfs.c index 0ccba57fb9f..5e4465ac08f 100644 --- a/drivers/net/wireless/wl12xx/wl1251_debugfs.c +++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.c @@ -24,6 +24,7 @@  #include "wl1251_debugfs.h"  #include <linux/skbuff.h> +#include <linux/slab.h>  #include "wl1251.h"  #include "wl1251_acx.h" @@ -466,7 +467,8 @@ out:  void wl1251_debugfs_reset(struct wl1251 *wl)  { -	memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); +	if (wl->stats.fw_stats != NULL) +		memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats));  	wl->stats.retry_count = 0;  	wl->stats.excessive_retries = 0;  } diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl12xx/wl1251_init.c index 5aad56ea715..b538bdd7b32 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.c +++ b/drivers/net/wireless/wl12xx/wl1251_init.c @@ -23,6 +23,7 @@  #include <linux/kernel.h>  #include <linux/module.h> +#include <linux/slab.h>  #include "wl1251_init.h"  #include "wl12xx_80211.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 24ae6a360ac..1c8226eee40 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -29,6 +29,7 @@  #include <linux/crc32.h>  #include <linux/etherdevice.h>  #include <linux/vmalloc.h> +#include <linux/slab.h>  #include "wl1251.h"  #include "wl12xx_80211.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c index b56732226cc..6f229e0990f 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.c +++ b/drivers/net/wireless/wl12xx/wl1251_rx.c @@ -23,6 +23,7 @@   */  #include <linux/skbuff.h> +#include <linux/gfp.h>  #include <net/mac80211.h>  #include "wl1251.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index 9cc8c323830..3bfb59bd463 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -23,6 +23,7 @@  #include <linux/irq.h>  #include <linux/module.h> +#include <linux/slab.h>  #include <linux/crc7.h>  #include <linux/spi/spi.h>  #include <linux/spi/wl12xx.h> diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index 60f10dce480..308782421fc 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -27,6 +27,7 @@  #include <linux/platform_device.h>  #include <linux/crc7.h>  #include <linux/spi/spi.h> +#include <linux/slab.h>  #include "wl1271.h"  #include "wl12xx_80211.h" diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index 2be76ee42bb..02435626306 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -22,6 +22,7 @@   */  #include <linux/gpio.h> +#include <linux/slab.h>  #include "wl1271_acx.h"  #include "wl1271_reg.h" diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 36a64e06f29..e7832f3318e 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -26,6 +26,7 @@  #include <linux/crc7.h>  #include <linux/spi/spi.h>  #include <linux/etherdevice.h> +#include <linux/slab.h>  #include "wl1271.h"  #include "wl1271_reg.h" diff --git a/drivers/net/wireless/wl12xx/wl1271_debugfs.c b/drivers/net/wireless/wl12xx/wl1271_debugfs.c index 8d7588ca68f..3f7ff8d0cf5 100644 --- a/drivers/net/wireless/wl12xx/wl1271_debugfs.c +++ b/drivers/net/wireless/wl12xx/wl1271_debugfs.c @@ -24,6 +24,7 @@  #include "wl1271_debugfs.h"  #include <linux/skbuff.h> +#include <linux/slab.h>  #include "wl1271.h"  #include "wl1271_acx.h" diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 86c30a86a45..d189e8fe05a 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -23,6 +23,7 @@  #include <linux/kernel.h>  #include <linux/module.h> +#include <linux/slab.h>  #include "wl1271_init.h"  #include "wl12xx_80211.h" diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 2a864b24291..65a1aeba241 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -33,6 +33,7 @@  #include <linux/vmalloc.h>  #include <linux/spi/wl12xx.h>  #include <linux/inetdevice.h> +#include <linux/slab.h>  #include "wl1271.h"  #include "wl12xx_80211.h" diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c index 6730f5b96e7..c723d9c7e13 100644 --- a/drivers/net/wireless/wl12xx/wl1271_rx.c +++ b/drivers/net/wireless/wl12xx/wl1271_rx.c @@ -21,6 +21,8 @@   *   */ +#include <linux/gfp.h> +  #include "wl1271.h"  #include "wl1271_acx.h"  #include "wl1271_reg.h" diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c index 67a82934f36..053c84aceb4 100644 --- a/drivers/net/wireless/wl12xx/wl1271_spi.c +++ b/drivers/net/wireless/wl12xx/wl1271_spi.c @@ -25,6 +25,7 @@  #include <linux/platform_device.h>  #include <linux/crc7.h>  #include <linux/spi/spi.h> +#include <linux/slab.h>  #include "wl1271.h"  #include "wl12xx_80211.h" diff --git a/drivers/net/wireless/wl12xx/wl1271_testmode.c b/drivers/net/wireless/wl12xx/wl1271_testmode.c index 3919102e942..5c1c4f565fd 100644 --- a/drivers/net/wireless/wl12xx/wl1271_testmode.c +++ b/drivers/net/wireless/wl12xx/wl1271_testmode.c @@ -22,6 +22,7 @@   */  #include "wl1271_testmode.h" +#include <linux/slab.h>  #include <net/genetlink.h>  #include "wl1271.h" diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index 6917286edca..9d127787464 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -14,6 +14,7 @@  #include <linux/module.h>  #include <linux/usb.h> +#include <linux/slab.h>  #include <linux/netdevice.h>  #include <linux/etherdevice.h>  #include <linux/wireless.h> diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 7ca95c414fa..b2af3c549bb 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -25,6 +25,7 @@  #include <linux/kernel.h>  #include <linux/errno.h> +#include <linux/slab.h>  #include "zd_def.h"  #include "zd_chip.h" diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 00e09e26c82..16fa289ad77 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -22,6 +22,7 @@  #include <linux/netdevice.h>  #include <linux/etherdevice.h> +#include <linux/slab.h>  #include <linux/usb.h>  #include <linux/jiffies.h>  #include <net/ieee80211_radiotap.h> diff --git a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c index 439799b8487..9e74eb1b67d 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c @@ -19,6 +19,7 @@   */  #include <linux/kernel.h> +#include <linux/slab.h>  #include "zd_rf.h"  #include "zd_usb.h" diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 442fc111732..d91ad1a612a 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -24,6 +24,7 @@  #include <linux/firmware.h>  #include <linux/device.h>  #include <linux/errno.h> +#include <linux/slab.h>  #include <linux/skbuff.h>  #include <linux/usb.h>  #include <linux/workqueue.h> diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index a869b45d3d3..d504e2b6025 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -40,6 +40,7 @@  #include <linux/udp.h>  #include <linux/moduleparam.h>  #include <linux/mm.h> +#include <linux/slab.h>  #include <net/ip.h>  #include <xen/xen.h> diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c index 1a74594224b..1e783ccc306 100644 --- a/drivers/net/xilinx_emaclite.c +++ b/drivers/net/xilinx_emaclite.c @@ -19,6 +19,7 @@  #include <linux/etherdevice.h>  #include <linux/skbuff.h>  #include <linux/io.h> +#include <linux/slab.h>  #include <linux/of_device.h>  #include <linux/of_platform.h> diff --git a/drivers/net/xtsonic.c b/drivers/net/xtsonic.c index 389ba9df712..fdba9cb3a59 100644 --- a/drivers/net/xtsonic.c +++ b/drivers/net/xtsonic.c @@ -20,11 +20,11 @@  #include <linux/module.h>  #include <linux/types.h>  #include <linux/fcntl.h> +#include <linux/gfp.h>  #include <linux/interrupt.h>  #include <linux/init.h>  #include <linux/ioport.h>  #include <linux/in.h> -#include <linux/slab.h>  #include <linux/string.h>  #include <linux/delay.h>  #include <linux/errno.h> @@ -33,6 +33,7 @@  #include <linux/skbuff.h>  #include <linux/platform_device.h>  #include <linux/dma-mapping.h> +#include <linux/slab.h>  #include <asm/io.h>  #include <asm/pgtable.h> diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 7d4107f5eeb..ede5b2436f2 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -90,7 +90,6 @@ static int gx_fix;  #include <linux/timer.h>  #include <linux/errno.h>  #include <linux/ioport.h> -#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/pci.h>  #include <linux/init.h> diff --git a/drivers/net/znet.c b/drivers/net/znet.c index def49d2ec69..dbfef8d70f2 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -88,6 +88,7 @@  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/string.h> +#include <linux/slab.h>  #include <linux/errno.h>  #include <linux/interrupt.h>  #include <linux/ioport.h>  |