Merge branch 'linux-2.6.31.y' of git://git.kernel.org/pub/scm/linux/kernel/git/inaky/wimax
diff --git a/Documentation/DocBook/mac80211.tmpl b/Documentation/DocBook/mac80211.tmpl
index fbeaffc..e369866 100644
--- a/Documentation/DocBook/mac80211.tmpl
+++ b/Documentation/DocBook/mac80211.tmpl
@@ -145,7 +145,6 @@
         interface in STA mode at first!
       </para>
 !Finclude/net/mac80211.h ieee80211_if_init_conf
-!Finclude/net/mac80211.h ieee80211_if_conf
     </chapter>
 
     <chapter id="rx-tx">
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 31693bc..965ece2 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -34,13 +34,6 @@
 		skb_reset_mac_header(skb);
 		skb_reset_network_header(skb);
 		skb->protocol = __constant_htons(ETH_P_AOE);
-		skb->priority = 0;
-		skb->next = skb->prev = NULL;
-
-		/* tell the network layer not to perform IP checksums
-		 * or to get the NIC to do it
-		 */
-		skb->ip_summed = CHECKSUM_NONE;
 	}
 	return skb;
 }
diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c
index 09202a5..db3a1e4 100644
--- a/drivers/isdn/gigaset/isocdata.c
+++ b/drivers/isdn/gigaset/isocdata.c
@@ -175,7 +175,7 @@
 		return -EINVAL;
 	}
 	src = iwb->read;
-	if (unlikely(limit > BAS_OUTBUFSIZE + BAS_OUTBUFPAD ||
+	if (unlikely(limit >= BAS_OUTBUFSIZE + BAS_OUTBUFPAD ||
 		     (read < src && limit >= src))) {
 		pr_err("isoc write buffer frame reservation violated\n");
 		return -EFAULT;
diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig
index fd112ae..3024566 100644
--- a/drivers/isdn/hardware/mISDN/Kconfig
+++ b/drivers/isdn/hardware/mISDN/Kconfig
@@ -13,7 +13,7 @@
 
 config MISDN_HFCMULTI
 	tristate "Support for HFC multiport cards (HFC-4S/8S/E1)"
-	depends on PCI
+	depends on PCI || 8xx
 	depends on MISDN
 	help
 	  Enable support for cards with Cologne Chip AG's HFC multiport
@@ -23,6 +23,15 @@
 	   * HFC-8S (8 S/T interfaces on one chip)
 	   * HFC-E1 (E1 interface for 2Mbit ISDN)
 
+config MISDN_HFCMULTI_8xx
+	boolean "Support for XHFC embedded board in HFC multiport driver"
+	depends on MISDN
+	depends on MISDN_HFCMULTI
+	depends on 8xx
+	default 8xx
+	help
+	  Enable support for the XHFC embedded solution from Speech Design.
+
 config MISDN_HFCUSB
 	tristate "Support for HFC-S USB based TAs"
 	depends on USB
diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h
index 663b77f..0c77386 100644
--- a/drivers/isdn/hardware/mISDN/hfc_multi.h
+++ b/drivers/isdn/hardware/mISDN/hfc_multi.h
@@ -17,6 +17,16 @@
 #define	PCI_ENA_REGIO	0x01
 #define	PCI_ENA_MEMIO	0x02
 
+#define XHFC_IRQ	4		/* SIU_IRQ2 */
+#define XHFC_MEMBASE	0xFE000000
+#define XHFC_MEMSIZE    0x00001000
+#define XHFC_OFFSET	0x00001000
+#define PA_XHFC_A0	0x0020		/* PA10 */
+#define PB_XHFC_IRQ1	0x00000100	/* PB23 */
+#define PB_XHFC_IRQ2	0x00000200	/* PB22 */
+#define PB_XHFC_IRQ3	0x00000400	/* PB21 */
+#define PB_XHFC_IRQ4	0x00000800	/* PB20 */
+
 /*
  * NOTE: some registers are assigned multiple times due to different modes
  *       also registers are assigned differen for HFC-4s/8s and HFC-E1
@@ -44,6 +54,7 @@
 	int		conf;	/* conference setting of TX slot */
 	int		txpending;	/* if there is currently data in */
 					/* the FIFO 0=no, 1=yes, 2=splloop */
+	int		Zfill;	/* rx-fifo level on last hfcmulti_tx */
 	int		rx_off; /* set to turn fifo receive off */
 	int		coeff_count; /* curren coeff block */
 	s32		*coeff; /* memory pointer to 8 coeff blocks */
@@ -62,6 +73,7 @@
 	u_char	r_sci_msk;
 	u_char	r_tx0, r_tx1;
 	u_char	a_st_ctrl0[8];
+	u_char	r_bert_wd_md;
 	timer_t	timer;
 };
 
@@ -79,6 +91,11 @@
 #define	HFC_CFG_CRC4		10 /* disable CRC-4 Multiframe mode, */
 					/* use double frame instead. */
 
+#define HFC_TYPE_E1		1 /* controller is HFC-E1 */
+#define HFC_TYPE_4S		4 /* controller is HFC-4S */
+#define HFC_TYPE_8S		8 /* controller is HFC-8S */
+#define HFC_TYPE_XHFC		5 /* controller is XHFC */
+
 #define	HFC_CHIP_EXRAM_128	0 /* external ram 128k */
 #define	HFC_CHIP_EXRAM_512	1 /* external ram 256k */
 #define	HFC_CHIP_REVISION0	2 /* old fifo handling */
@@ -86,19 +103,22 @@
 #define	HFC_CHIP_PCM_MASTER	4 /* PCM is master */
 #define	HFC_CHIP_RX_SYNC	5 /* disable pll sync for pcm */
 #define	HFC_CHIP_DTMF		6 /* DTMF decoding is enabled */
-#define	HFC_CHIP_ULAW		7 /* ULAW mode */
-#define	HFC_CHIP_CLOCK2		8 /* double clock mode */
-#define	HFC_CHIP_E1CLOCK_GET	9 /* always get clock from E1 interface */
-#define	HFC_CHIP_E1CLOCK_PUT	10 /* always put clock from E1 interface */
-#define	HFC_CHIP_WATCHDOG	11 /* whether we should send signals */
+#define	HFC_CHIP_CONF		7 /* conference handling is enabled */
+#define	HFC_CHIP_ULAW		8 /* ULAW mode */
+#define	HFC_CHIP_CLOCK2		9 /* double clock mode */
+#define	HFC_CHIP_E1CLOCK_GET	10 /* always get clock from E1 interface */
+#define	HFC_CHIP_E1CLOCK_PUT	11 /* always put clock from E1 interface */
+#define	HFC_CHIP_WATCHDOG	12 /* whether we should send signals */
 					/* to the watchdog */
-#define	HFC_CHIP_B410P		12 /* whether we have a b410p with echocan in */
+#define	HFC_CHIP_B410P		13 /* whether we have a b410p with echocan in */
 					/* hw */
-#define	HFC_CHIP_PLXSD		13 /* whether we have a Speech-Design PLX */
+#define	HFC_CHIP_PLXSD		14 /* whether we have a Speech-Design PLX */
+#define	HFC_CHIP_EMBSD          15 /* whether we have a SD Embedded board */
 
 #define HFC_IO_MODE_PCIMEM	0x00 /* normal memory mapped IO */
 #define HFC_IO_MODE_REGIO	0x01 /* PCI io access */
 #define HFC_IO_MODE_PLXSD	0x02 /* access HFC via PLX9030 */
+#define HFC_IO_MODE_EMBSD	0x03 /* direct access */
 
 /* table entry in the PCI devices list */
 struct hm_map {
@@ -111,6 +131,7 @@
 	int opticalsupport;
 	int dip_type;
 	int io_mode;
+	int irq;
 };
 
 struct hfc_multi {
@@ -118,7 +139,7 @@
 	struct hm_map	*mtyp;
 	int		id;
 	int		pcm;	/* id of pcm bus */
-	int		type;
+	int		ctype;	/* controller type */
 	int		ports;
 
 	u_int		irq;	/* irq used by card */
@@ -158,10 +179,16 @@
 				int len);
 	void		(*write_fifo)(struct hfc_multi *hc, u_char *data,
 				int len);
-	u_long		pci_origmembase, plx_origmembase, dsp_origmembase;
+	u_long		pci_origmembase, plx_origmembase;
 	void __iomem	*pci_membase; /* PCI memory */
 	void __iomem	*plx_membase; /* PLX memory */
-	u_char		*dsp_membase; /* DSP on PLX */
+	u_long		xhfc_origmembase;
+	u_char		*xhfc_membase;
+	u_long		*xhfc_memaddr, *xhfc_memdata;
+#ifdef CONFIG_MISDN_HFCMULTI_8xx
+	struct immap	*immap;
+#endif
+	u_long		pb_irqmsk;	/* Portbit mask to check the IRQ line */
 	u_long		pci_iobase; /* PCI IO */
 	struct hfcm_hw	hw;	/* remember data of write-only-registers */
 
diff --git a/drivers/isdn/hardware/mISDN/hfc_multi_8xx.h b/drivers/isdn/hardware/mISDN/hfc_multi_8xx.h
new file mode 100644
index 0000000..45ddced
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/hfc_multi_8xx.h
@@ -0,0 +1,167 @@
+/*
+ * For License see notice in hfc_multi.c
+ *
+ * special IO and init functions for the embedded XHFC board
+ * from Speech Design
+ *
+ */
+
+#include <asm/8xx_immap.h>
+
+/* Change this to the value used by your board */
+#ifndef IMAP_ADDR
+#define IMAP_ADDR	0xFFF00000
+#endif
+
+static void
+#ifdef HFC_REGISTER_DEBUG
+HFC_outb_embsd(struct hfc_multi *hc, u_char reg, u_char val,
+		const char *function, int line)
+#else
+HFC_outb_embsd(struct hfc_multi *hc, u_char reg, u_char val)
+#endif
+{
+	hc->immap->im_ioport.iop_padat |= PA_XHFC_A0;
+	writeb(reg, hc->xhfc_memaddr);
+	hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0);
+	writeb(val, hc->xhfc_memdata);
+}
+static u_char
+#ifdef HFC_REGISTER_DEBUG
+HFC_inb_embsd(struct hfc_multi *hc, u_char reg, const char *function, int line)
+#else
+HFC_inb_embsd(struct hfc_multi *hc, u_char reg)
+#endif
+{
+	hc->immap->im_ioport.iop_padat |= PA_XHFC_A0;
+	writeb(reg, hc->xhfc_memaddr);
+	hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0);
+	return readb(hc->xhfc_memdata);
+}
+static u_short
+#ifdef HFC_REGISTER_DEBUG
+HFC_inw_embsd(struct hfc_multi *hc, u_char reg, const char *function, int line)
+#else
+HFC_inw_embsd(struct hfc_multi *hc, u_char reg)
+#endif
+{
+	hc->immap->im_ioport.iop_padat |= PA_XHFC_A0;
+	writeb(reg, hc->xhfc_memaddr);
+	hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0);
+	return readb(hc->xhfc_memdata);
+}
+static void
+#ifdef HFC_REGISTER_DEBUG
+HFC_wait_embsd(struct hfc_multi *hc, const char *function, int line)
+#else
+HFC_wait_embsd(struct hfc_multi *hc)
+#endif
+{
+	hc->immap->im_ioport.iop_padat |= PA_XHFC_A0;
+	writeb(R_STATUS, hc->xhfc_memaddr);
+	hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0);
+	while (readb(hc->xhfc_memdata) & V_BUSY)
+		cpu_relax();
+}
+
+/* write fifo data (EMBSD) */
+void
+write_fifo_embsd(struct hfc_multi *hc, u_char *data, int len)
+{
+	hc->immap->im_ioport.iop_padat |= PA_XHFC_A0;
+	*hc->xhfc_memaddr = A_FIFO_DATA0;
+	hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0);
+	while (len) {
+		*hc->xhfc_memdata = *data;
+		data++;
+		len--;
+	}
+}
+
+/* read fifo data (EMBSD) */
+void
+read_fifo_embsd(struct hfc_multi *hc, u_char *data, int len)
+{
+	hc->immap->im_ioport.iop_padat |= PA_XHFC_A0;
+	*hc->xhfc_memaddr = A_FIFO_DATA0;
+	hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0);
+	while (len) {
+		*data = (u_char)(*hc->xhfc_memdata);
+		data++;
+		len--;
+	}
+}
+
+static int
+setup_embedded(struct hfc_multi *hc, struct hm_map *m)
+{
+	printk(KERN_INFO
+	    "HFC-multi: card manufacturer: '%s' card name: '%s' clock: %s\n",
+	    m->vendor_name, m->card_name, m->clock2 ? "double" : "normal");
+
+	hc->pci_dev = NULL;
+	if (m->clock2)
+		test_and_set_bit(HFC_CHIP_CLOCK2, &hc->chip);
+
+	hc->leds = m->leds;
+	hc->ledstate = 0xAFFEAFFE;
+	hc->opticalsupport = m->opticalsupport;
+
+	hc->pci_iobase = 0;
+	hc->pci_membase = 0;
+	hc->xhfc_membase = NULL;
+	hc->xhfc_memaddr = NULL;
+	hc->xhfc_memdata = NULL;
+
+	/* set memory access methods */
+	if (m->io_mode) /* use mode from card config */
+		hc->io_mode = m->io_mode;
+	switch (hc->io_mode) {
+	case HFC_IO_MODE_EMBSD:
+		test_and_set_bit(HFC_CHIP_EMBSD, &hc->chip);
+		hc->slots = 128; /* required */
+		/* fall through */
+		hc->HFC_outb = HFC_outb_embsd;
+		hc->HFC_inb = HFC_inb_embsd;
+		hc->HFC_inw = HFC_inw_embsd;
+		hc->HFC_wait = HFC_wait_embsd;
+		hc->read_fifo = read_fifo_embsd;
+		hc->write_fifo = write_fifo_embsd;
+		hc->xhfc_origmembase = XHFC_MEMBASE + XHFC_OFFSET * hc->id;
+		hc->xhfc_membase = (u_char *)ioremap(hc->xhfc_origmembase,
+				XHFC_MEMSIZE);
+		if (!hc->xhfc_membase) {
+			printk(KERN_WARNING
+			    "HFC-multi: failed to remap xhfc address space. "
+			    "(internal error)\n");
+			return -EIO;
+		}
+		hc->xhfc_memaddr = (u_long *)(hc->xhfc_membase + 4);
+		hc->xhfc_memdata = (u_long *)(hc->xhfc_membase);
+		printk(KERN_INFO
+		    "HFC-multi: xhfc_membase:%#lx xhfc_origmembase:%#lx "
+		    "xhfc_memaddr:%#lx xhfc_memdata:%#lx\n",
+		    (u_long)hc->xhfc_membase, hc->xhfc_origmembase,
+		    (u_long)hc->xhfc_memaddr, (u_long)hc->xhfc_memdata);
+		break;
+	default:
+		printk(KERN_WARNING "HFC-multi: Invalid IO mode.\n");
+		return -EIO;
+	}
+
+	/* Prepare the MPC8XX PortA 10 as output (address/data selector) */
+	hc->immap = (struct immap *)(IMAP_ADDR);
+	hc->immap->im_ioport.iop_papar &= ~(PA_XHFC_A0);
+	hc->immap->im_ioport.iop_paodr &= ~(PA_XHFC_A0);
+	hc->immap->im_ioport.iop_padir |=   PA_XHFC_A0;
+
+	/* Prepare the MPC8xx PortB __X__ as input (ISDN__X__IRQ) */
+	hc->pb_irqmsk = (PB_XHFC_IRQ1 << hc->id);
+	hc->immap->im_cpm.cp_pbpar &= ~(hc->pb_irqmsk);
+	hc->immap->im_cpm.cp_pbodr &= ~(hc->pb_irqmsk);
+	hc->immap->im_cpm.cp_pbdir &= ~(hc->pb_irqmsk);
+
+	/* At this point the needed config is done */
+	/* fifos are still not enabled */
+	return 0;
+}
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index 0b28141..e1dab30 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -104,7 +104,7 @@
  *	If unsure, don't give this parameter.
  *
  * dslot:
- *	NOTE: only one poll value must be given for every card.
+ *	NOTE: only one dslot value must be given for every card.
  *	Also this value must be given for non-E1 cards. If omitted, the E1
  *	card has D-channel on time slot 16, which is default.
  *	If 1..15 or 17..31, an alternate time slot is used for D-channel.
@@ -139,6 +139,10 @@
  *	Selects interface with clock source for mISDN and applications.
  *	Set to card number starting with 1. Set to -1 to disable.
  *	By default, the first card is used as clock source.
+ *
+ * hwid:
+ *	NOTE: only one hwid value must be given once
+ * 	Enable special embedded devices with XHFC controllers.
  */
 
 /*
@@ -206,6 +210,11 @@
 static uint	timer;
 static uint	clockdelay_te = CLKDEL_TE;
 static uint	clockdelay_nt = CLKDEL_NT;
+#define HWID_NONE	0
+#define HWID_MINIP4	1
+#define HWID_MINIP8	2
+#define HWID_MINIP16	3
+static uint	hwid = HWID_NONE;
 
 static int	HFC_cnt, Port_cnt, PCM_cnt = 99;
 
@@ -223,6 +232,7 @@
 module_param_array(dslot, int, NULL, S_IRUGO | S_IWUSR);
 module_param_array(iomode, uint, NULL, S_IRUGO | S_IWUSR);
 module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR);
+module_param(hwid, uint, S_IRUGO | S_IWUSR); /* The hardware ID */
 
 #ifdef HFC_REGISTER_DEBUG
 #define HFC_outb(hc, reg, val) \
@@ -252,6 +262,10 @@
 #define HFC_wait_nodebug(hc)		(hc->HFC_wait_nodebug(hc))
 #endif
 
+#ifdef CONFIG_MISDN_HFCMULTI_8xx
+#include "hfc_multi_8xx.h"
+#endif
+
 /* HFC_IO_MODE_PCIMEM */
 static void
 #ifdef HFC_REGISTER_DEBUG
@@ -261,7 +275,7 @@
 HFC_outb_pcimem(struct hfc_multi *hc, u_char reg, u_char val)
 #endif
 {
-	writeb(val, (hc->pci_membase)+reg);
+	writeb(val, hc->pci_membase + reg);
 }
 static u_char
 #ifdef HFC_REGISTER_DEBUG
@@ -270,7 +284,7 @@
 HFC_inb_pcimem(struct hfc_multi *hc, u_char reg)
 #endif
 {
-	return readb((hc->pci_membase)+reg);
+	return readb(hc->pci_membase + reg);
 }
 static u_short
 #ifdef HFC_REGISTER_DEBUG
@@ -279,7 +293,7 @@
 HFC_inw_pcimem(struct hfc_multi *hc, u_char reg)
 #endif
 {
-	return readw((hc->pci_membase)+reg);
+	return readw(hc->pci_membase + reg);
 }
 static void
 #ifdef HFC_REGISTER_DEBUG
@@ -288,7 +302,8 @@
 HFC_wait_pcimem(struct hfc_multi *hc)
 #endif
 {
-	while (readb((hc->pci_membase)+R_STATUS) & V_BUSY);
+	while (readb(hc->pci_membase + R_STATUS) & V_BUSY)
+		cpu_relax();
 }
 
 /* HFC_IO_MODE_REGIO */
@@ -300,7 +315,7 @@
 HFC_outb_regio(struct hfc_multi *hc, u_char reg, u_char val)
 #endif
 {
-	outb(reg, (hc->pci_iobase)+4);
+	outb(reg, hc->pci_iobase + 4);
 	outb(val, hc->pci_iobase);
 }
 static u_char
@@ -310,7 +325,7 @@
 HFC_inb_regio(struct hfc_multi *hc, u_char reg)
 #endif
 {
-	outb(reg, (hc->pci_iobase)+4);
+	outb(reg, hc->pci_iobase + 4);
 	return inb(hc->pci_iobase);
 }
 static u_short
@@ -320,7 +335,7 @@
 HFC_inw_regio(struct hfc_multi *hc, u_char reg)
 #endif
 {
-	outb(reg, (hc->pci_iobase)+4);
+	outb(reg, hc->pci_iobase + 4);
 	return inw(hc->pci_iobase);
 }
 static void
@@ -330,8 +345,9 @@
 HFC_wait_regio(struct hfc_multi *hc)
 #endif
 {
-	outb(R_STATUS, (hc->pci_iobase)+4);
-	while (inb(hc->pci_iobase) & V_BUSY);
+	outb(R_STATUS, hc->pci_iobase + 4);
+	while (inb(hc->pci_iobase) & V_BUSY)
+		cpu_relax();
 }
 
 #ifdef HFC_REGISTER_DEBUG
@@ -350,14 +366,14 @@
 	if (regname[0] == '\0')
 		strcpy(regname, "register");
 
-	bits[7] = '0'+(!!(val&1));
-	bits[6] = '0'+(!!(val&2));
-	bits[5] = '0'+(!!(val&4));
-	bits[4] = '0'+(!!(val&8));
-	bits[3] = '0'+(!!(val&16));
-	bits[2] = '0'+(!!(val&32));
-	bits[1] = '0'+(!!(val&64));
-	bits[0] = '0'+(!!(val&128));
+	bits[7] = '0' + (!!(val & 1));
+	bits[6] = '0' + (!!(val & 2));
+	bits[5] = '0' + (!!(val & 4));
+	bits[4] = '0' + (!!(val & 8));
+	bits[3] = '0' + (!!(val & 16));
+	bits[2] = '0' + (!!(val & 32));
+	bits[1] = '0' + (!!(val & 64));
+	bits[0] = '0' + (!!(val & 128));
 	printk(KERN_DEBUG
 	    "HFC_outb(chip %d, %02x=%s, 0x%02x=%s); in %s() line %d\n",
 	    hc->id, reg, regname, val, bits, function, line);
@@ -380,14 +396,14 @@
 	if (regname[0] == '\0')
 		strcpy(regname, "register");
 
-	bits[7] = '0'+(!!(val&1));
-	bits[6] = '0'+(!!(val&2));
-	bits[5] = '0'+(!!(val&4));
-	bits[4] = '0'+(!!(val&8));
-	bits[3] = '0'+(!!(val&16));
-	bits[2] = '0'+(!!(val&32));
-	bits[1] = '0'+(!!(val&64));
-	bits[0] = '0'+(!!(val&128));
+	bits[7] = '0' + (!!(val & 1));
+	bits[6] = '0' + (!!(val & 2));
+	bits[5] = '0' + (!!(val & 4));
+	bits[4] = '0' + (!!(val & 8));
+	bits[3] = '0' + (!!(val & 16));
+	bits[2] = '0' + (!!(val & 32));
+	bits[1] = '0' + (!!(val & 64));
+	bits[0] = '0' + (!!(val & 128));
 	printk(KERN_DEBUG
 	    "HFC_inb(chip %d, %02x=%s) = 0x%02x=%s; in %s() line %d\n",
 	    hc->id, reg, regname, val, bits, function, line);
@@ -467,6 +483,7 @@
 		len--;
 	}
 }
+
 /* read fifo data (REGIO) */
 static void
 read_fifo_regio(struct hfc_multi *hc, u_char *data, int len)
@@ -512,7 +529,6 @@
 	}
 }
 
-
 static void
 enable_hwirq(struct hfc_multi *hc)
 {
@@ -928,7 +944,7 @@
 			writel(pv, plx_acc_32);
 			if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) {
 				pcmmaster = hc;
-				if (hc->type == 1) {
+				if (hc->ctype == HFC_TYPE_E1) {
 					if (debug & DEBUG_HFCMULTI_PLXSD)
 						printk(KERN_DEBUG
 							"Schedule SYNC_I\n");
@@ -949,7 +965,8 @@
 		pv |= PLX_SYNC_O_EN;
 		writel(pv, plx_acc_32);
 		/* switch to jatt PLL, if not disabled by RX_SYNC */
-		if (hc->type == 1 && !test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) {
+		if (hc->ctype == HFC_TYPE_E1
+				&& !test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) {
 			if (debug & DEBUG_HFCMULTI_PLXSD)
 				printk(KERN_DEBUG "Schedule jatt PLL\n");
 			hc->e1_resync |= 2; /* switch to jatt */
@@ -961,7 +978,7 @@
 				printk(KERN_DEBUG
 					"id=%d (0x%p) = PCM master syncronized "
 					"with QUARTZ\n", hc->id, hc);
-			if (hc->type == 1) {
+			if (hc->ctype == HFC_TYPE_E1) {
 				/* Use the crystal clock for the PCM
 				   master card */
 				if (debug & DEBUG_HFCMULTI_PLXSD)
@@ -972,7 +989,7 @@
 				if (debug & DEBUG_HFCMULTI_PLXSD)
 					printk(KERN_DEBUG
 					    "QUARTZ is automatically "
-					    "enabled by HFC-%dS\n", hc->type);
+					    "enabled by HFC-%dS\n", hc->ctype);
 			}
 			plx_acc_32 = hc->plx_membase + PLX_GPIOC;
 			pv = readl(plx_acc_32);
@@ -996,7 +1013,7 @@
 	if (hc->syncronized) {
 		if (syncmaster == NULL) {
 			if (debug & DEBUG_HFCMULTI_PLXSD)
-				printk(KERN_WARNING "%s: GOT sync on card %d"
+				printk(KERN_DEBUG "%s: GOT sync on card %d"
 					" (id=%d)\n", __func__, hc->id + 1,
 					hc->id);
 			hfcmulti_resync(hc, hc, rm);
@@ -1004,7 +1021,7 @@
 	} else {
 		if (syncmaster == hc) {
 			if (debug & DEBUG_HFCMULTI_PLXSD)
-				printk(KERN_WARNING "%s: LOST sync on card %d"
+				printk(KERN_DEBUG "%s: LOST sync on card %d"
 					" (id=%d)\n", __func__, hc->id + 1,
 					hc->id);
 			hfcmulti_resync(hc, NULL, rm);
@@ -1053,20 +1070,23 @@
 		pv &= ~PLX_DSP_RES_N;
 		writel(pv, plx_acc_32);
 		if (debug & DEBUG_HFCMULTI_INIT)
-			printk(KERN_WARNING "%s: PCM off: PLX_GPIO=%x\n",
+			printk(KERN_DEBUG "%s: PCM off: PLX_GPIO=%x\n",
 				__func__, pv);
 		spin_unlock_irqrestore(&plx_lock, plx_flags);
 	}
 
 	/* disable memory mapped ports / io ports */
 	test_and_clear_bit(HFC_CHIP_PLXSD, &hc->chip); /* prevent resync */
-	pci_write_config_word(hc->pci_dev, PCI_COMMAND, 0);
+	if (hc->pci_dev)
+		pci_write_config_word(hc->pci_dev, PCI_COMMAND, 0);
 	if (hc->pci_membase)
 		iounmap(hc->pci_membase);
 	if (hc->plx_membase)
 		iounmap(hc->plx_membase);
 	if (hc->pci_iobase)
 		release_region(hc->pci_iobase, 8);
+	if (hc->xhfc_membase)
+		iounmap((void *)hc->xhfc_membase);
 
 	if (hc->pci_dev) {
 		pci_disable_device(hc->pci_dev);
@@ -1100,8 +1120,9 @@
 	/* revision check */
 	if (debug & DEBUG_HFCMULTI_INIT)
 		printk(KERN_DEBUG "%s: entered\n", __func__);
-	val = HFC_inb(hc, R_CHIP_ID)>>4;
-	if (val != 0x8 && val != 0xc && val != 0xe) {
+	val = HFC_inb(hc, R_CHIP_ID);
+	if ((val >> 4) != 0x8 && (val >> 4) != 0xc && (val >> 4) != 0xe &&
+	    (val >> 1) != 0x31) {
 		printk(KERN_INFO "HFC_multi: unknown CHIP_ID:%x\n", (u_int)val);
 		err = -EIO;
 		goto out;
@@ -1109,8 +1130,9 @@
 	rev = HFC_inb(hc, R_CHIP_RV);
 	printk(KERN_INFO
 	    "HFC_multi: detected HFC with chip ID=0x%lx revision=%ld%s\n",
-	    val, rev, (rev == 0) ? " (old FIFO handling)" : "");
-	if (rev == 0) {
+	    val, rev, (rev == 0 && (hc->ctype != HFC_TYPE_XHFC)) ?
+		" (old FIFO handling)" : "");
+	if (hc->ctype != HFC_TYPE_XHFC && rev == 0) {
 		test_and_set_bit(HFC_CHIP_REVISION0, &hc->chip);
 		printk(KERN_WARNING
 		    "HFC_multi: NOTE: Your chip is revision 0, "
@@ -1152,6 +1174,12 @@
 		hc->Zlen = 8000;
 		hc->DTMFbase = 0x2000;
 	}
+	if (hc->ctype == HFC_TYPE_XHFC) {
+		hc->Flen = 0x8;
+		hc->Zmin = 0x0;
+		hc->Zlen = 64;
+		hc->DTMFbase = 0x0;
+	}
 	hc->max_trans = poll << 1;
 	if (hc->max_trans > hc->Zlen)
 		hc->max_trans = hc->Zlen;
@@ -1176,7 +1204,7 @@
 		writel(pv, plx_acc_32);
 		spin_unlock_irqrestore(&plx_lock, plx_flags);
 		if (debug & DEBUG_HFCMULTI_INIT)
-			printk(KERN_WARNING "%s: slave/term: PLX_GPIO=%x\n",
+			printk(KERN_DEBUG "%s: slave/term: PLX_GPIO=%x\n",
 				__func__, pv);
 		/*
 		 * If we are the 3rd PLXSD card or higher, we must turn
@@ -1204,13 +1232,17 @@
 			writel(pv, plx_acc_32);
 			spin_unlock_irqrestore(&plx_lock, plx_flags);
 			if (debug & DEBUG_HFCMULTI_INIT)
-			    printk(KERN_WARNING "%s: term off: PLX_GPIO=%x\n",
-					__func__, pv);
+				printk(KERN_DEBUG
+				    "%s: term off: PLX_GPIO=%x\n",
+				    __func__, pv);
 		}
 		spin_unlock_irqrestore(&HFClock, hfc_flags);
 		hc->hw.r_pcm_md0 = V_F0_LEN; /* shift clock for DSP */
 	}
 
+	if (test_bit(HFC_CHIP_EMBSD, &hc->chip))
+		hc->hw.r_pcm_md0 = V_F0_LEN; /* shift clock for DSP */
+
 	/* we only want the real Z2 read-pointer for revision > 0 */
 	if (!test_bit(HFC_CHIP_REVISION0, &hc->chip))
 		hc->hw.r_ram_sz |= V_FZ_MD;
@@ -1234,15 +1266,24 @@
 
 	/* soft reset */
 	HFC_outb(hc, R_CTRL, hc->hw.r_ctrl);
-	HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz);
+	if (hc->ctype == HFC_TYPE_XHFC)
+		HFC_outb(hc, 0x0C /* R_FIFO_THRES */,
+				0x11 /* 16 Bytes TX/RX */);
+	else
+		HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz);
 	HFC_outb(hc, R_FIFO_MD, 0);
-	hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES | V_RLD_EPR;
+	if (hc->ctype == HFC_TYPE_XHFC)
+		hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES;
+	else
+		hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES
+			| V_RLD_EPR;
 	HFC_outb(hc, R_CIRM, hc->hw.r_cirm);
 	udelay(100);
 	hc->hw.r_cirm = 0;
 	HFC_outb(hc, R_CIRM, hc->hw.r_cirm);
 	udelay(100);
-	HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz);
+	if (hc->ctype != HFC_TYPE_XHFC)
+		HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz);
 
 	/* Speech Design PLX bridge pcm and sync mode */
 	if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
@@ -1254,13 +1295,13 @@
 			pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N;
 			pv |= PLX_SYNC_O_EN;
 			if (debug & DEBUG_HFCMULTI_INIT)
-				printk(KERN_WARNING "%s: master: PLX_GPIO=%x\n",
+				printk(KERN_DEBUG "%s: master: PLX_GPIO=%x\n",
 					__func__, pv);
 		} else {
 			pv &= ~(PLX_MASTER_EN | PLX_SLAVE_EN_N);
 			pv &= ~PLX_SYNC_O_EN;
 			if (debug & DEBUG_HFCMULTI_INIT)
-				printk(KERN_WARNING "%s: slave: PLX_GPIO=%x\n",
+				printk(KERN_DEBUG "%s: slave: PLX_GPIO=%x\n",
 					__func__, pv);
 		}
 		writel(pv, plx_acc_32);
@@ -1278,13 +1319,16 @@
 	HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0xa0);
 	if (test_bit(HFC_CHIP_PLXSD, &hc->chip))
 		HFC_outb(hc, R_PCM_MD2, V_SYNC_SRC); /* sync via SYNC_I / O */
+	else if (test_bit(HFC_CHIP_EMBSD, &hc->chip))
+		HFC_outb(hc, R_PCM_MD2, 0x10); /* V_C2O_EN */
 	else
 		HFC_outb(hc, R_PCM_MD2, 0x00); /* sync from interface */
 	HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00);
 	for (i = 0; i < 256; i++) {
 		HFC_outb_nodebug(hc, R_SLOT, i);
 		HFC_outb_nodebug(hc, A_SL_CFG, 0);
-		HFC_outb_nodebug(hc, A_CONF, 0);
+		if (hc->ctype != HFC_TYPE_XHFC)
+			HFC_outb_nodebug(hc, A_CONF, 0);
 		hc->slot_owner[i] = -1;
 	}
 
@@ -1296,6 +1340,9 @@
 		HFC_outb(hc, R_BRG_PCM_CFG, V_PCM_CLK);
 	}
 
+	if (test_bit(HFC_CHIP_EMBSD, &hc->chip))
+		HFC_outb(hc, 0x02 /* R_CLK_CFG */, 0x40 /* V_CLKO_OFF */);
+
 	/* B410P GPIO */
 	if (test_bit(HFC_CHIP_B410P, &hc->chip)) {
 		printk(KERN_NOTICE "Setting GPIOs\n");
@@ -1366,8 +1413,8 @@
 				writel(pv, plx_acc_32);
 				spin_unlock_irqrestore(&plx_lock, plx_flags);
 				if (debug & DEBUG_HFCMULTI_INIT)
-				    printk(KERN_WARNING "%s: master: PLX_GPIO"
-					"=%x\n", __func__, pv);
+					printk(KERN_DEBUG "%s: master: "
+					    "PLX_GPIO=%x\n", __func__, pv);
 			}
 			hc->hw.r_pcm_md0 |= V_PCM_MD;
 			HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00);
@@ -1401,7 +1448,7 @@
 		writel(pv, plx_acc_32);
 		spin_unlock_irqrestore(&plx_lock, plx_flags);
 		if (debug & DEBUG_HFCMULTI_INIT)
-			printk(KERN_WARNING "%s: reset off: PLX_GPIO=%x\n",
+			printk(KERN_DEBUG "%s: reset off: PLX_GPIO=%x\n",
 				__func__, pv);
 	}
 
@@ -1424,7 +1471,7 @@
 	hc->hw.r_irqmsk_misc |= V_TI_IRQMSK;
 
 	/* set E1 state machine IRQ */
-	if (hc->type == 1)
+	if (hc->ctype == HFC_TYPE_E1)
 		hc->hw.r_irqmsk_misc |= V_STA_IRQMSK;
 
 	/* set DTMF detection */
@@ -1444,7 +1491,8 @@
 		r_conf_en = V_CONF_EN | V_ULAW;
 	else
 		r_conf_en = V_CONF_EN;
-	HFC_outb(hc, R_CONF_EN, r_conf_en);
+	if (hc->ctype != HFC_TYPE_XHFC)
+		HFC_outb(hc, R_CONF_EN, r_conf_en);
 
 	/* setting leds */
 	switch (hc->leds) {
@@ -1468,16 +1516,23 @@
 		break;
 	}
 
+	if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) {
+		hc->hw.r_st_sync = 0x10; /* V_AUTO_SYNCI */
+		HFC_outb(hc, R_ST_SYNC, hc->hw.r_st_sync);
+	}
+
 	/* set master clock */
 	if (hc->masterclk >= 0) {
 		if (debug & DEBUG_HFCMULTI_INIT)
 			printk(KERN_DEBUG "%s: setting ST master clock "
 			    "to port %d (0..%d)\n",
 			    __func__, hc->masterclk, hc->ports-1);
-		hc->hw.r_st_sync = hc->masterclk | V_AUTO_SYNC;
+		hc->hw.r_st_sync |= (hc->masterclk | V_AUTO_SYNC);
 		HFC_outb(hc, R_ST_SYNC, hc->hw.r_st_sync);
 	}
 
+
+
 	/* setting misc irq */
 	HFC_outb(hc, R_IRQMSK_MISC, hc->hw.r_irqmsk_misc);
 	if (debug & DEBUG_HFCMULTI_INIT)
@@ -1817,8 +1872,8 @@
 			coeff[(co<<1)|1] = mantissa;
 		}
 		if (debug & DEBUG_HFCMULTI_DTMF)
-			printk("%s: DTMF ready %08x %08x %08x %08x "
-			    "%08x %08x %08x %08x\n", __func__,
+			printk(" DTMF ready %08x %08x %08x %08x "
+			    "%08x %08x %08x %08x\n",
 			    coeff[0], coeff[1], coeff[2], coeff[3],
 			    coeff[4], coeff[5], coeff[6], coeff[7]);
 		hc->chan[ch].coeff_count++;
@@ -1826,7 +1881,7 @@
 			hc->chan[ch].coeff_count = 0;
 			skb = mI_alloc_skb(512, GFP_ATOMIC);
 			if (!skb) {
-				printk(KERN_WARNING "%s: No memory for skb\n",
+				printk(KERN_DEBUG "%s: No memory for skb\n",
 				    __func__);
 				continue;
 			}
@@ -1929,7 +1984,7 @@
 				Fspace = 1;
 		}
 		/* one frame only for ST D-channels, to allow resending */
-		if (hc->type != 1 && dch) {
+		if (hc->ctype != HFC_TYPE_E1 && dch) {
 			if (f1 != f2)
 				Fspace = 0;
 		}
@@ -1945,6 +2000,9 @@
 				"%d!=%d\n", __func__, hc->id + 1, temp, z2);
 		z2 = temp; /* repeat unti Z2 is equal */
 	}
+	hc->chan[ch].Zfill = z1 - z2;
+	if (hc->chan[ch].Zfill < 0)
+		hc->chan[ch].Zfill += hc->Zlen;
 	Zspace = z2 - z1;
 	if (Zspace <= 0)
 		Zspace += hc->Zlen;
@@ -1968,12 +2026,22 @@
 					    "slot_tx %d\n",
 					    __func__, ch, slot_tx);
 				/* connect slot */
-				HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 |
-				    V_HDLC_TRP | V_IFF);
+				if (hc->ctype == HFC_TYPE_XHFC)
+					HFC_outb(hc, A_CON_HDLC, 0xc0
+					    | 0x07 << 2 | V_HDLC_TRP | V_IFF);
+						/* Enable FIFO, no interrupt */
+				else
+					HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 |
+					    V_HDLC_TRP | V_IFF);
 				HFC_outb_nodebug(hc, R_FIFO, ch<<1 | 1);
 				HFC_wait_nodebug(hc);
-				HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 |
-				    V_HDLC_TRP | V_IFF);
+				if (hc->ctype == HFC_TYPE_XHFC)
+					HFC_outb(hc, A_CON_HDLC, 0xc0
+					    | 0x07 << 2 | V_HDLC_TRP | V_IFF);
+						/* Enable FIFO, no interrupt */
+				else
+					HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 |
+					    V_HDLC_TRP | V_IFF);
 				HFC_outb_nodebug(hc, R_FIFO, ch<<1);
 				HFC_wait_nodebug(hc);
 			}
@@ -2001,10 +2069,22 @@
 			    "FIFO data: channel %d slot_tx %d\n",
 			    __func__, ch, slot_tx);
 		/* disconnect slot */
-		HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | V_HDLC_TRP | V_IFF);
+		if (hc->ctype == HFC_TYPE_XHFC)
+			HFC_outb(hc, A_CON_HDLC, 0x80
+			    | 0x07 << 2 | V_HDLC_TRP | V_IFF);
+				/* Enable FIFO, no interrupt */
+		else
+			HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 |
+			    V_HDLC_TRP | V_IFF);
 		HFC_outb_nodebug(hc, R_FIFO, ch<<1 | 1);
 		HFC_wait_nodebug(hc);
-		HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | V_HDLC_TRP | V_IFF);
+		if (hc->ctype == HFC_TYPE_XHFC)
+			HFC_outb(hc, A_CON_HDLC, 0x80
+			    | 0x07 << 2 | V_HDLC_TRP | V_IFF);
+				/* Enable FIFO, no interrupt */
+		else
+			HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 |
+			    V_HDLC_TRP | V_IFF);
 		HFC_outb_nodebug(hc, R_FIFO, ch<<1);
 		HFC_wait_nodebug(hc);
 	}
@@ -2027,10 +2107,11 @@
 		printk(KERN_DEBUG "%s(card %d): fifo(%d) has %d bytes space "
 		    "left (z1=%04x, z2=%04x) sending %d of %d bytes %s\n",
 			__func__, hc->id + 1, ch, Zspace, z1, z2, ii-i, len-i,
-			temp ? "HDLC":"TRANS");
+			temp ? "HDLC" : "TRANS");
 
 	/* Have to prep the audio data */
 	hc->write_fifo(hc, d, ii - i);
+	hc->chan[ch].Zfill += ii - i;
 	*idxp = ii;
 
 	/* if not all data has been written */
@@ -2226,7 +2307,7 @@
 			if (dch)
 				recv_Dchannel(dch);
 			else
-				recv_Bchannel(bch);
+				recv_Bchannel(bch, MISDN_ID_ANY);
 			*sp = skb;
 			again++;
 			goto next_frame;
@@ -2258,7 +2339,7 @@
 			    "(z1=%04x, z2=%04x) TRANS\n",
 				__func__, hc->id + 1, ch, Zsize, z1, z2);
 		/* only bch is transparent */
-		recv_Bchannel(bch);
+		recv_Bchannel(bch, hc->chan[ch].Zfill);
 		*sp = skb;
 	}
 }
@@ -2323,7 +2404,7 @@
 		spin_unlock_irqrestore(&HFClock, flags);
 	}
 
-	if (hc->type != 1 || hc->e1_state == 1)
+	if (hc->ctype != HFC_TYPE_E1 || hc->e1_state == 1)
 		for (ch = 0; ch <= 31; ch++) {
 			if (hc->created[hc->chan[ch].port]) {
 				hfcmulti_tx(hc, ch);
@@ -2346,7 +2427,7 @@
 				}
 			}
 		}
-	if (hc->type == 1 && hc->created[0]) {
+	if (hc->ctype == HFC_TYPE_E1 && hc->created[0]) {
 		dch = hc->chan[hc->dslot].dch;
 		if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dslot].cfg)) {
 			/* LOS */
@@ -2606,7 +2687,10 @@
 		"card %d, this is no bug.\n", hc->id + 1, irqsem);
 	irqsem = hc->id + 1;
 #endif
-
+#ifdef CONFIG_MISDN_HFCMULTI_8xx
+	if (hc->immap->im_cpm.cp_pbdat & hc->pb_irqmsk)
+		goto irq_notforus;
+#endif
 	if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
 		spin_lock_irqsave(&plx_lock, flags);
 		plx_acc = hc->plx_membase + PLX_INTCSR;
@@ -2646,7 +2730,7 @@
 	}
 	hc->irqcnt++;
 	if (r_irq_statech) {
-		if (hc->type != 1)
+		if (hc->ctype != HFC_TYPE_E1)
 			ph_state_irq(hc, r_irq_statech);
 	}
 	if (status & V_EXT_IRQSTA)
@@ -2660,7 +2744,7 @@
 		r_irq_misc = HFC_inb_nodebug(hc, R_IRQ_MISC);
 		r_irq_misc &= hc->hw.r_irqmsk_misc; /* ignore disabled irqs */
 		if (r_irq_misc & V_STA_IRQ) {
-			if (hc->type == 1) {
+			if (hc->ctype == HFC_TYPE_E1) {
 				/* state machine */
 				dch = hc->chan[hc->dslot].dch;
 				e1_syncsta = HFC_inb_nodebug(hc, R_SYNC_STA);
@@ -2699,13 +2783,13 @@
 			handle_timer_irq(hc);
 		}
 
-		if (r_irq_misc & V_DTMF_IRQ) {
+		if (r_irq_misc & V_DTMF_IRQ)
 			hfcmulti_dtmf(hc);
-		}
+
 		if (r_irq_misc & V_IRQ_PROC) {
 			static int irq_proc_cnt;
 			if (!irq_proc_cnt++)
-				printk(KERN_WARNING "%s: got V_IRQ_PROC -"
+				printk(KERN_DEBUG "%s: got V_IRQ_PROC -"
 				    " this should not happen\n", __func__);
 		}
 
@@ -2782,7 +2866,8 @@
 		if (hc->slot_owner[oslot_tx<<1] == ch) {
 			HFC_outb(hc, R_SLOT, oslot_tx << 1);
 			HFC_outb(hc, A_SL_CFG, 0);
-			HFC_outb(hc, A_CONF, 0);
+			if (hc->ctype != HFC_TYPE_XHFC)
+				HFC_outb(hc, A_CONF, 0);
 			hc->slot_owner[oslot_tx<<1] = -1;
 		} else {
 			if (debug & DEBUG_HFCMULTI_MODE)
@@ -2835,7 +2920,9 @@
 			    flow_tx, routing, conf);
 		HFC_outb(hc, R_SLOT, slot_tx << 1);
 		HFC_outb(hc, A_SL_CFG, (ch<<1) | routing);
-		HFC_outb(hc, A_CONF, (conf < 0) ? 0 : (conf | V_CONF_SL));
+		if (hc->ctype != HFC_TYPE_XHFC)
+			HFC_outb(hc, A_CONF,
+				(conf < 0) ? 0 : (conf | V_CONF_SL));
 		hc->slot_owner[slot_tx << 1] = ch;
 		hc->chan[ch].slot_tx = slot_tx;
 		hc->chan[ch].bank_tx = bank_tx;
@@ -2852,7 +2939,7 @@
 		else
 			flow_rx = 0xc0; /* ST->(FIFO,PCM) */
 		/* put on slot */
-		routing = bank_rx?0x80:0xc0; /* reversed */
+		routing = bank_rx ? 0x80 : 0xc0; /* reversed */
 		if (conf >= 0 || bank_rx > 1)
 			routing = 0x40; /* loop */
 		if (debug & DEBUG_HFCMULTI_MODE)
@@ -2885,9 +2972,9 @@
 		HFC_outb(hc, A_IRQ_MSK, 0);
 		HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
 		HFC_wait(hc);
-		if (hc->chan[ch].bch && hc->type != 1) {
+		if (hc->chan[ch].bch && hc->ctype != HFC_TYPE_E1) {
 			hc->hw.a_st_ctrl0[hc->chan[ch].port] &=
-			    ((ch & 0x3) == 0)? ~V_B1_EN: ~V_B2_EN;
+			    ((ch & 0x3) == 0) ? ~V_B1_EN : ~V_B2_EN;
 			HFC_outb(hc, R_ST_SEL, hc->chan[ch].port);
 			/* undocumented: delay after R_ST_SEL */
 			udelay(1);
@@ -2961,8 +3048,13 @@
 			/* enable TX fifo */
 			HFC_outb(hc, R_FIFO, ch << 1);
 			HFC_wait(hc);
-			HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 |
-			    V_HDLC_TRP | V_IFF);
+			if (hc->ctype == HFC_TYPE_XHFC)
+				HFC_outb(hc, A_CON_HDLC, flow_tx | 0x07 << 2 |
+					V_HDLC_TRP | V_IFF);
+					/* Enable FIFO, no interrupt */
+			else
+				HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 |
+					V_HDLC_TRP | V_IFF);
 			HFC_outb(hc, A_SUBCH_CFG, 0);
 			HFC_outb(hc, A_IRQ_MSK, 0);
 			HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
@@ -2972,13 +3064,19 @@
 			/* enable RX fifo */
 			HFC_outb(hc, R_FIFO, (ch<<1)|1);
 			HFC_wait(hc);
-			HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00 | V_HDLC_TRP);
+			if (hc->ctype == HFC_TYPE_XHFC)
+				HFC_outb(hc, A_CON_HDLC, flow_rx | 0x07 << 2 |
+					V_HDLC_TRP);
+					/* Enable FIFO, no interrupt*/
+			else
+				HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00 |
+						V_HDLC_TRP);
 			HFC_outb(hc, A_SUBCH_CFG, 0);
 			HFC_outb(hc, A_IRQ_MSK, 0);
 			HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
 			HFC_wait(hc);
 		}
-		if (hc->type != 1) {
+		if (hc->ctype != HFC_TYPE_E1) {
 			hc->hw.a_st_ctrl0[hc->chan[ch].port] |=
 			    ((ch & 0x3) == 0) ? V_B1_EN : V_B2_EN;
 			HFC_outb(hc, R_ST_SEL, hc->chan[ch].port);
@@ -2999,7 +3097,7 @@
 		/* enable TX fifo */
 		HFC_outb(hc, R_FIFO, ch<<1);
 		HFC_wait(hc);
-		if (hc->type == 1 || hc->chan[ch].bch) {
+		if (hc->ctype == HFC_TYPE_E1 || hc->chan[ch].bch) {
 			/* E1 or B-channel */
 			HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04);
 			HFC_outb(hc, A_SUBCH_CFG, 0);
@@ -3015,7 +3113,7 @@
 		HFC_outb(hc, R_FIFO, (ch<<1)|1);
 		HFC_wait(hc);
 		HFC_outb(hc, A_CON_HDLC, flow_rx | 0x04);
-		if (hc->type == 1 || hc->chan[ch].bch)
+		if (hc->ctype == HFC_TYPE_E1 || hc->chan[ch].bch)
 			HFC_outb(hc, A_SUBCH_CFG, 0); /* full 8 bits */
 		else
 			HFC_outb(hc, A_SUBCH_CFG, 2); /* 2 bits dchannel */
@@ -3024,7 +3122,7 @@
 		HFC_wait(hc);
 		if (hc->chan[ch].bch) {
 			test_and_set_bit(FLG_HDLC, &hc->chan[ch].bch->Flags);
-			if (hc->type != 1) {
+			if (hc->ctype != HFC_TYPE_E1) {
 				hc->hw.a_st_ctrl0[hc->chan[ch].port] |=
 				  ((ch&0x3) == 0) ? V_B1_EN : V_B2_EN;
 				HFC_outb(hc, R_ST_SEL, hc->chan[ch].port);
@@ -3104,7 +3202,7 @@
 	case HW_RESET_REQ:
 		/* start activation */
 		spin_lock_irqsave(&hc->lock, flags);
-		if (hc->type == 1) {
+		if (hc->ctype == HFC_TYPE_E1) {
 			if (debug & DEBUG_HFCMULTI_MSG)
 				printk(KERN_DEBUG
 				    "%s: HW_RESET_REQ no BRI\n",
@@ -3125,7 +3223,7 @@
 	case HW_DEACT_REQ:
 		/* start deactivation */
 		spin_lock_irqsave(&hc->lock, flags);
-		if (hc->type == 1) {
+		if (hc->ctype == HFC_TYPE_E1) {
 			if (debug & DEBUG_HFCMULTI_MSG)
 				printk(KERN_DEBUG
 				    "%s: HW_DEACT_REQ no BRI\n",
@@ -3159,7 +3257,7 @@
 		break;
 	case HW_POWERUP_REQ:
 		spin_lock_irqsave(&hc->lock, flags);
-		if (hc->type == 1) {
+		if (hc->ctype == HFC_TYPE_E1) {
 			if (debug & DEBUG_HFCMULTI_MSG)
 				printk(KERN_DEBUG
 				    "%s: HW_POWERUP_REQ no BRI\n",
@@ -3236,7 +3334,7 @@
 				    __func__, hc->chan[dch->slot].port,
 				    hc->ports-1);
 			/* start activation */
-			if (hc->type == 1) {
+			if (hc->ctype == HFC_TYPE_E1) {
 				ph_state_change(dch);
 				if (debug & DEBUG_HFCMULTI_STATE)
 					printk(KERN_DEBUG
@@ -3269,7 +3367,7 @@
 				    __func__, hc->chan[dch->slot].port,
 				    hc->ports-1);
 			/* start deactivation */
-			if (hc->type == 1) {
+			if (hc->ctype == HFC_TYPE_E1) {
 				if (debug & DEBUG_HFCMULTI_MSG)
 					printk(KERN_DEBUG
 					    "%s: PH_DEACTIVATE no BRI\n",
@@ -3410,9 +3508,9 @@
 		switch (hh->id) {
 		case HFC_SPL_LOOP_ON: /* set sample loop */
 			if (debug & DEBUG_HFCMULTI_MSG)
-			printk(KERN_DEBUG
-			    "%s: HFC_SPL_LOOP_ON (len = %d)\n",
-			    __func__, skb->len);
+				printk(KERN_DEBUG
+				    "%s: HFC_SPL_LOOP_ON (len = %d)\n",
+				    __func__, skb->len);
 			ret = 0;
 			break;
 		case HFC_SPL_LOOP_OFF: /* set silence */
@@ -3489,6 +3587,8 @@
 		features->hfc_id = hc->id;
 		if (test_bit(HFC_CHIP_DTMF, &hc->chip))
 			features->hfc_dtmf = 1;
+		if (test_bit(HFC_CHIP_CONF, &hc->chip))
+			features->hfc_conf = 1;
 		features->hfc_loops = 0;
 		if (test_bit(HFC_CHIP_B410P, &hc->chip)) {
 			features->hfc_echocanhw = 1;
@@ -3619,14 +3719,13 @@
 	int ch, i;
 
 	if (!dch) {
-		printk(KERN_WARNING "%s: ERROR given dch is NULL\n",
-		    __func__);
+		printk(KERN_WARNING "%s: ERROR given dch is NULL\n", __func__);
 		return;
 	}
 	hc = dch->hw;
 	ch = dch->slot;
 
-	if (hc->type == 1) {
+	if (hc->ctype == HFC_TYPE_E1) {
 		if (dch->dev.D.protocol == ISDN_P_TE_E1) {
 			if (debug & DEBUG_HFCMULTI_STATE)
 				printk(KERN_DEBUG
@@ -3641,14 +3740,15 @@
 		switch (dch->state) {
 		case (1):
 			if (hc->e1_state != 1) {
-			    for (i = 1; i <= 31; i++) {
-				/* reset fifos on e1 activation */
-				HFC_outb_nodebug(hc, R_FIFO, (i << 1) | 1);
-				HFC_wait_nodebug(hc);
-				HFC_outb_nodebug(hc,
-					R_INC_RES_FIFO, V_RES_F);
-				HFC_wait_nodebug(hc);
-			    }
+				for (i = 1; i <= 31; i++) {
+					/* reset fifos on e1 activation */
+					HFC_outb_nodebug(hc, R_FIFO,
+						(i << 1) | 1);
+					HFC_wait_nodebug(hc);
+					HFC_outb_nodebug(hc, R_INC_RES_FIFO,
+						V_RES_F);
+					HFC_wait_nodebug(hc);
+				}
 			}
 			test_and_set_bit(FLG_ACTIVE, &dch->Flags);
 			_queue_data(&dch->dev.D, PH_ACTIVATE_IND,
@@ -3751,7 +3851,7 @@
 	if (debug & DEBUG_HFCMULTI_INIT)
 		printk(KERN_DEBUG "%s: entered\n", __func__);
 
-	if (hc->type == 1) {
+	if (hc->ctype == HFC_TYPE_E1) {
 		hc->chan[hc->dslot].slot_tx = -1;
 		hc->chan[hc->dslot].slot_rx = -1;
 		hc->chan[hc->dslot].conf = -1;
@@ -3900,6 +4000,11 @@
 		}
 		if (!test_bit(HFC_CFG_NONCAP_TX, &hc->chan[i].cfg))
 			hc->hw.a_st_ctrl0[pt] |= V_TX_LI;
+		if (hc->ctype == HFC_TYPE_XHFC) {
+			hc->hw.a_st_ctrl0[pt] |= 0x40 /* V_ST_PU_CTRL */;
+			HFC_outb(hc, 0x35 /* A_ST_CTRL3 */,
+				0x7c << 1 /* V_ST_PULSE */);
+		}
 		/* line setup */
 		HFC_outb(hc, A_ST_CTRL0,  hc->hw.a_st_ctrl0[pt]);
 		/* disable E-channel */
@@ -3943,12 +4048,12 @@
 		return -EINVAL;
 	if ((dch->dev.D.protocol != ISDN_P_NONE) &&
 	    (dch->dev.D.protocol != rq->protocol)) {
-	    if (debug & DEBUG_HFCMULTI_MODE)
-		printk(KERN_WARNING "%s: change protocol %x to %x\n",
-		    __func__, dch->dev.D.protocol, rq->protocol);
+		if (debug & DEBUG_HFCMULTI_MODE)
+			printk(KERN_DEBUG "%s: change protocol %x to %x\n",
+			    __func__, dch->dev.D.protocol, rq->protocol);
 	}
-	if ((dch->dev.D.protocol == ISDN_P_TE_S0)
-	 && (rq->protocol != ISDN_P_TE_S0))
+	if ((dch->dev.D.protocol == ISDN_P_TE_S0) &&
+	    (rq->protocol != ISDN_P_TE_S0))
 		l1_event(dch->l1, CLOSE_CHANNEL);
 	if (dch->dev.D.protocol != rq->protocol) {
 		if (rq->protocol == ISDN_P_TE_S0) {
@@ -3986,7 +4091,7 @@
 		return -EINVAL;
 	if (rq->protocol == ISDN_P_NONE)
 		return -EINVAL;
-	if (hc->type == 1)
+	if (hc->ctype == HFC_TYPE_E1)
 		ch = rq->adr.channel;
 	else
 		ch = (rq->adr.channel - 1) + (dch->slot - 2);
@@ -4013,11 +4118,41 @@
 static int
 channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq)
 {
+	struct hfc_multi	*hc = dch->hw;
 	int	ret = 0;
+	int	wd_mode, wd_cnt;
 
 	switch (cq->op) {
 	case MISDN_CTRL_GETOP:
-		cq->op = 0;
+		cq->op = MISDN_CTRL_HFC_OP;
+		break;
+	case MISDN_CTRL_HFC_WD_INIT: /* init the watchdog */
+		wd_cnt = cq->p1 & 0xf;
+		wd_mode = !!(cq->p1 >> 4);
+		if (debug & DEBUG_HFCMULTI_MSG)
+			printk(KERN_DEBUG "%s: MISDN_CTRL_HFC_WD_INIT mode %s"
+			    ", counter 0x%x\n", __func__,
+			    wd_mode ? "AUTO" : "MANUAL", wd_cnt);
+		/* set the watchdog timer */
+		HFC_outb(hc, R_TI_WD, poll_timer | (wd_cnt << 4));
+		hc->hw.r_bert_wd_md = (wd_mode ? V_AUTO_WD_RES : 0);
+		if (hc->ctype == HFC_TYPE_XHFC)
+			hc->hw.r_bert_wd_md |= 0x40 /* V_WD_EN */;
+		/* init the watchdog register and reset the counter */
+		HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES);
+		if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
+			/* enable the watchdog output for Speech-Design */
+			HFC_outb(hc, R_GPIO_SEL,  V_GPIO_SEL7);
+			HFC_outb(hc, R_GPIO_EN1,  V_GPIO_EN15);
+			HFC_outb(hc, R_GPIO_OUT1, 0);
+			HFC_outb(hc, R_GPIO_OUT1, V_GPIO_OUT15);
+		}
+		break;
+	case MISDN_CTRL_HFC_WD_RESET: /* reset the watchdog counter */
+		if (debug & DEBUG_HFCMULTI_MSG)
+			printk(KERN_DEBUG "%s: MISDN_CTRL_HFC_WD_RESET\n",
+			    __func__);
+		HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES);
 		break;
 	default:
 		printk(KERN_WARNING "%s: unknown Op %x\n",
@@ -4047,7 +4182,7 @@
 		switch (rq->protocol) {
 		case ISDN_P_TE_S0:
 		case ISDN_P_NT_S0:
-			if (hc->type == 1) {
+			if (hc->ctype == HFC_TYPE_E1) {
 				err = -EINVAL;
 				break;
 			}
@@ -4055,7 +4190,7 @@
 			break;
 		case ISDN_P_TE_E1:
 		case ISDN_P_NT_E1:
-			if (hc->type != 1) {
+			if (hc->ctype != HFC_TYPE_E1) {
 				err = -EINVAL;
 				break;
 			}
@@ -4122,13 +4257,13 @@
 	disable_hwirq(hc);
 	spin_unlock_irqrestore(&hc->lock, flags);
 
-	if (request_irq(hc->pci_dev->irq, hfcmulti_interrupt, IRQF_SHARED,
+	if (request_irq(hc->irq, hfcmulti_interrupt, IRQF_SHARED,
 	    "HFC-multi", hc)) {
 		printk(KERN_WARNING "mISDN: Could not get interrupt %d.\n",
-		    hc->pci_dev->irq);
+		    hc->irq);
+		hc->irq = 0;
 		return -EIO;
 	}
-	hc->irq = hc->pci_dev->irq;
 
 	if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
 		spin_lock_irqsave(&plx_lock, plx_flags);
@@ -4187,7 +4322,7 @@
 	}
 
 	if (debug & DEBUG_HFCMULTI_INIT)
-		printk(KERN_WARNING "%s: free irq %d\n", __func__, hc->irq);
+		printk(KERN_DEBUG "%s: free irq %d\n", __func__, hc->irq);
 	if (hc->irq) {
 		free_irq(hc->irq, hc);
 		hc->irq = 0;
@@ -4235,6 +4370,10 @@
 	hc->ledstate = 0xAFFEAFFE;
 	hc->opticalsupport = m->opticalsupport;
 
+	hc->pci_iobase = 0;
+	hc->pci_membase = NULL;
+	hc->plx_membase = NULL;
+
 	/* set memory access methods */
 	if (m->io_mode) /* use mode from card config */
 		hc->io_mode = m->io_mode;
@@ -4242,44 +4381,12 @@
 	case HFC_IO_MODE_PLXSD:
 		test_and_set_bit(HFC_CHIP_PLXSD, &hc->chip);
 		hc->slots = 128; /* required */
-		/* fall through */
-	case HFC_IO_MODE_PCIMEM:
 		hc->HFC_outb = HFC_outb_pcimem;
 		hc->HFC_inb = HFC_inb_pcimem;
 		hc->HFC_inw = HFC_inw_pcimem;
 		hc->HFC_wait = HFC_wait_pcimem;
 		hc->read_fifo = read_fifo_pcimem;
 		hc->write_fifo = write_fifo_pcimem;
-		break;
-	case HFC_IO_MODE_REGIO:
-		hc->HFC_outb = HFC_outb_regio;
-		hc->HFC_inb = HFC_inb_regio;
-		hc->HFC_inw = HFC_inw_regio;
-		hc->HFC_wait = HFC_wait_regio;
-		hc->read_fifo = read_fifo_regio;
-		hc->write_fifo = write_fifo_regio;
-		break;
-	default:
-		printk(KERN_WARNING "HFC-multi: Invalid IO mode.\n");
-		pci_disable_device(hc->pci_dev);
-		return -EIO;
-	}
-	hc->HFC_outb_nodebug = hc->HFC_outb;
-	hc->HFC_inb_nodebug = hc->HFC_inb;
-	hc->HFC_inw_nodebug = hc->HFC_inw;
-	hc->HFC_wait_nodebug = hc->HFC_wait;
-#ifdef HFC_REGISTER_DEBUG
-	hc->HFC_outb = HFC_outb_debug;
-	hc->HFC_inb = HFC_inb_debug;
-	hc->HFC_inw = HFC_inw_debug;
-	hc->HFC_wait = HFC_wait_debug;
-#endif
-	hc->pci_iobase = 0;
-	hc->pci_membase = NULL;
-	hc->plx_membase = NULL;
-
-	switch (hc->io_mode) {
-	case HFC_IO_MODE_PLXSD:
 		hc->plx_origmembase =  hc->pci_dev->resource[0].start;
 		/* MEMBASE 1 is PLX PCI Bridge */
 
@@ -4327,6 +4434,12 @@
 		pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO);
 		break;
 	case HFC_IO_MODE_PCIMEM:
+		hc->HFC_outb = HFC_outb_pcimem;
+		hc->HFC_inb = HFC_inb_pcimem;
+		hc->HFC_inw = HFC_inw_pcimem;
+		hc->HFC_wait = HFC_wait_pcimem;
+		hc->read_fifo = read_fifo_pcimem;
+		hc->write_fifo = write_fifo_pcimem;
 		hc->pci_origmembase = hc->pci_dev->resource[1].start;
 		if (!hc->pci_origmembase) {
 			printk(KERN_WARNING
@@ -4343,12 +4456,18 @@
 			pci_disable_device(hc->pci_dev);
 			return -EIO;
 		}
-		printk(KERN_INFO "card %d: defined at MEMBASE %#lx (%#lx) IRQ %d "
-		    "HZ %d leds-type %d\n", hc->id, (u_long)hc->pci_membase,
+		printk(KERN_INFO "card %d: defined at MEMBASE %#lx (%#lx) IRQ "
+		    "%d HZ %d leds-type %d\n", hc->id, (u_long)hc->pci_membase,
 		    hc->pci_origmembase, hc->pci_dev->irq, HZ, hc->leds);
 		pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO);
 		break;
 	case HFC_IO_MODE_REGIO:
+		hc->HFC_outb = HFC_outb_regio;
+		hc->HFC_inb = HFC_inb_regio;
+		hc->HFC_inw = HFC_inw_regio;
+		hc->HFC_wait = HFC_wait_regio;
+		hc->read_fifo = read_fifo_regio;
+		hc->write_fifo = write_fifo_regio;
 		hc->pci_iobase = (u_int) hc->pci_dev->resource[0].start;
 		if (!hc->pci_iobase) {
 			printk(KERN_WARNING
@@ -4430,7 +4549,7 @@
 		dch->timer.function = NULL;
 	}
 
-	if (hc->type == 1) { /* E1 */
+	if (hc->ctype == HFC_TYPE_E1) { /* E1 */
 		/* remove sync */
 		if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
 			hc->syncronized = 0;
@@ -4508,7 +4627,7 @@
 	int	ch;
 
 	if (debug & DEBUG_HFCMULTI_INIT)
-		printk(KERN_WARNING "%s: release card (%d) entered\n",
+		printk(KERN_DEBUG "%s: release card (%d) entered\n",
 		    __func__, hc->id);
 
 	/* unregister clock source */
@@ -4537,7 +4656,7 @@
 	/* release hardware & irq */
 	if (hc->irq) {
 		if (debug & DEBUG_HFCMULTI_INIT)
-			printk(KERN_WARNING "%s: free irq %d\n",
+			printk(KERN_DEBUG "%s: free irq %d\n",
 			    __func__, hc->irq);
 		free_irq(hc->irq, hc);
 		hc->irq = 0;
@@ -4546,17 +4665,17 @@
 	release_io_hfcmulti(hc);
 
 	if (debug & DEBUG_HFCMULTI_INIT)
-		printk(KERN_WARNING "%s: remove instance from list\n",
+		printk(KERN_DEBUG "%s: remove instance from list\n",
 		     __func__);
 	list_del(&hc->list);
 
 	if (debug & DEBUG_HFCMULTI_INIT)
-		printk(KERN_WARNING "%s: delete instance\n", __func__);
+		printk(KERN_DEBUG "%s: delete instance\n", __func__);
 	if (hc == syncmaster)
 		syncmaster = NULL;
 	kfree(hc);
 	if (debug & DEBUG_HFCMULTI_INIT)
-		printk(KERN_WARNING "%s: card successfully removed\n",
+		printk(KERN_DEBUG "%s: card successfully removed\n",
 		    __func__);
 }
 
@@ -4579,7 +4698,7 @@
 	    (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
 	dch->dev.D.send = handle_dmsg;
 	dch->dev.D.ctrl = hfcm_dctrl;
-	dch->dev.nrbchan = (hc->dslot)?30:31;
+	dch->dev.nrbchan = (hc->dslot) ? 30 : 31;
 	dch->slot = hc->dslot;
 	hc->chan[hc->dslot].dch = dch;
 	hc->chan[hc->dslot].port = 0;
@@ -4821,7 +4940,7 @@
 	}
 	/* disable E-channel */
 	if (port[Port_cnt] & 0x004) {
-	if (debug & DEBUG_HFCMULTI_INIT)
+		if (debug & DEBUG_HFCMULTI_INIT)
 			printk(KERN_DEBUG
 			    "%s: PROTOCOL disable E-channel: "
 			    "card(%d) port(%d)\n",
@@ -4829,9 +4948,15 @@
 		test_and_set_bit(HFC_CFG_DIS_ECHANNEL,
 		    &hc->chan[i + 2].cfg);
 	}
-	snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-%ds.%d-%d",
-		hc->type, HFC_cnt + 1, pt + 1);
-	ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name);
+	if (hc->ctype == HFC_TYPE_XHFC) {
+		snprintf(name, MISDN_MAX_IDLEN - 1, "xhfc.%d-%d",
+			HFC_cnt + 1, pt + 1);
+		ret = mISDN_register_device(&dch->dev, NULL, name);
+	} else {
+		snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-%ds.%d-%d",
+			hc->ctype, HFC_cnt + 1, pt + 1);
+		ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name);
+	}
 	if (ret)
 		goto free_chan;
 	hc->created[pt] = 1;
@@ -4842,9 +4967,9 @@
 }
 
 static int
-hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent)
+hfcmulti_init(struct hm_map *m, struct pci_dev *pdev,
+    const struct pci_device_id *ent)
 {
-	struct hm_map	*m = (struct hm_map *)ent->driver_data;
 	int		ret_err = 0;
 	int		pt;
 	struct hfc_multi	*hc;
@@ -4879,16 +5004,18 @@
 	}
 	spin_lock_init(&hc->lock);
 	hc->mtyp = m;
-	hc->type =  m->type;
+	hc->ctype =  m->type;
 	hc->ports = m->ports;
 	hc->id = HFC_cnt;
 	hc->pcm = pcm[HFC_cnt];
 	hc->io_mode = iomode[HFC_cnt];
-	if (dslot[HFC_cnt] < 0 && hc->type == 1) {
+	if (dslot[HFC_cnt] < 0 && hc->ctype == HFC_TYPE_E1) {
 		hc->dslot = 0;
 		printk(KERN_INFO "HFC-E1 card has disabled D-channel, but "
 			"31 B-channels\n");
-	} if (dslot[HFC_cnt] > 0 && dslot[HFC_cnt] < 32 && hc->type == 1) {
+	}
+	if (dslot[HFC_cnt] > 0 && dslot[HFC_cnt] < 32
+	    && hc->ctype == HFC_TYPE_E1) {
 		hc->dslot = dslot[HFC_cnt];
 		printk(KERN_INFO "HFC-E1 card has alternating D-channel on "
 			"time slot %d\n", dslot[HFC_cnt]);
@@ -4910,8 +5037,11 @@
 	for (i = 0; i < (poll >> 1); i++)
 		hc->silence_data[i] = hc->silence;
 
-	if (!(type[HFC_cnt] & 0x200))
-		test_and_set_bit(HFC_CHIP_DTMF, &hc->chip);
+	if (hc->ctype != HFC_TYPE_XHFC) {
+		if (!(type[HFC_cnt] & 0x200))
+			test_and_set_bit(HFC_CHIP_DTMF, &hc->chip);
+		test_and_set_bit(HFC_CHIP_CONF, &hc->chip);
+	}
 
 	if (type[HFC_cnt] & 0x800)
 		test_and_set_bit(HFC_CHIP_PCM_SLAVE, &hc->chip);
@@ -4935,8 +5065,18 @@
 		printk(KERN_NOTICE "Watchdog enabled\n");
 	}
 
-	/* setup pci, hc->slots may change due to PLXSD */
-	ret_err = setup_pci(hc, pdev, ent);
+	if (pdev && ent)
+		/* setup pci, hc->slots may change due to PLXSD */
+		ret_err = setup_pci(hc, pdev, ent);
+	else
+#ifdef CONFIG_MISDN_HFCMULTI_8xx
+		ret_err = setup_embedded(hc, m);
+#else
+	{
+		printk(KERN_WARNING "Embedded IO Mode not selected\n");
+		ret_err = -EIO;
+	}
+#endif
 	if (ret_err) {
 		if (hc == syncmaster)
 			syncmaster = NULL;
@@ -4944,7 +5084,17 @@
 		return ret_err;
 	}
 
-	/* crate channels */
+	hc->HFC_outb_nodebug = hc->HFC_outb;
+	hc->HFC_inb_nodebug = hc->HFC_inb;
+	hc->HFC_inw_nodebug = hc->HFC_inw;
+	hc->HFC_wait_nodebug = hc->HFC_wait;
+#ifdef HFC_REGISTER_DEBUG
+	hc->HFC_outb = HFC_outb_debug;
+	hc->HFC_inb = HFC_inb_debug;
+	hc->HFC_inw = HFC_inw_debug;
+	hc->HFC_wait = HFC_wait_debug;
+#endif
+	/* create channels */
 	for (pt = 0; pt < hc->ports; pt++) {
 		if (Port_cnt >= MAX_PORTS) {
 			printk(KERN_ERR "too many ports (max=%d).\n",
@@ -4952,7 +5102,7 @@
 			ret_err = -EINVAL;
 			goto free_card;
 		}
-		if (hc->type == 1)
+		if (hc->ctype == HFC_TYPE_E1)
 			ret_err = init_e1_port(hc, m);
 		else
 			ret_err = init_multi_port(hc, pt);
@@ -5036,6 +5186,7 @@
 		hc->iclock = mISDN_register_clock("HFCMulti", 0, clockctl, hc);
 
 	/* initialize hardware */
+	hc->irq = (m->irq) ? : hc->pci_dev->irq;
 	ret_err = init_card(hc);
 	if (ret_err) {
 		printk(KERN_ERR "init card returns %d\n", ret_err);
@@ -5074,7 +5225,7 @@
 		spin_unlock_irqrestore(&HFClock, flags);
 	}  else {
 		if (debug)
-			printk(KERN_WARNING "%s: drvdata allready removed\n",
+			printk(KERN_DEBUG "%s: drvdata allready removed\n",
 			    __func__);
 	}
 }
@@ -5086,45 +5237,48 @@
 #define VENDOR_PRIM	"PrimuX"
 
 static const struct hm_map hfcm_map[] = {
-/*0*/	{VENDOR_BN, "HFC-1S Card (mini PCI)", 4, 1, 1, 3, 0, DIP_4S, 0},
-/*1*/	{VENDOR_BN, "HFC-2S Card", 4, 2, 1, 3, 0, DIP_4S, 0},
-/*2*/	{VENDOR_BN, "HFC-2S Card (mini PCI)", 4, 2, 1, 3, 0, DIP_4S, 0},
-/*3*/	{VENDOR_BN, "HFC-4S Card", 4, 4, 1, 2, 0, DIP_4S, 0},
-/*4*/	{VENDOR_BN, "HFC-4S Card (mini PCI)", 4, 4, 1, 2, 0, 0, 0},
-/*5*/	{VENDOR_CCD, "HFC-4S Eval (old)", 4, 4, 0, 0, 0, 0, 0},
-/*6*/	{VENDOR_CCD, "HFC-4S IOB4ST", 4, 4, 1, 2, 0, DIP_4S, 0},
-/*7*/	{VENDOR_CCD, "HFC-4S", 4, 4, 1, 2, 0, 0, 0},
-/*8*/	{VENDOR_DIG, "HFC-4S Card", 4, 4, 0, 2, 0, 0, HFC_IO_MODE_REGIO},
-/*9*/	{VENDOR_CCD, "HFC-4S Swyx 4xS0 SX2 QuadBri", 4, 4, 1, 2, 0, 0, 0},
-/*10*/	{VENDOR_JH, "HFC-4S (junghanns 2.0)", 4, 4, 1, 2, 0, 0, 0},
-/*11*/	{VENDOR_PRIM, "HFC-2S Primux Card", 4, 2, 0, 0, 0, 0, 0},
+/*0*/	{VENDOR_BN, "HFC-1S Card (mini PCI)", 4, 1, 1, 3, 0, DIP_4S, 0, 0},
+/*1*/	{VENDOR_BN, "HFC-2S Card", 4, 2, 1, 3, 0, DIP_4S, 0, 0},
+/*2*/	{VENDOR_BN, "HFC-2S Card (mini PCI)", 4, 2, 1, 3, 0, DIP_4S, 0, 0},
+/*3*/	{VENDOR_BN, "HFC-4S Card", 4, 4, 1, 2, 0, DIP_4S, 0, 0},
+/*4*/	{VENDOR_BN, "HFC-4S Card (mini PCI)", 4, 4, 1, 2, 0, 0, 0, 0},
+/*5*/	{VENDOR_CCD, "HFC-4S Eval (old)", 4, 4, 0, 0, 0, 0, 0, 0},
+/*6*/	{VENDOR_CCD, "HFC-4S IOB4ST", 4, 4, 1, 2, 0, DIP_4S, 0, 0},
+/*7*/	{VENDOR_CCD, "HFC-4S", 4, 4, 1, 2, 0, 0, 0, 0},
+/*8*/	{VENDOR_DIG, "HFC-4S Card", 4, 4, 0, 2, 0, 0, HFC_IO_MODE_REGIO, 0},
+/*9*/	{VENDOR_CCD, "HFC-4S Swyx 4xS0 SX2 QuadBri", 4, 4, 1, 2, 0, 0, 0, 0},
+/*10*/	{VENDOR_JH, "HFC-4S (junghanns 2.0)", 4, 4, 1, 2, 0, 0, 0, 0},
+/*11*/	{VENDOR_PRIM, "HFC-2S Primux Card", 4, 2, 0, 0, 0, 0, 0, 0},
 
-/*12*/	{VENDOR_BN, "HFC-8S Card", 8, 8, 1, 0, 0, 0, 0},
+/*12*/	{VENDOR_BN, "HFC-8S Card", 8, 8, 1, 0, 0, 0, 0, 0},
 /*13*/	{VENDOR_BN, "HFC-8S Card (+)", 8, 8, 1, 8, 0, DIP_8S,
-		HFC_IO_MODE_REGIO},
-/*14*/	{VENDOR_CCD, "HFC-8S Eval (old)", 8, 8, 0, 0, 0, 0, 0},
-/*15*/	{VENDOR_CCD, "HFC-8S IOB4ST Recording", 8, 8, 1, 0, 0, 0, 0},
+		HFC_IO_MODE_REGIO, 0},
+/*14*/	{VENDOR_CCD, "HFC-8S Eval (old)", 8, 8, 0, 0, 0, 0, 0, 0},
+/*15*/	{VENDOR_CCD, "HFC-8S IOB4ST Recording", 8, 8, 1, 0, 0, 0, 0, 0},
 
-/*16*/	{VENDOR_CCD, "HFC-8S IOB8ST", 8, 8, 1, 0, 0, 0, 0},
-/*17*/	{VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0},
-/*18*/	{VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0},
+/*16*/	{VENDOR_CCD, "HFC-8S IOB8ST", 8, 8, 1, 0, 0, 0, 0, 0},
+/*17*/	{VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0, 0},
+/*18*/	{VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0, 0},
 
-/*19*/	{VENDOR_BN, "HFC-E1 Card", 1, 1, 0, 1, 0, DIP_E1, 0},
-/*20*/	{VENDOR_BN, "HFC-E1 Card (mini PCI)", 1, 1, 0, 1, 0, 0, 0},
-/*21*/	{VENDOR_BN, "HFC-E1+ Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0},
-/*22*/	{VENDOR_BN, "HFC-E1 Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0},
+/*19*/	{VENDOR_BN, "HFC-E1 Card", 1, 1, 0, 1, 0, DIP_E1, 0, 0},
+/*20*/	{VENDOR_BN, "HFC-E1 Card (mini PCI)", 1, 1, 0, 1, 0, 0, 0, 0},
+/*21*/	{VENDOR_BN, "HFC-E1+ Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0, 0},
+/*22*/	{VENDOR_BN, "HFC-E1 Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0, 0},
 
-/*23*/	{VENDOR_CCD, "HFC-E1 Eval (old)", 1, 1, 0, 0, 0, 0, 0},
-/*24*/	{VENDOR_CCD, "HFC-E1 IOB1E1", 1, 1, 0, 1, 0, 0, 0},
-/*25*/	{VENDOR_CCD, "HFC-E1", 1, 1, 0, 1, 0, 0, 0},
+/*23*/	{VENDOR_CCD, "HFC-E1 Eval (old)", 1, 1, 0, 0, 0, 0, 0, 0},
+/*24*/	{VENDOR_CCD, "HFC-E1 IOB1E1", 1, 1, 0, 1, 0, 0, 0, 0},
+/*25*/	{VENDOR_CCD, "HFC-E1", 1, 1, 0, 1, 0, 0, 0, 0},
 
 /*26*/	{VENDOR_CCD, "HFC-4S Speech Design", 4, 4, 0, 0, 0, 0,
-		HFC_IO_MODE_PLXSD},
+		HFC_IO_MODE_PLXSD, 0},
 /*27*/	{VENDOR_CCD, "HFC-E1 Speech Design", 1, 1, 0, 0, 0, 0,
-		HFC_IO_MODE_PLXSD},
-/*28*/	{VENDOR_CCD, "HFC-4S OpenVox", 4, 4, 1, 0, 0, 0, 0},
-/*29*/	{VENDOR_CCD, "HFC-2S OpenVox", 4, 2, 1, 0, 0, 0, 0},
-/*30*/	{VENDOR_CCD, "HFC-8S OpenVox", 8, 8, 1, 0, 0, 0, 0},
+		HFC_IO_MODE_PLXSD, 0},
+/*28*/	{VENDOR_CCD, "HFC-4S OpenVox", 4, 4, 1, 0, 0, 0, 0, 0},
+/*29*/	{VENDOR_CCD, "HFC-2S OpenVox", 4, 2, 1, 0, 0, 0, 0, 0},
+/*30*/	{VENDOR_CCD, "HFC-8S OpenVox", 8, 8, 1, 0, 0, 0, 0, 0},
+/*31*/	{VENDOR_CCD, "XHFC-4S Speech Design", 5, 4, 0, 0, 0, 0,
+		HFC_IO_MODE_EMBSD, XHFC_IRQ},
+/*32*/	{VENDOR_JH, "HFC-8S (junghanns)", 8, 8, 1, 0, 0, 0, 0, 0},
 };
 
 #undef H
@@ -5178,6 +5332,8 @@
 		PCI_SUBDEVICE_ID_CCD_HFC8S, 0, 0, H(18)}, /* 8S */
 	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
 		PCI_SUBDEVICE_ID_CCD_OV8S, 0, 0, H(30)}, /* OpenVox 8 */
+	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
+		PCI_SUBDEVICE_ID_CCD_JH8S, 0, 0, H(32)}, /* Junganns 8S  */
 
 
 	/* Cards with HFC-E1 Chip */
@@ -5201,6 +5357,10 @@
 		PCI_SUBDEVICE_ID_CCD_SPD4S, 0, 0, H(26)}, /* PLX PCI Bridge */
 	{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_CCD,
 		PCI_SUBDEVICE_ID_CCD_SPDE1, 0, 0, H(27)}, /* PLX PCI Bridge */
+
+	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD,
+		PCI_SUBDEVICE_ID_CCD_JHSE1, 0, 0, H(25)}, /* Junghanns E1 */
+
 	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_ANY_ID, PCI_ANY_ID,
 		0, 0, 0},
 	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_ANY_ID, PCI_ANY_ID,
@@ -5231,7 +5391,7 @@
 		    "Please contact the driver maintainer for support.\n");
 		return -ENODEV;
 	}
-	ret = hfcmulti_init(pdev, ent);
+	ret = hfcmulti_init(m, pdev, ent);
 	if (ret)
 		return ret;
 	HFC_cnt++;
@@ -5261,6 +5421,8 @@
 HFCmulti_init(void)
 {
 	int err;
+	int i, xhfc = 0;
+	struct hm_map m;
 
 	printk(KERN_INFO "mISDN: HFC-multi driver %s\n", HFC_MULTI_VERSION);
 
@@ -5308,11 +5470,43 @@
 	if (!clock)
 		clock = 1;
 
+	/* Register the embedded devices.
+	 * This should be done before the PCI cards registration */
+	switch (hwid) {
+	case HWID_MINIP4:
+		xhfc = 1;
+		m = hfcm_map[31];
+		break;
+	case HWID_MINIP8:
+		xhfc = 2;
+		m = hfcm_map[31];
+		break;
+	case HWID_MINIP16:
+		xhfc = 4;
+		m = hfcm_map[31];
+		break;
+	default:
+		xhfc = 0;
+	}
+
+	for (i = 0; i < xhfc; ++i) {
+		err = hfcmulti_init(&m, NULL, NULL);
+		if (err) {
+			printk(KERN_ERR "error registering embedded driver: "
+				"%x\n", err);
+			return -err;
+		}
+		HFC_cnt++;
+		printk(KERN_INFO "%d devices registered\n", HFC_cnt);
+	}
+
+	/* Register the PCI cards */
 	err = pci_register_driver(&hfcmultipci_driver);
 	if (err < 0) {
 		printk(KERN_ERR "error registering pci driver: %x\n", err);
 		return err;
 	}
+
 	return 0;
 }
 
diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c
index 641a9cd..776afc8 100644
--- a/drivers/isdn/hardware/mISDN/hfcpci.c
+++ b/drivers/isdn/hardware/mISDN/hfcpci.c
@@ -257,7 +257,7 @@
 	Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
 
 	/* Clear already pending ints */
-	if (Read_hfc(hc, HFCPCI_INT_S1));
+	val = Read_hfc(hc, HFCPCI_INT_S1);
 
 	/* set NT/TE mode */
 	hfcpci_setmode(hc);
@@ -452,7 +452,7 @@
 		}
 		bz->za[new_f2].z2 = cpu_to_le16(new_z2);
 		bz->f2 = new_f2;	/* next buffer */
-		recv_Bchannel(bch);
+		recv_Bchannel(bch, MISDN_ID_ANY);
 	}
 }
 
@@ -499,7 +499,8 @@
 			df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) |
 			    (MAX_D_FRAMES + 1);	/* next buffer */
 			df->za[df->f2 & D_FREG_MASK].z2 =
-			    cpu_to_le16((le16_to_cpu(zp->z2) + rcnt) & (D_FIFO_SIZE - 1));
+			    cpu_to_le16((le16_to_cpu(zp->z2) + rcnt) &
+			    (D_FIFO_SIZE - 1));
 		} else {
 			dch->rx_skb = mI_alloc_skb(rcnt - 3, GFP_ATOMIC);
 			if (!dch->rx_skb) {
@@ -541,35 +542,45 @@
  * check for transparent receive data and read max one 'poll' size if avail
  */
 static void
-hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *bz, u_char *bdata)
+hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz,
+	struct bzfifo *txbz, u_char *bdata)
 {
-	 __le16 *z1r, *z2r;
-	int		new_z2, fcnt, maxlen;
-	u_char		*ptr, *ptr1;
+	 __le16	*z1r, *z2r, *z1t, *z2t;
+	int	new_z2, fcnt_rx, fcnt_tx, maxlen;
+	u_char	*ptr, *ptr1;
 
-	z1r = &bz->za[MAX_B_FRAMES].z1;		/* pointer to z reg */
+	z1r = &rxbz->za[MAX_B_FRAMES].z1;	/* pointer to z reg */
 	z2r = z1r + 1;
+	z1t = &txbz->za[MAX_B_FRAMES].z1;
+	z2t = z1t + 1;
 
-	fcnt = le16_to_cpu(*z1r) - le16_to_cpu(*z2r);
-	if (!fcnt)
+	fcnt_rx = le16_to_cpu(*z1r) - le16_to_cpu(*z2r);
+	if (!fcnt_rx)
 		return;	/* no data avail */
 
-	if (fcnt <= 0)
-		fcnt += B_FIFO_SIZE;	/* bytes actually buffered */
-	new_z2 = le16_to_cpu(*z2r) + fcnt;	/* new position in fifo */
+	if (fcnt_rx <= 0)
+		fcnt_rx += B_FIFO_SIZE;	/* bytes actually buffered */
+	new_z2 = le16_to_cpu(*z2r) + fcnt_rx;	/* new position in fifo */
 	if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
 		new_z2 -= B_FIFO_SIZE;	/* buffer wrap */
 
-	if (fcnt > MAX_DATA_SIZE) {	/* flush, if oversized */
+	if (fcnt_rx > MAX_DATA_SIZE) {	/* flush, if oversized */
 		*z2r = cpu_to_le16(new_z2);		/* new position */
 		return;
 	}
 
-	bch->rx_skb = mI_alloc_skb(fcnt, GFP_ATOMIC);
+	fcnt_tx = le16_to_cpu(*z2t) - le16_to_cpu(*z1t);
+	if (fcnt_tx <= 0)
+		fcnt_tx += B_FIFO_SIZE;
+		    /* fcnt_tx contains available bytes in tx-fifo */
+	fcnt_tx = B_FIFO_SIZE - fcnt_tx;
+		    /* remaining bytes to send (bytes in tx-fifo) */
+
+	bch->rx_skb = mI_alloc_skb(fcnt_rx, GFP_ATOMIC);
 	if (bch->rx_skb) {
-		ptr = skb_put(bch->rx_skb, fcnt);
-		if (le16_to_cpu(*z2r) + fcnt <= B_FIFO_SIZE + B_SUB_VAL)
-			maxlen = fcnt;	/* complete transfer */
+		ptr = skb_put(bch->rx_skb, fcnt_rx);
+		if (le16_to_cpu(*z2r) + fcnt_rx <= B_FIFO_SIZE + B_SUB_VAL)
+			maxlen = fcnt_rx;	/* complete transfer */
 		else
 			maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(*z2r);
 			    /* maximum */
@@ -577,14 +588,14 @@
 		ptr1 = bdata + (le16_to_cpu(*z2r) - B_SUB_VAL);
 		    /* start of data */
 		memcpy(ptr, ptr1, maxlen);	/* copy data */
-		fcnt -= maxlen;
+		fcnt_rx -= maxlen;
 
-		if (fcnt) {	/* rest remaining */
+		if (fcnt_rx) {	/* rest remaining */
 			ptr += maxlen;
 			ptr1 = bdata;	/* start of buffer */
-			memcpy(ptr, ptr1, fcnt);	/* rest */
+			memcpy(ptr, ptr1, fcnt_rx);	/* rest */
 		}
-		recv_Bchannel(bch);
+		recv_Bchannel(bch, fcnt_tx); /* bch, id */
 	} else
 		printk(KERN_WARNING "HFCPCI: receive out of memory\n");
 
@@ -600,26 +611,28 @@
 	struct hfc_pci	*hc = bch->hw;
 	int		rcnt, real_fifo;
 	int		receive = 0, count = 5;
-	struct bzfifo	*bz;
+	struct bzfifo	*txbz, *rxbz;
 	u_char		*bdata;
 	struct zt	*zp;
 
 	if ((bch->nr & 2) && (!hc->hw.bswapped)) {
-		bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2;
+		rxbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2;
+		txbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2;
 		bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b2;
 		real_fifo = 1;
 	} else {
-		bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1;
+		rxbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1;
+		txbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1;
 		bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b1;
 		real_fifo = 0;
 	}
 Begin:
 	count--;
-	if (bz->f1 != bz->f2) {
+	if (rxbz->f1 != rxbz->f2) {
 		if (bch->debug & DEBUG_HW_BCHANNEL)
 			printk(KERN_DEBUG "hfcpci rec ch(%x) f1(%d) f2(%d)\n",
-			    bch->nr, bz->f1, bz->f2);
-		zp = &bz->za[bz->f2];
+			    bch->nr, rxbz->f1, rxbz->f2);
+		zp = &rxbz->za[rxbz->f2];
 
 		rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2);
 		if (rcnt < 0)
@@ -630,8 +643,8 @@
 			    "hfcpci rec ch(%x) z1(%x) z2(%x) cnt(%d)\n",
 			    bch->nr, le16_to_cpu(zp->z1),
 			    le16_to_cpu(zp->z2), rcnt);
-		hfcpci_empty_bfifo(bch, bz, bdata, rcnt);
-		rcnt = bz->f1 - bz->f2;
+		hfcpci_empty_bfifo(bch, rxbz, bdata, rcnt);
+		rcnt = rxbz->f1 - rxbz->f2;
 		if (rcnt < 0)
 			rcnt += MAX_B_FRAMES + 1;
 		if (hc->hw.last_bfifo_cnt[real_fifo] > rcnt + 1) {
@@ -644,7 +657,7 @@
 		else
 			receive = 0;
 	} else if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
-		hfcpci_empty_fifo_trans(bch, bz, bdata);
+		hfcpci_empty_fifo_trans(bch, rxbz, txbz, bdata);
 		return;
 	} else
 		receive = 0;
@@ -954,6 +967,7 @@
 ph_state_nt(struct dchannel *dch)
 {
 	struct hfc_pci	*hc = dch->hw;
+	u_char	val;
 
 	if (dch->debug)
 		printk(KERN_DEBUG "%s: NT newstate %x\n",
@@ -967,7 +981,7 @@
 			hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
 			Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
 			/* Clear already pending ints */
-			if (Read_hfc(hc, HFCPCI_INT_S1));
+			val = Read_hfc(hc, HFCPCI_INT_S1);
 			Write_hfc(hc, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE);
 			udelay(10);
 			Write_hfc(hc, HFCPCI_STATES, 4);
@@ -1256,8 +1270,7 @@
 		rx_slot = (bc>>8) & 0xff;
 		tx_slot = (bc>>16) & 0xff;
 		bc = bc & 0xff;
-	} else if (test_bit(HFC_CFG_PCM, &hc->cfg) &&
-	    (protocol > ISDN_P_NONE))
+	} else if (test_bit(HFC_CFG_PCM, &hc->cfg) && (protocol > ISDN_P_NONE))
 		printk(KERN_WARNING "%s: no pcm channel id but HFC_CFG_PCM\n",
 		    __func__);
 	if (hc->chanlimit > 1) {
@@ -1315,8 +1328,8 @@
 	case (ISDN_P_B_RAW):
 		bch->state = protocol;
 		bch->nr = bc;
-		hfcpci_clear_fifo_rx(hc, (fifo2 & 2)?1:0);
-		hfcpci_clear_fifo_tx(hc, (fifo2 & 2)?1:0);
+		hfcpci_clear_fifo_rx(hc, (fifo2 & 2) ? 1 : 0);
+		hfcpci_clear_fifo_tx(hc, (fifo2 & 2) ? 1 : 0);
 		if (bc & 2) {
 			hc->hw.sctrl |= SCTRL_B2_ENA;
 			hc->hw.sctrl_r |= SCTRL_B2_ENA;
@@ -1350,8 +1363,8 @@
 	case (ISDN_P_B_HDLC):
 		bch->state = protocol;
 		bch->nr = bc;
-		hfcpci_clear_fifo_rx(hc, (fifo2 & 2)?1:0);
-		hfcpci_clear_fifo_tx(hc, (fifo2 & 2)?1:0);
+		hfcpci_clear_fifo_rx(hc, (fifo2 & 2) ? 1 : 0);
+		hfcpci_clear_fifo_tx(hc, (fifo2 & 2) ? 1 : 0);
 		if (bc & 2) {
 			hc->hw.sctrl |= SCTRL_B2_ENA;
 			hc->hw.sctrl_r |= SCTRL_B2_ENA;
@@ -1445,7 +1458,7 @@
 	switch (protocol) {
 	case (ISDN_P_B_RAW):
 		bch->state = protocol;
-		hfcpci_clear_fifo_rx(hc, (chan & 2)?1:0);
+		hfcpci_clear_fifo_rx(hc, (chan & 2) ? 1 : 0);
 		if (chan & 2) {
 			hc->hw.sctrl_r |= SCTRL_B2_ENA;
 			hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX;
@@ -1470,7 +1483,7 @@
 		break;
 	case (ISDN_P_B_HDLC):
 		bch->state = protocol;
-		hfcpci_clear_fifo_rx(hc, (chan & 2)?1:0);
+		hfcpci_clear_fifo_rx(hc, (chan & 2) ? 1 : 0);
 		if (chan & 2) {
 			hc->hw.sctrl_r |= SCTRL_B2_ENA;
 			hc->hw.last_bfifo_cnt[1] = 0;
@@ -2035,7 +2048,8 @@
 		printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
 		return 1;
 	}
-	hc->hw.pci_io = (char __iomem *)(unsigned long)hc->pdev->resource[1].start;
+	hc->hw.pci_io =
+		(char __iomem *)(unsigned long)hc->pdev->resource[1].start;
 
 	if (!hc->hw.pci_io) {
 		printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
@@ -2277,7 +2291,7 @@
 		release_card(card);
 	else
 		if (debug)
-			printk(KERN_WARNING "%s: drvdata already removed\n",
+			printk(KERN_DEBUG "%s: drvdata already removed\n",
 			    __func__);
 }
 
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
index 9c427fb..6b7704c 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -947,7 +947,7 @@
 				if (fifo->dch)
 					recv_Dchannel(fifo->dch);
 				if (fifo->bch)
-					recv_Bchannel(fifo->bch);
+					recv_Bchannel(fifo->bch, MISDN_ID_ANY);
 				if (fifo->ech)
 					recv_Echannel(fifo->ech,
 						     &hw->dch);
@@ -969,7 +969,7 @@
 	} else {
 		/* deliver transparent data to layer2 */
 		if (rx_skb->len >= poll)
-			recv_Bchannel(fifo->bch);
+			recv_Bchannel(fifo->bch, MISDN_ID_ANY);
 	}
 	spin_unlock(&hw->lock);
 }
diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c
index 9426c98..21d34be 100644
--- a/drivers/isdn/mISDN/core.c
+++ b/drivers/isdn/mISDN/core.c
@@ -214,7 +214,7 @@
 		if (!test_and_set_bit(i, (u_long *)&device_ids))
 			break;
 	if (i > MAX_DEVICE_ID)
-		return -1;
+		return -EBUSY;
 	return i;
 }
 
@@ -224,10 +224,10 @@
 {
 	int	err;
 
-	dev->id = get_free_devid();
-	err = -EBUSY;
-	if (dev->id < 0)
+	err = get_free_devid();
+	if (err < 0)
 		goto error1;
+	dev->id = err;
 
 	device_initialize(&dev->dev);
 	if (name && name[0])
diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h
index 98a33c5..18af868 100644
--- a/drivers/isdn/mISDN/dsp.h
+++ b/drivers/isdn/mISDN/dsp.h
@@ -112,9 +112,11 @@
 
 #define DSP_DTMF_NPOINTS 102
 
-#define ECHOCAN_BUFLEN (4*128)
+#define ECHOCAN_BUFF_SIZE 0x400 /* must be 2**n */
+#define ECHOCAN_BUFF_MASK 0x3ff /* -1 */
 
 struct dsp_dtmf {
+	int		enable; /* dtmf is enabled */
 	int		treshold; /* above this is dtmf (square of) */
 	int		software; /* dtmf uses software decoding */
 	int		hardware; /* dtmf uses hardware decoding */
@@ -123,7 +125,7 @@
 		/* buffers one full dtmf frame */
 	u8		lastwhat, lastdigit;
 	int		count;
-	u8		digits[16]; /* just the dtmf result */
+	u8		digits[16]; /* dtmf result */
 };
 
 
@@ -150,6 +152,15 @@
 	struct timer_list tl;
 };
 
+/***************
+ * echo stuff *
+ ***************/
+
+struct dsp_echo {
+	int		software; /* echo is generated by software */
+	int		hardware; /* echo is generated by hardware */
+};
+
 /*****************
  * general stuff *
  *****************/
@@ -160,7 +171,7 @@
 	struct mISDNchannel	*up;
 	unsigned char	name[64];
 	int		b_active;
-	int		echo; /* echo is enabled */
+	struct dsp_echo	echo;
 	int		rx_disabled; /* what the user wants */
 	int		rx_is_off; /* what the card is */
 	int		tx_mix;
@@ -261,5 +272,5 @@
 extern void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data,
 		int len);
 extern void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data,
-		int len);
+		int len, unsigned int txlen);
 
diff --git a/drivers/isdn/mISDN/dsp_audio.c b/drivers/isdn/mISDN/dsp_audio.c
index de3795e..9c7c645 100644
--- a/drivers/isdn/mISDN/dsp_audio.c
+++ b/drivers/isdn/mISDN/dsp_audio.c
@@ -210,9 +210,8 @@
 		j = 0;
 		for (k = 0; k < 256; k++) {
 			if (dsp_audio_alaw_to_s32[k]
-				< dsp_audio_alaw_to_s32[i]) {
-			j++;
-			}
+			    < dsp_audio_alaw_to_s32[i])
+				j++;
 		}
 		sorted_alaw[j] = i;
 	}
diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c
index 58c43e4..9c7c0d1 100644
--- a/drivers/isdn/mISDN/dsp_cmx.c
+++ b/drivers/isdn/mISDN/dsp_cmx.c
@@ -163,8 +163,9 @@
 
 	printk(KERN_DEBUG "-----Current DSP\n");
 	list_for_each_entry(odsp, &dsp_ilist, list) {
-		printk(KERN_DEBUG "* %s echo=%d txmix=%d",
-		    odsp->name, odsp->echo, odsp->tx_mix);
+		printk(KERN_DEBUG "* %s hardecho=%d softecho=%d txmix=%d",
+		    odsp->name, odsp->echo.hardware, odsp->echo.software,
+		    odsp->tx_mix);
 		if (odsp->conf)
 			printk(" (Conf %d)", odsp->conf->id);
 		if (dsp == odsp)
@@ -177,10 +178,12 @@
 		list_for_each_entry(member, &conf->mlist, list) {
 			printk(KERN_DEBUG
 			    "  - member = %s (slot_tx %d, bank_tx %d, "
-			    "slot_rx %d, bank_rx %d hfc_conf %d)%s\n",
+			    "slot_rx %d, bank_rx %d hfc_conf %d "
+			    "tx_data %d rx_is_off %d)%s\n",
 			    member->dsp->name, member->dsp->pcm_slot_tx,
 			    member->dsp->pcm_bank_tx, member->dsp->pcm_slot_rx,
 			    member->dsp->pcm_bank_rx, member->dsp->hfc_conf,
+			    member->dsp->tx_data, member->dsp->rx_is_off,
 			    (member->dsp == dsp) ? " *this*" : "");
 		}
 	}
@@ -235,7 +238,7 @@
 
 	member = kzalloc(sizeof(struct dsp_conf_member), GFP_ATOMIC);
 	if (!member) {
-		printk(KERN_ERR "kmalloc struct dsp_conf_member failed\n");
+		printk(KERN_ERR "kzalloc struct dsp_conf_member failed\n");
 		return -ENOMEM;
 	}
 	member->dsp = dsp;
@@ -314,7 +317,7 @@
 
 	conf = kzalloc(sizeof(struct dsp_conf), GFP_ATOMIC);
 	if (!conf) {
-		printk(KERN_ERR "kmalloc struct dsp_conf failed\n");
+		printk(KERN_ERR "kzalloc struct dsp_conf failed\n");
 		return NULL;
 	}
 	INIT_LIST_HEAD(&conf->mlist);
@@ -385,7 +388,7 @@
 	int		freeunits[8];
 	u_char		freeslots[256];
 	int		same_hfc = -1, same_pcm = -1, current_conf = -1,
-	    all_conf = 1;
+	    all_conf = 1, tx_data = 0;
 
 	/* dsp gets updated (no conf) */
 	if (!conf) {
@@ -409,7 +412,7 @@
 		/* process hw echo */
 		if (dsp->features.pcm_banks < 1)
 			return;
-		if (!dsp->echo) {
+		if (!dsp->echo.software && !dsp->echo.hardware) {
 			/* NO ECHO: remove PCM slot if assigned */
 			if (dsp->pcm_slot_tx >= 0 || dsp->pcm_slot_rx >= 0) {
 				if (dsp_debug & DEBUG_DSP_CMX)
@@ -427,10 +430,15 @@
 			}
 			return;
 		}
+		/* echo is enabled, find out if we use soft or hardware */
+		dsp->echo.software = dsp->tx_data;
+		dsp->echo.hardware = 0;
 		/* ECHO: already echo */
 		if (dsp->pcm_slot_tx >= 0 && dsp->pcm_slot_rx < 0 &&
-		    dsp->pcm_bank_tx == 2 && dsp->pcm_bank_rx == 2)
+		    dsp->pcm_bank_tx == 2 && dsp->pcm_bank_rx == 2) {
+			dsp->echo.hardware = 1;
 			return;
+		}
 		/* ECHO: if slot already assigned */
 		if (dsp->pcm_slot_tx >= 0) {
 			dsp->pcm_slot_rx = dsp->pcm_slot_tx;
@@ -443,6 +451,7 @@
 				    dsp->pcm_slot_tx);
 			dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN,
 			    dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2);
+			dsp->echo.hardware = 1;
 			return;
 		}
 		/* ECHO: find slot */
@@ -472,6 +481,7 @@
 				    "%s no slot available for echo\n",
 				    __func__);
 			/* no more slots available */
+			dsp->echo.software = 1;
 			return;
 		}
 		/* assign free slot */
@@ -485,6 +495,7 @@
 			    __func__, dsp->name, dsp->pcm_slot_tx);
 		dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN,
 		    dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2);
+		dsp->echo.hardware = 1;
 		return;
 	}
 
@@ -554,7 +565,7 @@
 			return;
 		}
 		/* check if member has echo turned on */
-		if (member->dsp->echo) {
+		if (member->dsp->echo.hardware || member->dsp->echo.software) {
 			if (dsp_debug & DEBUG_DSP_CMX)
 				printk(KERN_DEBUG
 				    "%s dsp %s cannot form a conf, because "
@@ -592,10 +603,9 @@
 		if (member->dsp->tx_data) {
 			if (dsp_debug & DEBUG_DSP_CMX)
 				printk(KERN_DEBUG
-				    "%s dsp %s cannot form a conf, because "
-				    "tx_data is turned on\n",
+				    "%s dsp %s tx_data is turned on\n",
 				    __func__, member->dsp->name);
-			goto conf_software;
+			tx_data = 1;
 		}
 		/* check if pipeline exists */
 		if (member->dsp->pipeline.inuse) {
@@ -794,7 +804,7 @@
 			    nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx,
 			    nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx);
 			conf->hardware = 1;
-			conf->software = 0;
+			conf->software = tx_data;
 			return;
 		/* if members have one bank (or on the same chip) */
 		} else {
@@ -904,7 +914,7 @@
 			    nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx,
 			    nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx);
 			conf->hardware = 1;
-			conf->software = 0;
+			conf->software = tx_data;
 			return;
 		}
 	}
@@ -937,6 +947,10 @@
 	if (current_conf >= 0) {
 join_members:
 		list_for_each_entry(member, &conf->mlist, list) {
+			/* if no conference engine on our chip, change to
+			 * software */
+			if (!member->dsp->features.hfc_conf)
+				goto conf_software;
 			/* in case of hdlc, change to software */
 			if (member->dsp->hdlc)
 				goto conf_software;
@@ -1295,17 +1309,25 @@
 	int r, rr, t, tt, o_r, o_rr;
 	int preload = 0;
 	struct mISDNhead *hh, *thh;
+	int tx_data_only = 0;
 
 	/* don't process if: */
 	if (!dsp->b_active) { /* if not active */
 		dsp->last_tx = 0;
 		return;
 	}
-	if (dsp->pcm_slot_tx >= 0 && /* connected to pcm slot */
+	if (((dsp->conf && dsp->conf->hardware) || /* hardware conf */
+	    dsp->echo.hardware) && /* OR hardware echo */
 	    dsp->tx_R == dsp->tx_W && /* AND no tx-data */
 	    !(dsp->tone.tone && dsp->tone.software)) { /* AND not soft tones */
-		dsp->last_tx = 0;
-		return;
+		if (!dsp->tx_data) { /* no tx_data for user space required */
+			dsp->last_tx = 0;
+			return;
+		}
+		if (dsp->conf && dsp->conf->software && dsp->conf->hardware)
+			tx_data_only = 1;
+		if (dsp->conf->software && dsp->echo.hardware)
+			tx_data_only = 1;
 	}
 
 #ifdef CMX_DEBUG
@@ -1367,7 +1389,8 @@
 		while (r != rr && t != tt) {
 #ifdef CMX_TX_DEBUG
 			if (strlen(debugbuf) < 48)
-			    sprintf(debugbuf+strlen(debugbuf), " %02x", p[t]);
+				sprintf(debugbuf+strlen(debugbuf), " %02x",
+				    p[t]);
 #endif
 			*d++ = p[t]; /* write tx_buff */
 			t = (t+1) & CMX_BUFF_MASK;
@@ -1388,7 +1411,7 @@
 	/* PROCESS DATA (one member / no conf) */
 	if (!conf || members <= 1) {
 		/* -> if echo is NOT enabled */
-		if (!dsp->echo) {
+		if (!dsp->echo.software) {
 			/* -> send tx-data if available or use 0-volume */
 			while (r != rr && t != tt) {
 				*d++ = p[t]; /* write tx_buff */
@@ -1438,7 +1461,7 @@
 		o_r = (o_rr - rr + r) & CMX_BUFF_MASK;
 			/* start rx-pointer at current read position*/
 		/* -> if echo is NOT enabled */
-		if (!dsp->echo) {
+		if (!dsp->echo.software) {
 			/*
 			 * -> copy other member's rx-data,
 			 * if tx-data is available, mix
@@ -1486,7 +1509,7 @@
 #endif
 	/* PROCESS DATA (three or more members) */
 	/* -> if echo is NOT enabled */
-	if (!dsp->echo) {
+	if (!dsp->echo.software) {
 		/*
 		 * -> substract rx-data from conf-data,
 		 * if tx-data is available, mix
@@ -1550,27 +1573,40 @@
 	 * becuase we want what we send, not what we filtered
 	 */
 	if (dsp->tx_data) {
-		/* PREPARE RESULT */
-		txskb = mI_alloc_skb(len, GFP_ATOMIC);
-		if (!txskb) {
-			printk(KERN_ERR
-			    "FATAL ERROR in mISDN_dsp.o: "
-			    "cannot alloc %d bytes\n", len);
+		if (tx_data_only) {
+			hh->prim = DL_DATA_REQ;
+			hh->id = 0;
+			/* queue and trigger */
+			skb_queue_tail(&dsp->sendq, nskb);
+			schedule_work(&dsp->workq);
+			/* exit because only tx_data is used */
+			return;
 		} else {
-			thh = mISDN_HEAD_P(txskb);
-			thh->prim = DL_DATA_REQ;
-			thh->id = 0;
-			memcpy(skb_put(txskb, len), nskb->data+preload, len);
-			/* queue (trigger later) */
-			skb_queue_tail(&dsp->sendq, txskb);
+			txskb = mI_alloc_skb(len, GFP_ATOMIC);
+			if (!txskb) {
+				printk(KERN_ERR
+				    "FATAL ERROR in mISDN_dsp.o: "
+				    "cannot alloc %d bytes\n", len);
+			} else {
+				thh = mISDN_HEAD_P(txskb);
+				thh->prim = DL_DATA_REQ;
+				thh->id = 0;
+				memcpy(skb_put(txskb, len), nskb->data+preload,
+					len);
+				/* queue (trigger later) */
+				skb_queue_tail(&dsp->sendq, txskb);
+			}
 		}
 	}
+
+	/* send data only to card, if we don't just calculated tx_data */
 	/* adjust volume */
 	if (dsp->tx_volume)
 		dsp_change_volume(nskb, dsp->tx_volume);
 	/* pipeline */
 	if (dsp->pipeline.inuse)
-		dsp_pipeline_process_tx(&dsp->pipeline, nskb->data, nskb->len);
+		dsp_pipeline_process_tx(&dsp->pipeline, nskb->data,
+			nskb->len);
 	/* crypt */
 	if (dsp->bf_enable)
 		dsp_bf_encrypt(dsp, nskb->data, nskb->len);
@@ -1592,7 +1628,8 @@
 	struct dsp_conf_member *member;
 	struct dsp *dsp;
 	int mustmix, members;
-	s32 mixbuffer[MAX_POLL+100], *c;
+	static s32 mixbuffer[MAX_POLL+100];
+	s32 *c;
 	u8 *p, *q;
 	int r, rr;
 	int jittercheck = 0, delay, i;
@@ -1890,10 +1927,8 @@
 
 	/* no conf */
 	if (!dsp->conf) {
-		/* in case of hardware (echo) */
-		if (dsp->pcm_slot_tx >= 0)
-			return;
-		if (dsp->echo) {
+		/* in case of software echo */
+		if (dsp->echo.software) {
 			nskb = skb_clone(skb, GFP_ATOMIC);
 			if (nskb) {
 				hh = mISDN_HEAD_P(nskb);
@@ -1909,7 +1944,7 @@
 	if (dsp->conf->hardware)
 		return;
 	list_for_each_entry(member, &dsp->conf->mlist, list) {
-		if (dsp->echo || member->dsp != dsp) {
+		if (dsp->echo.software || member->dsp != dsp) {
 			nskb = skb_clone(skb, GFP_ATOMIC);
 			if (nskb) {
 				hh = mISDN_HEAD_P(nskb);
diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c
index 3083338..c12cd2f 100644
--- a/drivers/isdn/mISDN/dsp_core.c
+++ b/drivers/isdn/mISDN/dsp_core.c
@@ -203,13 +203,13 @@
 	else if (dsp->dtmf.software)
 		rx_off = 0;
 	/* echo in software */
-	else if (dsp->echo && dsp->pcm_slot_tx < 0)
+	else if (dsp->echo.software)
 		rx_off = 0;
 	/* bridge in software */
-	else if (dsp->conf) {
-		if (dsp->conf->software)
-			rx_off = 0;
-	}
+	else if (dsp->conf && dsp->conf->software)
+		rx_off = 0;
+	/* data is not required by user space and not required
+	 * for echo dtmf detection, soft-echo, soft-bridging */
 
 	if (rx_off == dsp->rx_is_off)
 		return;
@@ -280,7 +280,7 @@
 static int
 dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb)
 {
-	struct		sk_buff *nskb;
+	struct sk_buff	*nskb;
 	int ret = 0;
 	int cont;
 	u8 *data;
@@ -306,15 +306,18 @@
 					"to %d\n", *((int *)data));
 			dsp->dtmf.treshold = (*(int *)data) * 10000;
 		}
+		dsp->dtmf.enable = 1;
 		/* init goertzel */
 		dsp_dtmf_goertzel_init(dsp);
 
 		/* check dtmf hardware */
 		dsp_dtmf_hardware(dsp);
+		dsp_rx_off(dsp);
 		break;
 	case DTMF_TONE_STOP: /* turn off DTMF */
 		if (dsp_debug & DEBUG_DSP_CORE)
 			printk(KERN_DEBUG "%s: stop dtmf\n", __func__);
+		dsp->dtmf.enable = 0;
 		dsp->dtmf.hardware = 0;
 		dsp->dtmf.software = 0;
 		break;
@@ -414,7 +417,7 @@
 		dsp_rx_off(dsp);
 		break;
 	case DSP_ECHO_ON: /* enable echo */
-		dsp->echo = 1; /* soft echo */
+		dsp->echo.software = 1; /* soft echo */
 		if (dsp_debug & DEBUG_DSP_CORE)
 			printk(KERN_DEBUG "%s: enable cmx-echo\n", __func__);
 		dsp_cmx_hardware(dsp->conf, dsp);
@@ -423,7 +426,8 @@
 			dsp_cmx_debug(dsp);
 		break;
 	case DSP_ECHO_OFF: /* disable echo */
-		dsp->echo = 0;
+		dsp->echo.software = 0;
+		dsp->echo.hardware = 0;
 		if (dsp_debug & DEBUG_DSP_CORE)
 			printk(KERN_DEBUG "%s: disable cmx-echo\n", __func__);
 		dsp_cmx_hardware(dsp->conf, dsp);
@@ -556,7 +560,7 @@
 			dsp->pipeline.inuse = 1;
 			dsp_cmx_hardware(dsp->conf, dsp);
 			ret = dsp_pipeline_build(&dsp->pipeline,
-				len > 0 ? (char *)data : NULL);
+				len > 0 ? data : NULL);
 			dsp_cmx_hardware(dsp->conf, dsp);
 			dsp_rx_off(dsp);
 		}
@@ -657,11 +661,10 @@
 static int
 dsp_function(struct mISDNchannel *ch,  struct sk_buff *skb)
 {
-	struct dsp			*dsp = container_of(ch, struct dsp, ch);
+	struct dsp		*dsp = container_of(ch, struct dsp, ch);
 	struct mISDNhead	*hh;
 	int			ret = 0;
-	u8			*digits;
-	int			cont;
+	u8			*digits = NULL;
 	u_long			flags;
 
 	hh = mISDN_HEAD_P(skb);
@@ -704,50 +707,55 @@
 			break;
 		}
 
+		spin_lock_irqsave(&dsp_lock, flags);
+
 		/* decrypt if enabled */
 		if (dsp->bf_enable)
 			dsp_bf_decrypt(dsp, skb->data, skb->len);
 		/* pipeline */
 		if (dsp->pipeline.inuse)
 			dsp_pipeline_process_rx(&dsp->pipeline, skb->data,
-				skb->len);
+				skb->len, hh->id);
 		/* change volume if requested */
 		if (dsp->rx_volume)
 			dsp_change_volume(skb, dsp->rx_volume);
-
 		/* check if dtmf soft decoding is turned on */
 		if (dsp->dtmf.software) {
 			digits = dsp_dtmf_goertzel_decode(dsp, skb->data,
-				skb->len, (dsp_options&DSP_OPT_ULAW)?1:0);
+				skb->len, (dsp_options&DSP_OPT_ULAW) ? 1 : 0);
+		}
+		/* we need to process receive data if software */
+		if (dsp->conf && dsp->conf->software) {
+			/* process data from card at cmx */
+			dsp_cmx_receive(dsp, skb);
+		}
+
+		spin_unlock_irqrestore(&dsp_lock, flags);
+
+		/* send dtmf result, if any */
+		if (digits) {
 			while (*digits) {
+				int k;
 				struct sk_buff *nskb;
 				if (dsp_debug & DEBUG_DSP_DTMF)
 					printk(KERN_DEBUG "%s: digit"
 					    "(%c) to layer %s\n",
 					    __func__, *digits, dsp->name);
-				cont = DTMF_TONE_VAL | *digits;
+				k = *digits | DTMF_TONE_VAL;
 				nskb = _alloc_mISDN_skb(PH_CONTROL_IND,
-				    MISDN_ID_ANY, sizeof(int), &cont,
-				    GFP_ATOMIC);
+					MISDN_ID_ANY, sizeof(int), &k,
+					GFP_ATOMIC);
 				if (nskb) {
 					if (dsp->up) {
 						if (dsp->up->send(
 						    dsp->up, nskb))
-						dev_kfree_skb(nskb);
+							dev_kfree_skb(nskb);
 					} else
 						dev_kfree_skb(nskb);
 				}
 				digits++;
 			}
 		}
-		/* we need to process receive data if software */
-		spin_lock_irqsave(&dsp_lock, flags);
-		if (dsp->pcm_slot_tx < 0 && dsp->pcm_slot_rx < 0) {
-			/* process data from card at cmx */
-			dsp_cmx_receive(dsp, skb);
-		}
-		spin_unlock_irqrestore(&dsp_lock, flags);
-
 		if (dsp->rx_disabled) {
 			/* if receive is not allowed */
 			break;
@@ -787,7 +795,7 @@
 					if (dsp->up) {
 						if (dsp->up->send(
 						    dsp->up, nskb))
-						dev_kfree_skb(nskb);
+							dev_kfree_skb(nskb);
 					} else
 						dev_kfree_skb(nskb);
 				}
@@ -946,7 +954,7 @@
 	int		err = 0;
 
 	if (debug & DEBUG_DSP_CTRL)
-	printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd);
+		printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd);
 
 	switch (cmd) {
 	case OPEN_CHANNEL:
@@ -1169,9 +1177,9 @@
 
 	/* init conversion tables */
 	dsp_audio_generate_law_tables();
-	dsp_silence = (dsp_options&DSP_OPT_ULAW)?0xff:0x2a;
-	dsp_audio_law_to_s32 = (dsp_options&DSP_OPT_ULAW)?dsp_audio_ulaw_to_s32:
-		dsp_audio_alaw_to_s32;
+	dsp_silence = (dsp_options&DSP_OPT_ULAW) ? 0xff : 0x2a;
+	dsp_audio_law_to_s32 = (dsp_options&DSP_OPT_ULAW) ?
+		dsp_audio_ulaw_to_s32 : dsp_audio_alaw_to_s32;
 	dsp_audio_generate_s2law_table();
 	dsp_audio_generate_seven();
 	dsp_audio_generate_mix_table();
diff --git a/drivers/isdn/mISDN/dsp_dtmf.c b/drivers/isdn/mISDN/dsp_dtmf.c
index efc371c..9ae2d33 100644
--- a/drivers/isdn/mISDN/dsp_dtmf.c
+++ b/drivers/isdn/mISDN/dsp_dtmf.c
@@ -51,6 +51,9 @@
 {
 	int hardware = 1;
 
+	if (!dsp->dtmf.enable)
+		return;
+
 	if (!dsp->features.hfc_dtmf)
 		hardware = 0;
 
diff --git a/drivers/isdn/mISDN/dsp_ecdis.h b/drivers/isdn/mISDN/dsp_ecdis.h
index 8a20af4..21dbd15 100644
--- a/drivers/isdn/mISDN/dsp_ecdis.h
+++ b/drivers/isdn/mISDN/dsp_ecdis.h
@@ -91,7 +91,7 @@
 					&& det->tone_cycle_duration <= 475*8) {
 					det->good_cycles++;
 					if (det->good_cycles > 2)
-					det->hit = TRUE;
+						det->hit = TRUE;
 				}
 				det->tone_cycle_duration = 0;
 			}
diff --git a/drivers/isdn/mISDN/dsp_pipeline.c b/drivers/isdn/mISDN/dsp_pipeline.c
index 18cf87c..ac61f19 100644
--- a/drivers/isdn/mISDN/dsp_pipeline.c
+++ b/drivers/isdn/mISDN/dsp_pipeline.c
@@ -347,7 +347,8 @@
 			entry->elem->process_tx(entry->p, data, len);
 }
 
-void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len)
+void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len,
+	unsigned int txlen)
 {
 	struct dsp_pipeline_entry *entry;
 
@@ -356,7 +357,7 @@
 
 	list_for_each_entry_reverse(entry, &pipeline->list, list)
 		if (entry->elem->process_rx)
-			entry->elem->process_rx(entry->p, data, len);
+			entry->elem->process_rx(entry->p, data, len, txlen);
 }
 
 
diff --git a/drivers/isdn/mISDN/dsp_tones.c b/drivers/isdn/mISDN/dsp_tones.c
index 7a9af66..1debf53 100644
--- a/drivers/isdn/mISDN/dsp_tones.c
+++ b/drivers/isdn/mISDN/dsp_tones.c
@@ -253,18 +253,24 @@
 	{8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
 
 	{TONE_GERMAN_DIALPBX,
-	{DATA_GA, DATA_S, DATA_GA, DATA_S, DATA_GA, DATA_S, NULL, NULL, NULL, NULL},
-	{SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL},
+	{DATA_GA, DATA_S, DATA_GA, DATA_S, DATA_GA, DATA_S, NULL, NULL, NULL,
+		NULL},
+	{SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, NULL, NULL, NULL,
+		NULL},
 	{2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} },
 
 	{TONE_GERMAN_OLDDIALPBX,
-	{DATA_GO, DATA_S, DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, NULL},
-	{SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL},
+	{DATA_GO, DATA_S, DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL,
+		NULL},
+	{SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL,
+		NULL},
 	{2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} },
 
 	{TONE_AMERICAN_DIALPBX,
-	{DATA_DT, DATA_S, DATA_DT, DATA_S, DATA_DT, DATA_S, NULL, NULL, NULL, NULL},
-	{SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, NULL, NULL, NULL, NULL},
+	{DATA_DT, DATA_S, DATA_DT, DATA_S, DATA_DT, DATA_S, NULL, NULL, NULL,
+		NULL},
+	{SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, NULL, NULL, NULL,
+		NULL},
 	{2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} },
 
 	{TONE_GERMAN_RINGING,
@@ -434,7 +440,7 @@
 
 	/* unlocking is not required, because we don't expect a response */
 	nskb = _alloc_mISDN_skb(PH_CONTROL_REQ,
-		(len)?HFC_SPL_LOOP_ON:HFC_SPL_LOOP_OFF, len, sample,
+		(len) ? HFC_SPL_LOOP_ON : HFC_SPL_LOOP_OFF, len, sample,
 		GFP_ATOMIC);
 	if (nskb) {
 		if (dsp->ch.peer) {
@@ -498,8 +504,7 @@
 
 	/* we turn off the tone */
 	if (!tone) {
-		if (dsp->features.hfc_loops)
-		if (timer_pending(&tonet->tl))
+		if (dsp->features.hfc_loops && timer_pending(&tonet->tl))
 			del_timer(&tonet->tl);
 		if (dsp->features.hfc_loops)
 			dsp_tone_hw_message(dsp, NULL, 0);
diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c
index ab1168a..0481a0c 100644
--- a/drivers/isdn/mISDN/hwchannel.c
+++ b/drivers/isdn/mISDN/hwchannel.c
@@ -185,13 +185,13 @@
 EXPORT_SYMBOL(recv_Echannel);
 
 void
-recv_Bchannel(struct bchannel *bch)
+recv_Bchannel(struct bchannel *bch, unsigned int id)
 {
 	struct mISDNhead *hh;
 
 	hh = mISDN_HEAD_P(bch->rx_skb);
 	hh->prim = PH_DATA_IND;
-	hh->id = MISDN_ID_ANY;
+	hh->id = id;
 	if (bch->rcount >= 64) {
 		printk(KERN_WARNING "B-channel %p receive queue overflow, "
 			"fushing!\n", bch);
diff --git a/drivers/isdn/mISDN/l1oip.h b/drivers/isdn/mISDN/l1oip.h
index a23d575..bc26c89 100644
--- a/drivers/isdn/mISDN/l1oip.h
+++ b/drivers/isdn/mISDN/l1oip.h
@@ -76,7 +76,7 @@
 	struct sockaddr_in	sin_local;	/* local socket name */
 	struct sockaddr_in	sin_remote;	/* remote socket name */
 	struct msghdr		sendmsg;	/* ip message to send */
-	struct iovec		sendiov;	/* iov for message */
+	struct kvec		sendiov;	/* iov for message */
 
 	/* frame */
 	struct l1oip_chan	chan[128];	/* channel instances */
diff --git a/drivers/isdn/mISDN/l1oip_codec.c b/drivers/isdn/mISDN/l1oip_codec.c
index e4ecba3..bbfd1b8 100644
--- a/drivers/isdn/mISDN/l1oip_codec.c
+++ b/drivers/isdn/mISDN/l1oip_codec.c
@@ -48,6 +48,7 @@
 
 #include <linux/vmalloc.h>
 #include <linux/mISDNif.h>
+#include <linux/in.h>
 #include "core.h"
 #include "l1oip.h"
 
diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c
index abe5749..990e6a7 100644
--- a/drivers/isdn/mISDN/l1oip_core.c
+++ b/drivers/isdn/mISDN/l1oip_core.c
@@ -279,7 +279,6 @@
 	int multi = 0;
 	u8 frame[len+32];
 	struct socket *socket = NULL;
-	mm_segment_t oldfs;
 
 	if (debug & DEBUG_L1OIP_MSG)
 		printk(KERN_DEBUG "%s: sending data to socket (len = %d)\n",
@@ -308,8 +307,8 @@
 
 	/* assemble frame */
 	*p++ = (L1OIP_VERSION<<6) /* version and coding */
-	     | (hc->pri?0x20:0x00) /* type */
-	     | (hc->id?0x10:0x00) /* id */
+	     | (hc->pri ? 0x20 : 0x00) /* type */
+	     | (hc->id ? 0x10 : 0x00) /* id */
 	     | localcodec;
 	if (hc->id) {
 		*p++ = hc->id>>24; /* id */
@@ -317,7 +316,7 @@
 		*p++ = hc->id>>8;
 		*p++ = hc->id;
 	}
-	*p++ = (multi == 1)?0x80:0x00 + channel; /* m-flag, channel */
+	*p++ = (multi == 1) ? 0x80 : 0x00 + channel; /* m-flag, channel */
 	if (multi == 1)
 		*p++ = len; /* length */
 	*p++ = timebase>>8; /* time base */
@@ -352,10 +351,7 @@
 			"= %d)\n", __func__, len);
 	hc->sendiov.iov_base = frame;
 	hc->sendiov.iov_len  = len;
-	oldfs = get_fs();
-	set_fs(KERNEL_DS);
-	len = sock_sendmsg(socket, &hc->sendmsg, len);
-	set_fs(oldfs);
+	len = kernel_sendmsg(socket, &hc->sendmsg, &hc->sendiov, 1, len);
 	/* give socket back */
 	hc->socket = socket; /* no locking required */
 
@@ -401,12 +397,12 @@
 	}
 
 	/* prepare message */
-	nskb = mI_alloc_skb((remotecodec == 3)?(len<<1):len, GFP_ATOMIC);
+	nskb = mI_alloc_skb((remotecodec == 3) ? (len<<1) : len, GFP_ATOMIC);
 	if (!nskb) {
 		printk(KERN_ERR "%s: No mem for skb.\n", __func__);
 		return;
 	}
-	p = skb_put(nskb, (remotecodec == 3)?(len<<1):len);
+	p = skb_put(nskb, (remotecodec == 3) ? (len<<1) : len);
 
 	if (remotecodec == 1 && ulaw)
 		l1oip_alaw_to_ulaw(buf, len, p);
@@ -458,7 +454,7 @@
 		hc->chan[channel].disorder_flag ^= 1;
 		if (nskb)
 #endif
-		queue_ch_frame(&bch->ch, PH_DATA_IND, rx_counter, nskb);
+			queue_ch_frame(&bch->ch, PH_DATA_IND, rx_counter, nskb);
 	}
 }
 
@@ -660,21 +656,29 @@
 	struct l1oip *hc = (struct l1oip *)data;
 	int ret = 0;
 	struct msghdr msg;
-	struct iovec iov;
-	mm_segment_t oldfs;
 	struct sockaddr_in sin_rx;
-	unsigned char recvbuf[1500];
+	unsigned char *recvbuf;
+	size_t recvbuf_size = 1500;
 	int recvlen;
 	struct socket *socket = NULL;
 	DECLARE_COMPLETION(wait);
 
+	/* allocate buffer memory */
+	recvbuf = kmalloc(recvbuf_size, GFP_KERNEL);
+	if (!recvbuf) {
+		printk(KERN_ERR "%s: Failed to alloc recvbuf.\n", __func__);
+		ret = -ENOMEM;
+		goto fail;
+	}
+
 	/* make daemon */
 	allow_signal(SIGTERM);
 
 	/* create socket */
 	if (sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &socket)) {
 		printk(KERN_ERR "%s: Failed to create socket.\n", __func__);
-		return -EIO;
+		ret = -EIO;
+		goto fail;
 	}
 
 	/* set incoming address */
@@ -708,16 +712,12 @@
 	msg.msg_namelen = sizeof(sin_rx);
 	msg.msg_control = NULL;
 	msg.msg_controllen = 0;
-	msg.msg_iov = &iov;
-	msg.msg_iovlen = 1;
 
 	/* build send message */
 	hc->sendmsg.msg_name = &hc->sin_remote;
 	hc->sendmsg.msg_namelen = sizeof(hc->sin_remote);
 	hc->sendmsg.msg_control = NULL;
 	hc->sendmsg.msg_controllen = 0;
-	hc->sendmsg.msg_iov    = &hc->sendiov;
-	hc->sendmsg.msg_iovlen = 1;
 
 	/* give away socket */
 	spin_lock(&hc->socket_lock);
@@ -729,18 +729,18 @@
 		printk(KERN_DEBUG "%s: socket created and open\n",
 			__func__);
 	while (!signal_pending(current)) {
-		iov.iov_base = recvbuf;
-		iov.iov_len = sizeof(recvbuf);
-		oldfs = get_fs();
-		set_fs(KERNEL_DS);
-		recvlen = sock_recvmsg(socket, &msg, sizeof(recvbuf), 0);
-		set_fs(oldfs);
+		struct kvec iov = {
+			.iov_base = recvbuf,
+			.iov_len = sizeof(recvbuf),
+		};
+		recvlen = kernel_recvmsg(socket, &msg, &iov, 1,
+					 sizeof(recvbuf), 0);
 		if (recvlen > 0) {
 			l1oip_socket_parse(hc, &sin_rx, recvbuf, recvlen);
 		} else {
 			if (debug & DEBUG_L1OIP_SOCKET)
-			    printk(KERN_WARNING "%s: broken pipe on socket\n",
-				__func__);
+				printk(KERN_WARNING
+				    "%s: broken pipe on socket\n", __func__);
 		}
 	}
 
@@ -760,6 +760,9 @@
 			__func__);
 
 fail:
+	/* free recvbuf */
+	kfree(recvbuf);
+
 	/* close socket */
 	if (socket)
 		sock_release(socket);
@@ -912,7 +915,7 @@
 		p = skb->data;
 		l = skb->len;
 		while (l) {
-			ll = (l < L1OIP_MAX_PERFRAME)?l:L1OIP_MAX_PERFRAME;
+			ll = (l < L1OIP_MAX_PERFRAME) ? l : L1OIP_MAX_PERFRAME;
 			l1oip_socket_send(hc, 0, dch->slot, 0,
 				hc->chan[dch->slot].tx_counter++, p, ll);
 			p += ll;
@@ -1160,7 +1163,7 @@
 		p = skb->data;
 		l = skb->len;
 		while (l) {
-			ll = (l < L1OIP_MAX_PERFRAME)?l:L1OIP_MAX_PERFRAME;
+			ll = (l < L1OIP_MAX_PERFRAME) ? l : L1OIP_MAX_PERFRAME;
 			l1oip_socket_send(hc, hc->codec, bch->slot, 0,
 				hc->chan[bch->slot].tx_counter, p, ll);
 			hc->chan[bch->slot].tx_counter += ll;
@@ -1318,8 +1321,8 @@
 	spin_lock_init(&hc->socket_lock);
 	hc->idx = l1oip_cnt;
 	hc->pri = pri;
-	hc->d_idx = pri?16:3;
-	hc->b_num = pri?30:2;
+	hc->d_idx = pri ? 16 : 3;
+	hc->b_num = pri ? 30 : 2;
 	hc->bundle = bundle;
 	if (hc->pri)
 		sprintf(hc->name, "l1oip-e1.%d", l1oip_cnt + 1);
@@ -1504,9 +1507,9 @@
 
 		if (debug & DEBUG_L1OIP_INIT)
 			printk(KERN_DEBUG "%s: interface %d is %s with %s.\n",
-				__func__, l1oip_cnt, pri?"PRI":"BRI",
-				bundle?"bundled IP packet for all B-channels"
-				 :"seperate IP packets for every B-channel");
+			    __func__, l1oip_cnt, pri ? "PRI" : "BRI",
+			    bundle ? "bundled IP packet for all B-channels" :
+			    "seperate IP packets for every B-channel");
 
 		hc = kzalloc(sizeof(struct l1oip), GFP_ATOMIC);
 		if (!hc) {
diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c
index d6e2863..9c2589e 100644
--- a/drivers/isdn/mISDN/layer2.c
+++ b/drivers/isdn/mISDN/layer2.c
@@ -99,7 +99,7 @@
 	if (!(*debug & DEBUG_L2_FSM))
 		return;
 	va_start(va, fmt);
-	printk(KERN_DEBUG "l2 (tei %d): ", l2->tei);
+	printk(KERN_DEBUG "l2 (sapi %d tei %d): ", l2->sapi, l2->tei);
 	vprintk(fmt, va);
 	printk("\n");
 	va_end(va);
@@ -1859,20 +1859,18 @@
 		psapi >>= 2;
 		ptei >>= 1;
 		if (psapi != l2->sapi) {
-			/* not our bussiness
-			 * printk(KERN_DEBUG "%s: sapi %d/%d sapi mismatch\n",
-			 *  __func__,
-			 *	psapi, l2->sapi);
-			 */
+			/* not our bussiness */
+			if (*debug & DEBUG_L2)
+				printk(KERN_DEBUG "%s: sapi %d/%d mismatch\n",
+					__func__, psapi, l2->sapi);
 			dev_kfree_skb(skb);
 			return 0;
 		}
 		if ((ptei != l2->tei) && (ptei != GROUP_TEI)) {
-			/* not our bussiness
-			 * printk(KERN_DEBUG "%s: tei %d/%d sapi %d mismatch\n",
-			 *  __func__,
-			 *	ptei, l2->tei, psapi);
-			 */
+			/* not our bussiness */
+			if (*debug & DEBUG_L2)
+				printk(KERN_DEBUG "%s: tei %d/%d mismatch\n",
+					__func__, ptei, l2->tei);
 			dev_kfree_skb(skb);
 			return 0;
 		}
@@ -1927,8 +1925,8 @@
 	int 			ret = -EINVAL;
 
 	if (*debug & DEBUG_L2_RECV)
-		printk(KERN_DEBUG "%s: prim(%x) id(%x) tei(%d)\n",
-		    __func__, hh->prim, hh->id, l2->tei);
+		printk(KERN_DEBUG "%s: prim(%x) id(%x) sapi(%d) tei(%d)\n",
+		    __func__, hh->prim, hh->id, l2->sapi, l2->tei);
 	switch (hh->prim) {
 	case PH_DATA_IND:
 		ret = ph_data_indication(l2, hh, skb);
@@ -2068,7 +2066,8 @@
 }
 
 struct layer2 *
-create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, u_long arg)
+create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, int tei,
+		int sapi)
 {
 	struct layer2		*l2;
 	struct channel_req	rq;
@@ -2089,7 +2088,7 @@
 		test_and_set_bit(FLG_LAPD, &l2->flag);
 		test_and_set_bit(FLG_LAPD_NET, &l2->flag);
 		test_and_set_bit(FLG_MOD128, &l2->flag);
-		l2->sapi = 0;
+		l2->sapi = sapi;
 		l2->maxlen = MAX_DFRAME_LEN;
 		if (test_bit(OPTION_L2_PMX, &options))
 			l2->window = 7;
@@ -2099,7 +2098,7 @@
 			test_and_set_bit(FLG_PTP, &l2->flag);
 		if (test_bit(OPTION_L2_FIXEDTEI, &options))
 			test_and_set_bit(FLG_FIXED_TEI, &l2->flag);
-		l2->tei = (u_int)arg;
+		l2->tei = tei;
 		l2->T200 = 1000;
 		l2->N200 = 3;
 		l2->T203 = 10000;
@@ -2114,7 +2113,7 @@
 		test_and_set_bit(FLG_LAPD, &l2->flag);
 		test_and_set_bit(FLG_MOD128, &l2->flag);
 		test_and_set_bit(FLG_ORIG, &l2->flag);
-		l2->sapi = 0;
+		l2->sapi = sapi;
 		l2->maxlen = MAX_DFRAME_LEN;
 		if (test_bit(OPTION_L2_PMX, &options))
 			l2->window = 7;
@@ -2124,7 +2123,7 @@
 			test_and_set_bit(FLG_PTP, &l2->flag);
 		if (test_bit(OPTION_L2_FIXEDTEI, &options))
 			test_and_set_bit(FLG_FIXED_TEI, &l2->flag);
-		l2->tei = (u_int)arg;
+		l2->tei = tei;
 		l2->T200 = 1000;
 		l2->N200 = 3;
 		l2->T203 = 10000;
@@ -2180,7 +2179,7 @@
 
 	if (crq->protocol != ISDN_P_B_X75SLP)
 		return -EPROTONOSUPPORT;
-	l2 = create_l2(crq->ch, crq->protocol, 0, 0);
+	l2 = create_l2(crq->ch, crq->protocol, 0, 0, 0);
 	if (!l2)
 		return -ENOMEM;
 	crq->ch = &l2->ch;
diff --git a/drivers/isdn/mISDN/layer2.h b/drivers/isdn/mISDN/layer2.h
index 6293f80..9547fb3 100644
--- a/drivers/isdn/mISDN/layer2.h
+++ b/drivers/isdn/mISDN/layer2.h
@@ -90,7 +90,7 @@
 #define L2_STATE_COUNT (ST_L2_8+1)
 
 extern struct layer2	*create_l2(struct mISDNchannel *, u_int,
-				u_long, u_long);
+				u_long, int, int);
 extern int		tei_l2(struct layer2 *, u_int, u_long arg);
 
 
diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c
index 508945d..c36f521 100644
--- a/drivers/isdn/mISDN/socket.c
+++ b/drivers/isdn/mISDN/socket.c
@@ -209,7 +209,7 @@
 
 	if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
 		err = -EFAULT;
-		goto drop;
+		goto done;
 	}
 
 	memcpy(mISDN_HEAD_P(skb), skb->data, MISDN_HEADER_LEN);
@@ -222,7 +222,7 @@
 	} else { /* use default for L2 messages */
 		if ((sk->sk_protocol == ISDN_P_LAPD_TE) ||
 		    (sk->sk_protocol == ISDN_P_LAPD_NT))
-		    mISDN_HEAD_ID(skb) = _pms(sk)->ch.nr;
+			mISDN_HEAD_ID(skb) = _pms(sk)->ch.nr;
 	}
 
 	if (*debug & DEBUG_SOCKET)
@@ -230,19 +230,21 @@
 		     __func__, mISDN_HEAD_ID(skb));
 
 	err = -ENODEV;
-	if (!_pms(sk)->ch.peer ||
-	    (err = _pms(sk)->ch.recv(_pms(sk)->ch.peer, skb)))
-		goto drop;
-
-	err = len;
+	if (!_pms(sk)->ch.peer)
+		goto done;
+	err = _pms(sk)->ch.recv(_pms(sk)->ch.peer, skb);
+	if (err)
+		goto done;
+	else {
+		skb = NULL;
+		err = len;
+	}
 
 done:
+	if (skb)
+		kfree_skb(skb);
 	release_sock(sk);
 	return err;
-
-drop:
-	kfree_skb(skb);
-	goto done;
 }
 
 static int
@@ -292,7 +294,7 @@
 data_sock_ioctl_bound(struct sock *sk, unsigned int cmd, void __user *p)
 {
 	struct mISDN_ctrl_req	cq;
-	int			err = -EINVAL, val;
+	int			err = -EINVAL, val[2];
 	struct mISDNchannel	*bchan, *next;
 
 	lock_sock(sk);
@@ -328,12 +330,27 @@
 			err = -EINVAL;
 			break;
 		}
-		if (get_user(val, (int __user *)p)) {
+		val[0] = cmd;
+		if (get_user(val[1], (int __user *)p)) {
 			err = -EFAULT;
 			break;
 		}
 		err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr,
-		    CONTROL_CHANNEL, &val);
+		    CONTROL_CHANNEL, val);
+		break;
+	case IMHOLD_L1:
+		if (sk->sk_protocol != ISDN_P_LAPD_NT
+		 && sk->sk_protocol != ISDN_P_LAPD_TE) {
+			err = -EINVAL;
+			break;
+		}
+		val[0] = cmd;
+		if (get_user(val[1], (int __user *)p)) {
+			err = -EFAULT;
+			break;
+		}
+		err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr,
+		    CONTROL_CHANNEL, val);
 		break;
 	default:
 		err = -EINVAL;
diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c
index b452dea..bfcdd97 100644
--- a/drivers/isdn/mISDN/tei.c
+++ b/drivers/isdn/mISDN/tei.c
@@ -122,8 +122,11 @@
 	}
 	read_unlock_irqrestore(&mgr->lock, flags);
 	/* All TEI are inactiv */
-	mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, NULL, 1);
-	mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING);
+	if (!test_bit(OPTION_L1_HOLD, &mgr->options)) {
+		mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER,
+			NULL, 1);
+		mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING);
+	}
 }
 
 static void
@@ -132,9 +135,11 @@
 	struct manager	*mgr = fi->userdata;
 
 	/* restart da timer */
-	mISDN_FsmDelTimer(&mgr->datimer, 2);
-	mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, NULL, 2);
-
+	if (!test_bit(OPTION_L1_HOLD, &mgr->options)) {
+		mISDN_FsmDelTimer(&mgr->datimer, 2);
+		mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER,
+			NULL, 2);
+	}
 }
 
 static void
@@ -222,7 +227,7 @@
 	if (!(*debug & DEBUG_L2_TEIFSM))
 		return;
 	va_start(va, fmt);
-	printk(KERN_DEBUG "tei(%d): ", tm->l2->tei);
+	printk(KERN_DEBUG "sapi(%d) tei(%d): ", tm->l2->sapi, tm->l2->tei);
 	vprintk(fmt, va);
 	printk("\n");
 	va_end(va);
@@ -421,7 +426,7 @@
 }
 
 static void
-put_tei_msg(struct manager *mgr, u_char m_id, unsigned int ri, u_char tei)
+put_tei_msg(struct manager *mgr, u_char m_id, unsigned int ri, int tei)
 {
 	struct sk_buff *skb;
 	u_char bp[8];
@@ -435,9 +440,8 @@
 	bp[4] = ri >> 8;
 	bp[5] = ri & 0xff;
 	bp[6] = m_id;
-	bp[7] = (tei << 1) | 1;
-	skb = _alloc_mISDN_skb(PH_DATA_REQ, new_id(mgr),
-	    8, bp, GFP_ATOMIC);
+	bp[7] = ((tei << 1) & 0xff) | 1;
+	skb = _alloc_mISDN_skb(PH_DATA_REQ, new_id(mgr), 8, bp, GFP_ATOMIC);
 	if (!skb) {
 		printk(KERN_WARNING "%s: no skb for tei msg\n", __func__);
 		return;
@@ -772,7 +776,7 @@
 }
 
 static struct layer2 *
-create_new_tei(struct manager *mgr, int tei)
+create_new_tei(struct manager *mgr, int tei, int sapi)
 {
 	u_long		opt = 0;
 	u_long		flags;
@@ -781,12 +785,12 @@
 
 	if (!mgr->up)
 		return NULL;
-	if (tei < 64)
+	if ((tei >= 0) && (tei < 64))
 		test_and_set_bit(OPTION_L2_FIXEDTEI, &opt);
 	if (mgr->ch.st->dev->Dprotocols
 	  & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1)))
 		test_and_set_bit(OPTION_L2_PMX, &opt);
-	l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, (u_int)opt, (u_long)tei);
+	l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, opt, tei, sapi);
 	if (!l2) {
 		printk(KERN_WARNING "%s:no memory for layer2\n", __func__);
 		return NULL;
@@ -834,12 +838,17 @@
 	ri += dp[1];
 	if (!mgr->up)
 		goto denied;
-	tei = get_free_tei(mgr);
+	if (!(dp[3] & 1)) /* Extension bit != 1 */
+		goto denied;
+	if (dp[3] != 0xff)
+		tei = dp[3] >> 1; /* 3GPP TS 08.56 6.1.11.2 */
+	else
+		tei = get_free_tei(mgr);
 	if (tei < 0) {
 		printk(KERN_WARNING "%s:No free tei\n", __func__);
 		goto denied;
 	}
-	l2 = create_new_tei(mgr, tei);
+	l2 = create_new_tei(mgr, tei, CTRL_SAPI);
 	if (!l2)
 		goto denied;
 	else
@@ -863,7 +872,6 @@
 			    __func__, skb->len);
 		goto done;
 	}
-	if (*debug  & DEBUG_L2_TEI)
 
 	if ((skb->data[0] >> 2) != TEI_SAPI) /* not for us */
 		goto done;
@@ -971,8 +979,6 @@
 			__func__, dev_name(&mgr->ch.st->dev->dev),
 			crq->protocol, crq->adr.dev, crq->adr.channel,
 			crq->adr.sapi, crq->adr.tei);
-	if (crq->adr.sapi != 0) /* not supported yet */
-		return -EINVAL;
 	if (crq->adr.tei > GROUP_TEI)
 		return -EINVAL;
 	if (crq->adr.tei < 64)
@@ -1019,8 +1025,8 @@
 		}
 		return 0;
 	}
-	l2 = create_l2(crq->ch, crq->protocol, (u_int)opt,
-		(u_long)crq->adr.tei);
+	l2 = create_l2(crq->ch, crq->protocol, opt,
+		crq->adr.tei, crq->adr.sapi);
 	if (!l2)
 		return -ENOMEM;
 	l2->tm = kzalloc(sizeof(struct teimgr), GFP_KERNEL);
@@ -1103,6 +1109,7 @@
 {
 	struct layer2	*l2, *nl2;
 
+	test_and_clear_bit(OPTION_L1_HOLD, &mgr->options);
 	if (test_bit(MGR_OPT_NETWORK, &mgr->options)) {
 		/* not locked lock is taken in release tei */
 		mgr->up = NULL;
@@ -1133,13 +1140,26 @@
 ctrl_teimanager(struct manager *mgr, void *arg)
 {
 	/* currently we only have one option */
-	int	clean = *((int *)arg);
+	int	*val = (int *)arg;
+	int	ret = 0;
 
-	if (clean)
-		test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options);
-	else
-		test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options);
-	return 0;
+	switch (val[0]) {
+	case IMCLEAR_L2:
+		if (val[1])
+			test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options);
+		else
+			test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options);
+		break;
+	case IMHOLD_L1:
+		if (val[1])
+			test_and_set_bit(OPTION_L1_HOLD, &mgr->options);
+		else
+			test_and_clear_bit(OPTION_L1_HOLD, &mgr->options);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	return ret;
 }
 
 /* This function does create a L2 for fixed TEI in NT Mode */
@@ -1147,7 +1167,7 @@
 check_data(struct manager *mgr, struct sk_buff *skb)
 {
 	struct mISDNhead	*hh =  mISDN_HEAD_P(skb);
-	int			ret, tei;
+	int			ret, tei, sapi;
 	struct layer2		*l2;
 
 	if (*debug & DEBUG_L2_CTRL)
@@ -1159,20 +1179,27 @@
 		return -ENOTCONN;
 	if (skb->len != 3)
 		return -ENOTCONN;
-	if (skb->data[0] != 0)
-		/* only SAPI 0 command */
-		return -ENOTCONN;
+	if (skb->data[0] & 3) /* EA0 and CR must be  0 */
+		return -EINVAL;
+	sapi = skb->data[0] >> 2;
 	if (!(skb->data[1] & 1)) /* invalid EA1 */
 		return -EINVAL;
-	tei = skb->data[1] >> 0;
+	tei = skb->data[1] >> 1;
 	if (tei > 63) /* not a fixed tei */
 		return -ENOTCONN;
 	if ((skb->data[2] & ~0x10) != SABME)
 		return -ENOTCONN;
 	/* We got a SABME for a fixed TEI */
-	l2 = create_new_tei(mgr, tei);
-	if (!l2)
+	if (*debug & DEBUG_L2_CTRL)
+		printk(KERN_DEBUG "%s: SABME sapi(%d) tei(%d)\n",
+		    __func__, sapi, tei);
+	l2 = create_new_tei(mgr, tei, sapi);
+	if (!l2) {
+		if (*debug & DEBUG_L2_CTRL)
+			printk(KERN_DEBUG "%s: failed to create new tei\n",
+			    __func__);
 		return -ENOMEM;
+	}
 	ret = l2->ch.send(&l2->ch, skb);
 	return ret;
 }
diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c
index bbd99d3..5b7e9bf 100644
--- a/drivers/isdn/mISDN/timerdev.c
+++ b/drivers/isdn/mISDN/timerdev.c
@@ -259,7 +259,7 @@
 	return ret;
 }
 
-static struct file_operations mISDN_fops = {
+static const struct file_operations mISDN_fops = {
 	.read		= mISDN_read,
 	.poll		= mISDN_poll,
 	.ioctl		= mISDN_ioctl,
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index 1c5344a..367bec6 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -281,7 +281,7 @@
 		autoirq = probe_irq_off(irq_mask);
 
 		if (autoirq == 0) {
-			printk(KERN_WARNING "%s probe at %#x failed to detect IRQ line.\n",
+			pr_warning("%s probe at %#x failed to detect IRQ line.\n",
 				mname, ioaddr);
 			release_region(ioaddr, EL1_IO_EXTENT);
 			return -EAGAIN;
@@ -297,16 +297,16 @@
 	if (autoirq)
 		dev->irq = autoirq;
 
-	printk(KERN_INFO "%s: %s EtherLink at %#lx, using %sIRQ %d.\n",
+	pr_info("%s: %s EtherLink at %#lx, using %sIRQ %d.\n",
 			dev->name, mname, dev->base_addr,
 			autoirq ? "auto":"assigned ", dev->irq);
 
 #ifdef CONFIG_IP_MULTICAST
-	printk(KERN_WARNING "WARNING: Use of the 3c501 in a multicast kernel is NOT recommended.\n");
+	pr_warning("WARNING: Use of the 3c501 in a multicast kernel is NOT recommended.\n");
 #endif
 
 	if (el_debug)
-		printk(KERN_DEBUG "%s", version);
+		pr_debug("%s", version);
 
 	lp = netdev_priv(dev);
 	memset(lp, 0, sizeof(struct net_local));
@@ -343,7 +343,7 @@
 	unsigned long flags;
 
 	if (el_debug > 2)
-		printk(KERN_DEBUG "%s: Doing el_open()...", dev->name);
+		pr_debug("%s: Doing el_open()...\n", dev->name);
 
 	retval = request_irq(dev->irq, &el_interrupt, 0, dev->name, dev);
 	if (retval)
@@ -374,7 +374,7 @@
 	int ioaddr = dev->base_addr;
 
 	if (el_debug)
-		printk(KERN_DEBUG "%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n",
+		pr_debug("%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n",
 			dev->name, inb(TX_STATUS),
 			inb(AX_STATUS), inb(RX_STATUS));
 	dev->stats.tx_errors++;
@@ -483,14 +483,13 @@
 			lp->loading = 0;
 			dev->trans_start = jiffies;
 			if (el_debug > 2)
-				printk(KERN_DEBUG " queued xmit.\n");
+				pr_debug(" queued xmit.\n");
 			dev_kfree_skb(skb);
 			return 0;
 		}
 		/* A receive upset our load, despite our best efforts */
 		if (el_debug > 2)
-			printk(KERN_DEBUG "%s: burped during tx load.\n",
-				dev->name);
+			pr_debug("%s: burped during tx load.\n", dev->name);
 		spin_lock_irqsave(&lp->lock, flags);
 	} while (1);
 }
@@ -540,11 +539,10 @@
 	 */
 
 	if (el_debug > 3)
-		printk(KERN_DEBUG "%s: el_interrupt() aux=%#02x",
-							dev->name, axsr);
+		pr_debug("%s: el_interrupt() aux=%#02x\n", dev->name, axsr);
 
 	if (lp->loading == 1 && !lp->txing)
-		printk(KERN_WARNING "%s: Inconsistent state loading while not in tx\n",
+		pr_warning("%s: Inconsistent state loading while not in tx\n",
 			dev->name);
 
 	if (lp->txing) {
@@ -555,19 +553,17 @@
 		int txsr = inb(TX_STATUS);
 
 		if (lp->loading == 1) {
-			if (el_debug > 2) {
-				printk(KERN_DEBUG "%s: Interrupt while loading [",
-					dev->name);
-				printk(" txsr=%02x gp=%04x rp=%04x]\n",
-					txsr, inw(GP_LOW), inw(RX_LOW));
-			}
+			if (el_debug > 2)
+				pr_debug("%s: Interrupt while loading [txsr=%02x gp=%04x rp=%04x]\n",
+					dev->name, txsr, inw(GP_LOW), inw(RX_LOW));
+
 			/* Force a reload */
 			lp->loading = 2;
 			spin_unlock(&lp->lock);
 			goto out;
 		}
 		if (el_debug > 6)
-			printk(KERN_DEBUG " txsr=%02x gp=%04x rp=%04x",
+			pr_debug("%s: txsr=%02x gp=%04x rp=%04x\n", dev->name,
 					txsr, inw(GP_LOW), inw(RX_LOW));
 
 		if ((axsr & 0x80) && (txsr & TX_READY) == 0) {
@@ -576,7 +572,7 @@
 			 *	on trying or reset immediately ?
 			 */
 			if (el_debug > 1)
-				printk(KERN_DEBUG "%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x gp=%03x rp=%03x.\n",
+				pr_debug("%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x gp=%03x rp=%03x.\n",
 					dev->name, txsr, axsr,
 					inw(ioaddr + EL1_DATAPTR),
 					inw(ioaddr + EL1_RXPTR));
@@ -587,7 +583,7 @@
 			 *	Timed out
 			 */
 			if (el_debug)
-				printk(KERN_DEBUG "%s: Transmit failed 16 times, Ethernet jammed?\n", dev->name);
+				pr_debug("%s: Transmit failed 16 times, Ethernet jammed?\n", dev->name);
 			outb(AX_SYS, AX_CMD);
 			lp->txing = 0;
 			dev->stats.tx_aborted_errors++;
@@ -598,7 +594,7 @@
 			 */
 
 			if (el_debug > 6)
-				printk(KERN_DEBUG " retransmitting after a collision.\n");
+				pr_debug("%s: retransmitting after a collision.\n", dev->name);
 			/*
 			 *	Poor little chip can't reset its own start
 			 *	pointer
@@ -616,9 +612,8 @@
 			 */
 			dev->stats.tx_packets++;
 			if (el_debug > 6)
-				printk(KERN_DEBUG " Tx succeeded %s\n",
-					(txsr & TX_RDY) ? "." :
-							"but tx is busy!");
+				pr_debug("%s: Tx succeeded %s\n", dev->name,
+					(txsr & TX_RDY) ? "." : "but tx is busy!");
 			/*
 			 *	This is safe the interrupt is atomic WRT itself.
 			 */
@@ -633,7 +628,8 @@
 
 		int rxsr = inb(RX_STATUS);
 		if (el_debug > 5)
-			printk(KERN_DEBUG " rxsr=%02x txsr=%02x rp=%04x", rxsr, inb(TX_STATUS), inw(RX_LOW));
+			pr_debug("%s: rxsr=%02x txsr=%02x rp=%04x\n",
+				dev->name, rxsr, inb(TX_STATUS), inw(RX_LOW));
 		/*
 		 *	Just reading rx_status fixes most errors.
 		 */
@@ -643,7 +639,7 @@
 			/* Handled to avoid board lock-up. */
 			dev->stats.rx_length_errors++;
 			if (el_debug > 5)
-				printk(KERN_DEBUG " runt.\n");
+				pr_debug("%s: runt.\n", dev->name);
 		} else if (rxsr & RX_GOOD) {
 			/*
 			 *	Receive worked.
@@ -654,12 +650,10 @@
 			 *	Nothing?  Something is broken!
 			 */
 			if (el_debug > 2)
-				printk(KERN_DEBUG "%s: No packet seen, rxsr=%02x **resetting 3c501***\n",
+				pr_debug("%s: No packet seen, rxsr=%02x **resetting 3c501***\n",
 					dev->name, rxsr);
 			el_reset(dev);
 		}
-		if (el_debug > 3)
-			printk(KERN_DEBUG ".\n");
 	}
 
 	/*
@@ -695,11 +689,11 @@
 	pkt_len = inw(RX_LOW);
 
 	if (el_debug > 4)
-		printk(KERN_DEBUG " el_receive %d.\n", pkt_len);
+		pr_debug(" el_receive %d.\n", pkt_len);
 
 	if (pkt_len < 60 || pkt_len > 1536) {
 		if (el_debug)
-			printk(KERN_DEBUG "%s: bogus packet, length=%d\n",
+			pr_debug("%s: bogus packet, length=%d\n",
 						dev->name, pkt_len);
 		dev->stats.rx_over_errors++;
 		return;
@@ -718,8 +712,7 @@
 
 	outw(0x00, GP_LOW);
 	if (skb == NULL) {
-		printk(KERN_INFO "%s: Memory squeeze, dropping packet.\n",
-								dev->name);
+		pr_info("%s: Memory squeeze, dropping packet.\n", dev->name);
 		dev->stats.rx_dropped++;
 		return;
 	} else {
@@ -753,7 +746,7 @@
 	int ioaddr = dev->base_addr;
 
 	if (el_debug > 2)
-		printk(KERN_INFO "3c501 reset...");
+		pr_info("3c501 reset...\n");
 	outb(AX_RESET, AX_CMD);		/* Reset the chip */
 	/* Aux control, irq and loopback enabled */
 	outb(AX_LOOP, AX_CMD);
@@ -787,7 +780,7 @@
 	int ioaddr = dev->base_addr;
 
 	if (el_debug > 2)
-		printk(KERN_INFO "%s: Shutting down Ethernet card at %#x.\n",
+		pr_info("%s: Shutting down Ethernet card at %#x.\n",
 						dev->name, ioaddr);
 
 	netif_stop_queue(dev);
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index 4f08bd9..134638a 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -234,16 +234,16 @@
     }
 
     if (ei_debug  &&  version_printed++ == 0)
-	printk(version);
+	pr_debug("%s", version);
 
     dev->base_addr = ioaddr;
 
-    printk("%s: 3c503 at i/o base %#3x, node ", dev->name, ioaddr);
+    pr_info("%s: 3c503 at i/o base %#3x, node ", dev->name, ioaddr);
 
     /* Retrieve and print the ethernet address. */
     for (i = 0; i < 6; i++)
 	dev->dev_addr[i] = inb(ioaddr + i);
-    printk("%pM", dev->dev_addr);
+    pr_cont("%pM", dev->dev_addr);
 
     /* Map the 8390 back into the window. */
     outb(ECNTRL_THIN, ioaddr + 0x406);
@@ -256,7 +256,8 @@
     outb_p(E8390_PAGE0, ioaddr + E8390_CMD);
 
     /* Probe for, turn on and clear the board's shared memory. */
-    if (ei_debug > 2) printk(" memory jumpers %2.2x ", membase_reg);
+    if (ei_debug > 2)
+	pr_cont(" memory jumpers %2.2x ", membase_reg);
     outb(EGACFR_NORM, ioaddr + 0x405);	/* Enable RAM */
 
     /* This should be probed for (or set via an ioctl()) at run-time.
@@ -268,7 +269,7 @@
 #else
     ei_status.interface_num = dev->mem_end & 0xf;
 #endif
-    printk(", using %sternal xcvr.\n", ei_status.interface_num == 0 ? "in" : "ex");
+    pr_cont(", using %sternal xcvr.\n", ei_status.interface_num == 0 ? "in" : "ex");
 
     if ((membase_reg & 0xf0) == 0) {
 	dev->mem_start = 0;
@@ -292,7 +293,7 @@
 		writel(test_val, mem_base + i);
 		if (readl(mem_base) != 0xba5eba5e
 		    || readl(mem_base + i) != test_val) {
-		    printk("3c503: memory failure or memory address conflict.\n");
+		    pr_warning("3c503: memory failure or memory address conflict.\n");
 		    dev->mem_start = 0;
 		    ei_status.name = "3c503-PIO";
 		    iounmap(mem_base);
@@ -344,7 +345,7 @@
     if (dev->irq == 2)
 	dev->irq = 9;
     else if (dev->irq > 5 && dev->irq != 9) {
-	printk("3c503: configured interrupt %d invalid, will use autoIRQ.\n",
+	pr_warning("3c503: configured interrupt %d invalid, will use autoIRQ.\n",
 	       dev->irq);
 	dev->irq = 0;
     }
@@ -359,7 +360,7 @@
 	goto out1;
 
     if (dev->mem_start)
-	printk("%s: %s - %dkB RAM, 8kB shared mem window at %#6lx-%#6lx.\n",
+	pr_info("%s: %s - %dkB RAM, 8kB shared mem window at %#6lx-%#6lx.\n",
 		dev->name, ei_status.name, (wordlength+1)<<3,
 		dev->mem_start, dev->mem_end-1);
 
@@ -367,7 +368,7 @@
     {
 	ei_status.tx_start_page = EL2_MB1_START_PG;
 	ei_status.rx_start_page = EL2_MB1_START_PG + TX_PAGES;
-	printk("\n%s: %s, %dkB RAM, using programmed I/O (REJUMPER for SHARED MEMORY).\n",
+	pr_info("%s: %s, %dkB RAM, using programmed I/O (REJUMPER for SHARED MEMORY).\n",
 	       dev->name, ei_status.name, (wordlength+1)<<3);
     }
     release_region(ioaddr + 0x400, 8);
@@ -435,15 +436,16 @@
 el2_reset_8390(struct net_device *dev)
 {
     if (ei_debug > 1) {
-	printk("%s: Resetting the 3c503 board...", dev->name);
-	printk("%#lx=%#02x %#lx=%#02x %#lx=%#02x...", E33G_IDCFR, inb(E33G_IDCFR),
+	pr_debug("%s: Resetting the 3c503 board...", dev->name);
+	pr_cont(" %#lx=%#02x %#lx=%#02x %#lx=%#02x...", E33G_IDCFR, inb(E33G_IDCFR),
 	       E33G_CNTRL, inb(E33G_CNTRL), E33G_GACFR, inb(E33G_GACFR));
     }
     outb_p(ECNTRL_RESET|ECNTRL_THIN, E33G_CNTRL);
     ei_status.txing = 0;
     outb_p(ei_status.interface_num==0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
     el2_init_card(dev);
-    if (ei_debug > 1) printk("done\n");
+    if (ei_debug > 1)
+	pr_cont("done\n");
 }
 
 /* Initialize the 3c503 GA registers after a reset. */
@@ -529,7 +531,7 @@
         {
             if(!boguscount--)
             {
-                printk("%s: FIFO blocked in el2_block_output.\n", dev->name);
+                pr_notice("%s: FIFO blocked in el2_block_output.\n", dev->name);
                 el2_reset_8390(dev);
                 goto blocked;
             }
@@ -581,7 +583,7 @@
     {
         if(!boguscount--)
         {
-            printk("%s: FIFO blocked in el2_get_8390_hdr.\n", dev->name);
+            pr_notice("%s: FIFO blocked in el2_get_8390_hdr.\n", dev->name);
             memset(hdr, 0x00, sizeof(struct e8390_pkt_hdr));
             el2_reset_8390(dev);
             goto blocked;
@@ -645,7 +647,7 @@
         {
             if(!boguscount--)
             {
-                printk("%s: FIFO blocked in el2_block_input.\n", dev->name);
+                pr_notice("%s: FIFO blocked in el2_block_input.\n", dev->name);
                 el2_reset_8390(dev);
                 goto blocked;
             }
@@ -707,7 +709,7 @@
 	for (this_dev = 0; this_dev < MAX_EL2_CARDS; this_dev++) {
 		if (io[this_dev] == 0)  {
 			if (this_dev != 0) break; /* only autoprobe 1st one */
-			printk(KERN_NOTICE "3c503.c: Presently autoprobing (not recommended) for a single card.\n");
+			pr_notice("3c503.c: Presently autoprobing (not recommended) for a single card.\n");
 		}
 		dev = alloc_eip_netdev();
 		if (!dev)
@@ -720,7 +722,7 @@
 			continue;
 		}
 		free_netdev(dev);
-		printk(KERN_WARNING "3c503.c: No 3c503 card found (i/o = 0x%x).\n", io[this_dev]);
+		pr_warning("3c503.c: No 3c503 card found (i/o = 0x%x).\n", io[this_dev]);
 		break;
 	}
 	if (found)
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index 2de1c9c..b284994 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -126,26 +126,25 @@
  *
  *********************************************************/
 
-static const char filename[] = __FILE__;
+#define filename __FILE__
 
-static const char timeout_msg[] = "*** timeout at %s:%s (line %d) ***\n";
+#define timeout_msg "*** timeout at %s:%s (line %d) ***\n"
 #define TIMEOUT_MSG(lineno) \
-	printk(timeout_msg, filename,__func__,(lineno))
+	pr_notice(timeout_msg, filename, __func__, (lineno))
 
-static const char invalid_pcb_msg[] =
-"*** invalid pcb length %d at %s:%s (line %d) ***\n";
+#define invalid_pcb_msg "*** invalid pcb length %d at %s:%s (line %d) ***\n"
 #define INVALID_PCB_MSG(len) \
-	printk(invalid_pcb_msg, (len),filename,__func__,__LINE__)
+	pr_notice(invalid_pcb_msg, (len), filename, __func__, __LINE__)
 
-static char search_msg[] __initdata = KERN_INFO "%s: Looking for 3c505 adapter at address %#x...";
+#define search_msg "%s: Looking for 3c505 adapter at address %#x..."
 
-static char stilllooking_msg[] __initdata = "still looking...";
+#define stilllooking_msg "still looking..."
 
-static char found_msg[] __initdata = "found.\n";
+#define found_msg "found.\n"
 
-static char notfound_msg[] __initdata = "not found (reason = %d)\n";
+#define notfound_msg "not found (reason = %d)\n"
 
-static char couldnot_msg[] __initdata = KERN_INFO "%s: 3c505 not found\n";
+#define couldnot_msg "%s: 3c505 not found\n"
 
 /*********************************************************
  *
@@ -284,7 +283,7 @@
 
 	outb_control(orig_hcr, dev);
 	if (!start_receive(dev, &adapter->tx_pcb))
-		printk(KERN_ERR "%s: start receive command failed \n", dev->name);
+		pr_err("%s: start receive command failed\n", dev->name);
 }
 
 /* Check to make sure that a DMA transfer hasn't timed out.  This should
@@ -296,7 +295,9 @@
 	elp_device *adapter = netdev_priv(dev);
 	if (adapter->dmaing && time_after(jiffies, adapter->current_dma.start_time + 10)) {
 		unsigned long flags, f;
-		printk(KERN_ERR "%s: DMA %s timed out, %d bytes left\n", dev->name, adapter->current_dma.direction ? "download" : "upload", get_dma_residue(dev->dma));
+		pr_err("%s: DMA %s timed out, %d bytes left\n", dev->name,
+			adapter->current_dma.direction ? "download" : "upload",
+			get_dma_residue(dev->dma));
 		spin_lock_irqsave(&adapter->lock, flags);
 		adapter->dmaing = 0;
 		adapter->busy = 0;
@@ -321,7 +322,7 @@
 		if (inb_status(base_addr) & HCRE)
 			return false;
 	}
-	printk(KERN_WARNING "3c505: send_pcb_slow timed out\n");
+	pr_warning("3c505: send_pcb_slow timed out\n");
 	return true;
 }
 
@@ -333,7 +334,7 @@
 		if (inb_status(base_addr) & HCRE)
 			return false;
 	}
-	printk(KERN_WARNING "3c505: send_pcb_fast timed out\n");
+	pr_warning("3c505: send_pcb_fast timed out\n");
 	return true;
 }
 
@@ -386,7 +387,7 @@
 	/* Avoid contention */
 	if (test_and_set_bit(1, &adapter->send_pcb_semaphore)) {
 		if (elp_debug >= 3) {
-			printk(KERN_DEBUG "%s: send_pcb entered while threaded\n", dev->name);
+			pr_debug("%s: send_pcb entered while threaded\n", dev->name);
 		}
 		return false;
 	}
@@ -424,14 +425,15 @@
 
 		case ASF_PCB_NAK:
 #ifdef ELP_DEBUG
-			printk(KERN_DEBUG "%s: send_pcb got NAK\n", dev->name);
+			pr_debug("%s: send_pcb got NAK\n", dev->name);
 #endif
 			goto abort;
 		}
 	}
 
 	if (elp_debug >= 1)
-		printk(KERN_DEBUG "%s: timeout waiting for PCB acknowledge (status %02x)\n", dev->name, inb_status(dev->base_addr));
+		pr_debug("%s: timeout waiting for PCB acknowledge (status %02x)\n",
+			dev->name, inb_status(dev->base_addr));
 	goto abort;
 
       sti_abort:
@@ -481,7 +483,7 @@
 	while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout));
 	if (time_after_eq(jiffies, timeout)) {
 		TIMEOUT_MSG(__LINE__);
-		printk(KERN_INFO "%s: status %02x\n", dev->name, stat);
+		pr_info("%s: status %02x\n", dev->name, stat);
 		return false;
 	}
 	pcb->length = inb_command(dev->base_addr);
@@ -518,7 +520,7 @@
 	/* safety check total length vs data length */
 	if (total_length != (pcb->length + 2)) {
 		if (elp_debug >= 2)
-			printk(KERN_WARNING "%s: mangled PCB received\n", dev->name);
+			pr_warning("%s: mangled PCB received\n", dev->name);
 		set_hsf(dev, HSF_PCB_NAK);
 		return false;
 	}
@@ -527,7 +529,7 @@
 		if (test_and_set_bit(0, (void *) &adapter->busy)) {
 			if (backlog_next(adapter->rx_backlog.in) == adapter->rx_backlog.out) {
 				set_hsf(dev, HSF_PCB_NAK);
-				printk(KERN_WARNING "%s: PCB rejected, transfer in progress and backlog full\n", dev->name);
+				pr_warning("%s: PCB rejected, transfer in progress and backlog full\n", dev->name);
 				pcb->command = 0;
 				return true;
 			} else {
@@ -552,7 +554,7 @@
 	elp_device *adapter = netdev_priv(dev);
 
 	if (elp_debug >= 3)
-		printk(KERN_DEBUG "%s: restarting receiver\n", dev->name);
+		pr_debug("%s: restarting receiver\n", dev->name);
 	tx_pcb->command = CMD_RECEIVE_PACKET;
 	tx_pcb->length = sizeof(struct Rcv_pkt);
 	tx_pcb->data.rcv_pkt.buf_seg
@@ -586,7 +588,7 @@
 	skb = dev_alloc_skb(rlen + 2);
 
 	if (!skb) {
-		printk(KERN_WARNING "%s: memory squeeze, dropping packet\n", dev->name);
+		pr_warning("%s: memory squeeze, dropping packet\n", dev->name);
 		target = adapter->dma_buffer;
 		adapter->current_dma.target = NULL;
 		/* FIXME: stats */
@@ -604,7 +606,8 @@
 
 	/* if this happens, we die */
 	if (test_and_set_bit(0, (void *) &adapter->dmaing))
-		printk(KERN_ERR "%s: rx blocked, DMA in progress, dir %d\n", dev->name, adapter->current_dma.direction);
+		pr_err("%s: rx blocked, DMA in progress, dir %d\n",
+			dev->name, adapter->current_dma.direction);
 
 	adapter->current_dma.direction = 0;
 	adapter->current_dma.length = rlen;
@@ -623,14 +626,14 @@
 	release_dma_lock(flags);
 
 	if (elp_debug >= 3) {
-		printk(KERN_DEBUG "%s: rx DMA transfer started\n", dev->name);
+		pr_debug("%s: rx DMA transfer started\n", dev->name);
 	}
 
 	if (adapter->rx_active)
 		adapter->rx_active--;
 
 	if (!adapter->busy)
-		printk(KERN_WARNING "%s: receive_packet called, busy not set.\n", dev->name);
+		pr_warning("%s: receive_packet called, busy not set.\n", dev->name);
 }
 
 /******************************************************
@@ -655,12 +658,13 @@
 		 * has a DMA transfer finished?
 		 */
 		if (inb_status(dev->base_addr) & DONE) {
-			if (!adapter->dmaing) {
-				printk(KERN_WARNING "%s: phantom DMA completed\n", dev->name);
-			}
-			if (elp_debug >= 3) {
-				printk(KERN_DEBUG "%s: %s DMA complete, status %02x\n", dev->name, adapter->current_dma.direction ? "tx" : "rx", inb_status(dev->base_addr));
-			}
+			if (!adapter->dmaing)
+				pr_warning("%s: phantom DMA completed\n", dev->name);
+
+			if (elp_debug >= 3)
+				pr_debug("%s: %s DMA complete, status %02x\n", dev->name,
+					adapter->current_dma.direction ? "tx" : "rx",
+					inb_status(dev->base_addr));
 
 			outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
 			if (adapter->current_dma.direction) {
@@ -682,7 +686,7 @@
 				int t = adapter->rx_backlog.length[adapter->rx_backlog.out];
 				adapter->rx_backlog.out = backlog_next(adapter->rx_backlog.out);
 				if (elp_debug >= 2)
-					printk(KERN_DEBUG "%s: receiving backlogged packet (%d)\n", dev->name, t);
+					pr_debug("%s: receiving backlogged packet (%d)\n", dev->name, t);
 				receive_packet(dev, t);
 			} else {
 				adapter->busy = 0;
@@ -713,21 +717,23 @@
 					len = adapter->irx_pcb.data.rcv_resp.pkt_len;
 					dlen = adapter->irx_pcb.data.rcv_resp.buf_len;
 					if (adapter->irx_pcb.data.rcv_resp.timeout != 0) {
-						printk(KERN_ERR "%s: interrupt - packet not received correctly\n", dev->name);
+						pr_err("%s: interrupt - packet not received correctly\n", dev->name);
 					} else {
 						if (elp_debug >= 3) {
-							printk(KERN_DEBUG "%s: interrupt - packet received of length %i (%i)\n", dev->name, len, dlen);
+							pr_debug("%s: interrupt - packet received of length %i (%i)\n",
+								dev->name, len, dlen);
 						}
 						if (adapter->irx_pcb.command == 0xff) {
 							if (elp_debug >= 2)
-								printk(KERN_DEBUG "%s: adding packet to backlog (len = %d)\n", dev->name, dlen);
+								pr_debug("%s: adding packet to backlog (len = %d)\n",
+									dev->name, dlen);
 							adapter->rx_backlog.length[adapter->rx_backlog.in] = dlen;
 							adapter->rx_backlog.in = backlog_next(adapter->rx_backlog.in);
 						} else {
 							receive_packet(dev, dlen);
 						}
 						if (elp_debug >= 3)
-							printk(KERN_DEBUG "%s: packet received\n", dev->name);
+							pr_debug("%s: packet received\n", dev->name);
 					}
 					break;
 
@@ -737,7 +743,7 @@
 				case CMD_CONFIGURE_82586_RESPONSE:
 					adapter->got[CMD_CONFIGURE_82586] = 1;
 					if (elp_debug >= 3)
-						printk(KERN_DEBUG "%s: interrupt - configure response received\n", dev->name);
+						pr_debug("%s: interrupt - configure response received\n", dev->name);
 					break;
 
 					/*
@@ -746,7 +752,7 @@
 				case CMD_CONFIGURE_ADAPTER_RESPONSE:
 					adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 1;
 					if (elp_debug >= 3)
-						printk(KERN_DEBUG "%s: Adapter memory configuration %s.\n", dev->name,
+						pr_debug("%s: Adapter memory configuration %s.\n", dev->name,
 						       adapter->irx_pcb.data.failed ? "failed" : "succeeded");
 					break;
 
@@ -756,7 +762,7 @@
 				case CMD_LOAD_MULTICAST_RESPONSE:
 					adapter->got[CMD_LOAD_MULTICAST_LIST] = 1;
 					if (elp_debug >= 3)
-						printk(KERN_DEBUG "%s: Multicast address list loading %s.\n", dev->name,
+						pr_debug("%s: Multicast address list loading %s.\n", dev->name,
 						       adapter->irx_pcb.data.failed ? "failed" : "succeeded");
 					break;
 
@@ -766,7 +772,7 @@
 				case CMD_SET_ADDRESS_RESPONSE:
 					adapter->got[CMD_SET_STATION_ADDRESS] = 1;
 					if (elp_debug >= 3)
-						printk(KERN_DEBUG "%s: Ethernet address setting %s.\n", dev->name,
+						pr_debug("%s: Ethernet address setting %s.\n", dev->name,
 						       adapter->irx_pcb.data.failed ? "failed" : "succeeded");
 					break;
 
@@ -783,7 +789,7 @@
 					dev->stats.rx_over_errors += adapter->irx_pcb.data.netstat.err_res;
 					adapter->got[CMD_NETWORK_STATISTICS] = 1;
 					if (elp_debug >= 3)
-						printk(KERN_DEBUG "%s: interrupt - statistics response received\n", dev->name);
+						pr_debug("%s: interrupt - statistics response received\n", dev->name);
 					break;
 
 					/*
@@ -791,17 +797,17 @@
 					 */
 				case CMD_TRANSMIT_PACKET_COMPLETE:
 					if (elp_debug >= 3)
-						printk(KERN_DEBUG "%s: interrupt - packet sent\n", dev->name);
+						pr_debug("%s: interrupt - packet sent\n", dev->name);
 					if (!netif_running(dev))
 						break;
 					switch (adapter->irx_pcb.data.xmit_resp.c_stat) {
 					case 0xffff:
 						dev->stats.tx_aborted_errors++;
-						printk(KERN_INFO "%s: transmit timed out, network cable problem?\n", dev->name);
+						pr_info("%s: transmit timed out, network cable problem?\n", dev->name);
 						break;
 					case 0xfffe:
 						dev->stats.tx_fifo_errors++;
-						printk(KERN_INFO "%s: transmit timed out, FIFO underrun\n", dev->name);
+						pr_info("%s: transmit timed out, FIFO underrun\n", dev->name);
 						break;
 					}
 					netif_wake_queue(dev);
@@ -811,11 +817,12 @@
 					 * some unknown PCB
 					 */
 				default:
-					printk(KERN_DEBUG "%s: unknown PCB received - %2.2x\n", dev->name, adapter->irx_pcb.command);
+					pr_debug("%s: unknown PCB received - %2.2x\n",
+						dev->name, adapter->irx_pcb.command);
 					break;
 				}
 			} else {
-				printk(KERN_WARNING "%s: failed to read PCB on interrupt\n", dev->name);
+				pr_warning("%s: failed to read PCB on interrupt\n", dev->name);
 				adapter_reset(dev);
 			}
 		}
@@ -844,13 +851,13 @@
 	int retval;
 
 	if (elp_debug >= 3)
-		printk(KERN_DEBUG "%s: request to open device\n", dev->name);
+		pr_debug("%s: request to open device\n", dev->name);
 
 	/*
 	 * make sure we actually found the device
 	 */
 	if (adapter == NULL) {
-		printk(KERN_ERR "%s: Opening a non-existent physical device\n", dev->name);
+		pr_err("%s: Opening a non-existent physical device\n", dev->name);
 		return -EAGAIN;
 	}
 	/*
@@ -880,17 +887,17 @@
 	 * install our interrupt service routine
 	 */
 	if ((retval = request_irq(dev->irq, &elp_interrupt, 0, dev->name, dev))) {
-		printk(KERN_ERR "%s: could not allocate IRQ%d\n", dev->name, dev->irq);
+		pr_err("%s: could not allocate IRQ%d\n", dev->name, dev->irq);
 		return retval;
 	}
 	if ((retval = request_dma(dev->dma, dev->name))) {
 		free_irq(dev->irq, dev);
-		printk(KERN_ERR "%s: could not allocate DMA%d channel\n", dev->name, dev->dma);
+		pr_err("%s: could not allocate DMA%d channel\n", dev->name, dev->dma);
 		return retval;
 	}
 	adapter->dma_buffer = (void *) dma_mem_alloc(DMA_BUFFER_SIZE);
 	if (!adapter->dma_buffer) {
-		printk(KERN_ERR "%s: could not allocate DMA buffer\n", dev->name);
+		pr_err("%s: could not allocate DMA buffer\n", dev->name);
 		free_dma(dev->dma);
 		free_irq(dev->irq, dev);
 		return -ENOMEM;
@@ -906,7 +913,7 @@
 	 * configure adapter memory: we need 10 multicast addresses, default==0
 	 */
 	if (elp_debug >= 3)
-		printk(KERN_DEBUG "%s: sending 3c505 memory configuration command\n", dev->name);
+		pr_debug("%s: sending 3c505 memory configuration command\n", dev->name);
 	adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY;
 	adapter->tx_pcb.data.memconf.cmd_q = 10;
 	adapter->tx_pcb.data.memconf.rcv_q = 20;
@@ -917,7 +924,7 @@
 	adapter->tx_pcb.length = sizeof(struct Memconf);
 	adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 0;
 	if (!send_pcb(dev, &adapter->tx_pcb))
-		printk(KERN_ERR "%s: couldn't send memory configuration command\n", dev->name);
+		pr_err("%s: couldn't send memory configuration command\n", dev->name);
 	else {
 		unsigned long timeout = jiffies + TIMEOUT;
 		while (adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] == 0 && time_before(jiffies, timeout));
@@ -930,13 +937,13 @@
 	 * configure adapter to receive broadcast messages and wait for response
 	 */
 	if (elp_debug >= 3)
-		printk(KERN_DEBUG "%s: sending 82586 configure command\n", dev->name);
+		pr_debug("%s: sending 82586 configure command\n", dev->name);
 	adapter->tx_pcb.command = CMD_CONFIGURE_82586;
 	adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD;
 	adapter->tx_pcb.length = 2;
 	adapter->got[CMD_CONFIGURE_82586] = 0;
 	if (!send_pcb(dev, &adapter->tx_pcb))
-		printk(KERN_ERR "%s: couldn't send 82586 configure command\n", dev->name);
+		pr_err("%s: couldn't send 82586 configure command\n", dev->name);
 	else {
 		unsigned long timeout = jiffies + TIMEOUT;
 		while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout));
@@ -952,7 +959,7 @@
 	 */
 	prime_rx(dev);
 	if (elp_debug >= 3)
-		printk(KERN_DEBUG "%s: %d receive PCBs active\n", dev->name, adapter->rx_active);
+		pr_debug("%s: %d receive PCBs active\n", dev->name, adapter->rx_active);
 
 	/*
 	 * device is now officially open!
@@ -982,7 +989,7 @@
 
 	if (test_and_set_bit(0, (void *) &adapter->busy)) {
 		if (elp_debug >= 2)
-			printk(KERN_DEBUG "%s: transmit blocked\n", dev->name);
+			pr_debug("%s: transmit blocked\n", dev->name);
 		return false;
 	}
 
@@ -1004,7 +1011,7 @@
 	}
 	/* if this happens, we die */
 	if (test_and_set_bit(0, (void *) &adapter->dmaing))
-		printk(KERN_DEBUG "%s: tx: DMA %d in progress\n", dev->name, adapter->current_dma.direction);
+		pr_debug("%s: tx: DMA %d in progress\n", dev->name, adapter->current_dma.direction);
 
 	adapter->current_dma.direction = 1;
 	adapter->current_dma.start_time = jiffies;
@@ -1030,7 +1037,7 @@
 	release_dma_lock(flags);
 
 	if (elp_debug >= 3)
-		printk(KERN_DEBUG "%s: DMA transfer started\n", dev->name);
+		pr_debug("%s: DMA transfer started\n", dev->name);
 
 	return true;
 }
@@ -1044,9 +1051,10 @@
 	int stat;
 
 	stat = inb_status(dev->base_addr);
-	printk(KERN_WARNING "%s: transmit timed out, lost %s?\n", dev->name, (stat & ACRF) ? "interrupt" : "command");
+	pr_warning("%s: transmit timed out, lost %s?\n", dev->name,
+		   (stat & ACRF) ? "interrupt" : "command");
 	if (elp_debug >= 1)
-		printk(KERN_DEBUG "%s: status %#02x\n", dev->name, stat);
+		pr_debug("%s: status %#02x\n", dev->name, stat);
 	dev->trans_start = jiffies;
 	dev->stats.tx_dropped++;
 	netif_wake_queue(dev);
@@ -1068,7 +1076,7 @@
 	check_3c505_dma(dev);
 
 	if (elp_debug >= 3)
-		printk(KERN_DEBUG "%s: request to send packet of length %d\n", dev->name, (int) skb->len);
+		pr_debug("%s: request to send packet of length %d\n", dev->name, (int) skb->len);
 
 	netif_stop_queue(dev);
 
@@ -1077,13 +1085,13 @@
 	 */
 	if (!send_packet(dev, skb)) {
 		if (elp_debug >= 2) {
-			printk(KERN_DEBUG "%s: failed to transmit packet\n", dev->name);
+			pr_debug("%s: failed to transmit packet\n", dev->name);
 		}
 		spin_unlock_irqrestore(&adapter->lock, flags);
 		return 1;
 	}
 	if (elp_debug >= 3)
-		printk(KERN_DEBUG "%s: packet of length %d sent\n", dev->name, (int) skb->len);
+		pr_debug("%s: packet of length %d sent\n", dev->name, (int) skb->len);
 
 	/*
 	 * start the transmit timeout
@@ -1107,7 +1115,7 @@
 	elp_device *adapter = netdev_priv(dev);
 
 	if (elp_debug >= 3)
-		printk(KERN_DEBUG "%s: request for stats\n", dev->name);
+		pr_debug("%s: request for stats\n", dev->name);
 
 	/* If the device is closed, just return the latest stats we have,
 	   - we cannot ask from the adapter without interrupts */
@@ -1119,7 +1127,7 @@
 	adapter->tx_pcb.length = 0;
 	adapter->got[CMD_NETWORK_STATISTICS] = 0;
 	if (!send_pcb(dev, &adapter->tx_pcb))
-		printk(KERN_ERR "%s: couldn't send get statistics command\n", dev->name);
+		pr_err("%s: couldn't send get statistics command\n", dev->name);
 	else {
 		unsigned long timeout = jiffies + TIMEOUT;
 		while (adapter->got[CMD_NETWORK_STATISTICS] == 0 && time_before(jiffies, timeout));
@@ -1169,7 +1177,7 @@
 	elp_device *adapter = netdev_priv(dev);
 
 	if (elp_debug >= 3)
-		printk(KERN_DEBUG "%s: request to close device\n", dev->name);
+		pr_debug("%s: request to close device\n", dev->name);
 
 	netif_stop_queue(dev);
 
@@ -1213,7 +1221,7 @@
 	unsigned long flags;
 
 	if (elp_debug >= 3)
-		printk(KERN_DEBUG "%s: request to set multicast list\n", dev->name);
+		pr_debug("%s: request to set multicast list\n", dev->name);
 
 	spin_lock_irqsave(&adapter->lock, flags);
 
@@ -1228,7 +1236,7 @@
 		}
 		adapter->got[CMD_LOAD_MULTICAST_LIST] = 0;
 		if (!send_pcb(dev, &adapter->tx_pcb))
-			printk(KERN_ERR "%s: couldn't send set_multicast command\n", dev->name);
+			pr_err("%s: couldn't send set_multicast command\n", dev->name);
 		else {
 			unsigned long timeout = jiffies + TIMEOUT;
 			while (adapter->got[CMD_LOAD_MULTICAST_LIST] == 0 && time_before(jiffies, timeout));
@@ -1247,14 +1255,14 @@
 	 * and wait for response
 	 */
 	if (elp_debug >= 3)
-		printk(KERN_DEBUG "%s: sending 82586 configure command\n", dev->name);
+		pr_debug("%s: sending 82586 configure command\n", dev->name);
 	adapter->tx_pcb.command = CMD_CONFIGURE_82586;
 	adapter->tx_pcb.length = 2;
 	adapter->got[CMD_CONFIGURE_82586] = 0;
 	if (!send_pcb(dev, &adapter->tx_pcb))
 	{
 		spin_unlock_irqrestore(&adapter->lock, flags);
-		printk(KERN_ERR "%s: couldn't send 82586 configure command\n", dev->name);
+		pr_err("%s: couldn't send 82586 configure command\n", dev->name);
 	}
 	else {
 		unsigned long timeout = jiffies + TIMEOUT;
@@ -1283,17 +1291,17 @@
 	orig_HSR = inb_status(addr);
 
 	if (elp_debug > 0)
-		printk(search_msg, name, addr);
+		pr_debug(search_msg, name, addr);
 
 	if (orig_HSR == 0xff) {
 		if (elp_debug > 0)
-			printk(notfound_msg, 1);
+			pr_cont(notfound_msg, 1);
 		goto out;
 	}
 
 	/* Wait for a while; the adapter may still be booting up */
 	if (elp_debug > 0)
-		printk(stilllooking_msg);
+		pr_cont(stilllooking_msg);
 
 	if (orig_HSR & DIR) {
 		/* If HCR.DIR is up, we pull it down. HSR.DIR should follow. */
@@ -1301,7 +1309,7 @@
 		msleep(300);
 		if (inb_status(addr) & DIR) {
 			if (elp_debug > 0)
-				printk(notfound_msg, 2);
+				pr_cont(notfound_msg, 2);
 			goto out;
 		}
 	} else {
@@ -1310,7 +1318,7 @@
 		msleep(300);
 		if (!(inb_status(addr) & DIR)) {
 			if (elp_debug > 0)
-				printk(notfound_msg, 3);
+				pr_cont(notfound_msg, 3);
 			goto out;
 		}
 	}
@@ -1318,7 +1326,7 @@
 	 * It certainly looks like a 3c505.
 	 */
 	if (elp_debug > 0)
-		printk(found_msg);
+		pr_cont(found_msg);
 
 	return 0;
 out:
@@ -1349,7 +1357,7 @@
 
 	/* could not find an adapter */
 	if (elp_debug > 0)
-		printk(couldnot_msg, dev->name);
+		pr_debug(couldnot_msg, dev->name);
 
 	return 0;		/* Because of this, the layer above will return -ENODEV */
 }
@@ -1424,16 +1432,16 @@
 			/* Nope, it's ignoring the command register.  This means that
 			 * either it's still booting up, or it's died.
 			 */
-			printk(KERN_ERR "%s: command register wouldn't drain, ", dev->name);
+			pr_err("%s: command register wouldn't drain, ", dev->name);
 			if ((inb_status(dev->base_addr) & 7) == 3) {
 				/* If the adapter status is 3, it *could* still be booting.
 				 * Give it the benefit of the doubt for 10 seconds.
 				 */
-				printk("assuming 3c505 still starting\n");
+				pr_cont("assuming 3c505 still starting\n");
 				timeout = jiffies + 10*HZ;
 				while (time_before(jiffies, timeout) && (inb_status(dev->base_addr) & 7));
 				if (inb_status(dev->base_addr) & 7) {
-					printk(KERN_ERR "%s: 3c505 failed to start\n", dev->name);
+					pr_err("%s: 3c505 failed to start\n", dev->name);
 				} else {
 					okay = 1;  /* It started */
 				}
@@ -1441,7 +1449,7 @@
 				/* Otherwise, it must just be in a strange
 				 * state.  We probably need to kick it.
 				 */
-				printk("3c505 is sulking\n");
+				pr_cont("3c505 is sulking\n");
 			}
 		}
 		for (tries = 0; tries < 5 && okay; tries++) {
@@ -1454,18 +1462,19 @@
 			adapter->tx_pcb.length = 0;
 			cookie = probe_irq_on();
 			if (!send_pcb(dev, &adapter->tx_pcb)) {
-				printk(KERN_ERR "%s: could not send first PCB\n", dev->name);
+				pr_err("%s: could not send first PCB\n", dev->name);
 				probe_irq_off(cookie);
 				continue;
 			}
 			if (!receive_pcb(dev, &adapter->rx_pcb)) {
-				printk(KERN_ERR "%s: could not read first PCB\n", dev->name);
+				pr_err("%s: could not read first PCB\n", dev->name);
 				probe_irq_off(cookie);
 				continue;
 			}
 			if ((adapter->rx_pcb.command != CMD_ADDRESS_RESPONSE) ||
 			    (adapter->rx_pcb.length != 6)) {
-				printk(KERN_ERR "%s: first PCB wrong (%d, %d)\n", dev->name, adapter->rx_pcb.command, adapter->rx_pcb.length);
+				pr_err("%s: first PCB wrong (%d, %d)\n", dev->name,
+					adapter->rx_pcb.command, adapter->rx_pcb.length);
 				probe_irq_off(cookie);
 				continue;
 			}
@@ -1474,32 +1483,32 @@
 		/* It's broken.  Do a hard reset to re-initialise the board,
 		 * and try again.
 		 */
-		printk(KERN_INFO "%s: resetting adapter\n", dev->name);
+		pr_info("%s: resetting adapter\n", dev->name);
 		outb_control(adapter->hcr_val | FLSH | ATTN, dev);
 		outb_control(adapter->hcr_val & ~(FLSH | ATTN), dev);
 	}
-	printk(KERN_ERR "%s: failed to initialise 3c505\n", dev->name);
+	pr_err("%s: failed to initialise 3c505\n", dev->name);
 	goto out;
 
       okay:
 	if (dev->irq) {		/* Is there a preset IRQ? */
 		int rpt = probe_irq_off(cookie);
 		if (dev->irq != rpt) {
-			printk(KERN_WARNING "%s: warning, irq %d configured but %d detected\n", dev->name, dev->irq, rpt);
+			pr_warning("%s: warning, irq %d configured but %d detected\n", dev->name, dev->irq, rpt);
 		}
 		/* if dev->irq == probe_irq_off(cookie), all is well */
 	} else		       /* No preset IRQ; just use what we can detect */
 		dev->irq = probe_irq_off(cookie);
 	switch (dev->irq) {    /* Legal, sane? */
 	case 0:
-		printk(KERN_ERR "%s: IRQ probe failed: check 3c505 jumpers.\n",
+		pr_err("%s: IRQ probe failed: check 3c505 jumpers.\n",
 		       dev->name);
 		goto out;
 	case 1:
 	case 6:
 	case 8:
 	case 13:
-		printk(KERN_ERR "%s: Impossible IRQ %d reported by probe_irq_off().\n",
+		pr_err("%s: Impossible IRQ %d reported by probe_irq_off().\n",
 		       dev->name, dev->irq);
 		       goto out;
 	}
@@ -1521,7 +1530,7 @@
 			dev->dma = dev->mem_start & 7;
 		}
 		else {
-			printk(KERN_WARNING "%s: warning, DMA channel not specified, using default\n", dev->name);
+			pr_warning("%s: warning, DMA channel not specified, using default\n", dev->name);
 			dev->dma = ELP_DMA;
 		}
 	}
@@ -1529,11 +1538,8 @@
 	/*
 	 * print remainder of startup message
 	 */
-	printk(KERN_INFO "%s: 3c505 at %#lx, irq %d, dma %d, "
-	       "addr %pM, ",
-	       dev->name, dev->base_addr, dev->irq, dev->dma,
-	       dev->dev_addr);
-
+	pr_info("%s: 3c505 at %#lx, irq %d, dma %d, addr %pM, ",
+		dev->name, dev->base_addr, dev->irq, dev->dma, dev->dev_addr);
 	/*
 	 * read more information from the adapter
 	 */
@@ -1544,9 +1550,10 @@
 	    !receive_pcb(dev, &adapter->rx_pcb) ||
 	    (adapter->rx_pcb.command != CMD_ADAPTER_INFO_RESPONSE) ||
 	    (adapter->rx_pcb.length != 10)) {
-		printk("not responding to second PCB\n");
+		pr_cont("not responding to second PCB\n");
 	}
-	printk("rev %d.%d, %dk\n", adapter->rx_pcb.data.info.major_vers, adapter->rx_pcb.data.info.minor_vers, adapter->rx_pcb.data.info.RAM_sz);
+	pr_cont("rev %d.%d, %dk\n", adapter->rx_pcb.data.info.major_vers,
+		adapter->rx_pcb.data.info.minor_vers, adapter->rx_pcb.data.info.RAM_sz);
 
 	/*
 	 * reconfigure the adapter memory to better suit our purposes
@@ -1563,10 +1570,10 @@
 	    !receive_pcb(dev, &adapter->rx_pcb) ||
 	    (adapter->rx_pcb.command != CMD_CONFIGURE_ADAPTER_RESPONSE) ||
 	    (adapter->rx_pcb.length != 2)) {
-		printk(KERN_ERR "%s: could not configure adapter memory\n", dev->name);
+		pr_err("%s: could not configure adapter memory\n", dev->name);
 	}
 	if (adapter->rx_pcb.data.configure) {
-		printk(KERN_ERR "%s: adapter configuration failed\n", dev->name);
+		pr_err("%s: adapter configuration failed\n", dev->name);
 	}
 
 	dev->netdev_ops = &elp_netdev_ops;
@@ -1631,17 +1638,17 @@
 			dev->dma = dma[this_dev];
 		} else {
 			dev->dma = ELP_DMA;
-			printk(KERN_WARNING "3c505.c: warning, using default DMA channel,\n");
+			pr_warning("3c505.c: warning, using default DMA channel,\n");
 		}
 		if (io[this_dev] == 0) {
 			if (this_dev) {
 				free_netdev(dev);
 				break;
 			}
-			printk(KERN_NOTICE "3c505.c: module autoprobe not recommended, give io=xx.\n");
+			pr_notice("3c505.c: module autoprobe not recommended, give io=xx.\n");
 		}
 		if (elplus_setup(dev) != 0) {
-			printk(KERN_WARNING "3c505.c: Failed to register card at 0x%x.\n", io[this_dev]);
+			pr_warning("3c505.c: Failed to register card at 0x%x.\n", io[this_dev]);
 			free_netdev(dev);
 			break;
 		}
diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
index fbbaf82..96b8665 100644
--- a/drivers/net/3c507.c
+++ b/drivers/net/3c507.c
@@ -364,7 +364,7 @@
 
 static int __init el16_probe1(struct net_device *dev, int ioaddr)
 {
-	static unsigned char init_ID_done, version_printed;
+	static unsigned char init_ID_done;
 	int i, irq, irqval, retval;
 	struct net_local *lp;
 
@@ -391,10 +391,7 @@
 		goto out;
 	}
 
-	if (net_debug  &&  version_printed++ == 0)
-		printk(version);
-
-	printk("%s: 3c507 at %#x,", dev->name, ioaddr);
+	pr_info("%s: 3c507 at %#x,", dev->name, ioaddr);
 
 	/* We should make a few more checks here, like the first three octets of
 	   the S.A. for the manufacturer's code. */
@@ -403,7 +400,8 @@
 
 	irqval = request_irq(irq, &el16_interrupt, 0, DRV_NAME, dev);
 	if (irqval) {
-		printk(KERN_ERR "3c507: unable to get IRQ %d (irqval=%d).\n", irq, irqval);
+		pr_cont("\n");
+		pr_err("3c507: unable to get IRQ %d (irqval=%d).\n", irq, irqval);
 		retval = -EAGAIN;
 		goto out;
 	}
@@ -414,7 +412,7 @@
 	outb(0x01, ioaddr + MISC_CTRL);
 	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = inb(ioaddr + i);
-	printk(" %pM", dev->dev_addr);
+	pr_cont(" %pM", dev->dev_addr);
 
 	if (mem_start)
 		net_debug = mem_start & 7;
@@ -443,18 +441,18 @@
 	dev->if_port = (inb(ioaddr + ROM_CONFIG) & 0x80) ? 1 : 0;
 	dev->irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
 
-	printk(", IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->irq,
+	pr_cont(", IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->irq,
 		   dev->if_port ? "ex" : "in", dev->mem_start, dev->mem_end-1);
 
 	if (net_debug)
-		printk(version);
+		pr_debug("%s", version);
 
 	lp = netdev_priv(dev);
  	memset(lp, 0, sizeof(*lp));
 	spin_lock_init(&lp->lock);
 	lp->base = ioremap(dev->mem_start, RX_BUF_END);
 	if (!lp->base) {
-		printk(KERN_ERR "3c507: unable to remap memory\n");
+		pr_err("3c507: unable to remap memory\n");
 		retval = -EAGAIN;
 		goto out1;
 	}
@@ -488,20 +486,20 @@
 	void __iomem *shmem = lp->base;
 
 	if (net_debug > 1)
-		printk ("%s: transmit timed out, %s?  ", dev->name,
+		pr_debug("%s: transmit timed out, %s?  ", dev->name,
 			readw(shmem + iSCB_STATUS) & 0x8000 ? "IRQ conflict" :
 			"network cable problem");
 	/* Try to restart the adaptor. */
 	if (lp->last_restart == dev->stats.tx_packets) {
 		if (net_debug > 1)
-			printk ("Resetting board.\n");
+			pr_cont("Resetting board.\n");
 		/* Completely reset the adaptor. */
 		init_82586_mem (dev);
 		lp->tx_pkts_in_ring = 0;
 	} else {
 		/* Issue the channel attention signal and hope it "gets better". */
 		if (net_debug > 1)
-			printk ("Kicking board.\n");
+			pr_cont("Kicking board.\n");
 		writew(0xf000 | CUC_START | RX_START, shmem + iSCB_CMD);
 		outb (0, ioaddr + SIGNAL_CA);	/* Issue channel-attn. */
 		lp->last_restart = dev->stats.tx_packets;
@@ -553,7 +551,8 @@
 	void __iomem *shmem;
 
 	if (dev == NULL) {
-		printk ("net_interrupt(): irq %d for unknown device.\n", irq);
+		pr_err("%s: net_interrupt(): irq %d for unknown device.\n",
+			dev->name, irq);
 		return IRQ_NONE;
 	}
 
@@ -566,7 +565,7 @@
 	status = readw(shmem+iSCB_STATUS);
 
 	if (net_debug > 4) {
-		printk("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status);
+		pr_debug("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status);
 	}
 
 	/* Disable the 82586's input to the interrupt line. */
@@ -577,7 +576,7 @@
 	  unsigned short tx_status = readw(shmem+lp->tx_reap);
 	  if (!(tx_status & 0x8000)) {
 		if (net_debug > 5)
-			printk("Tx command incomplete (%#x).\n", lp->tx_reap);
+			pr_debug("Tx command incomplete (%#x).\n", lp->tx_reap);
 		break;
 	  }
 	  /* Tx unsuccessful or some interesting status bit set. */
@@ -591,7 +590,7 @@
 	  }
 	  dev->stats.tx_packets++;
 	  if (net_debug > 5)
-		  printk("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status);
+		  pr_debug("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status);
 	  lp->tx_reap += TX_BUF_SIZE;
 	  if (lp->tx_reap > RX_BUF_START - TX_BUF_SIZE)
 		lp->tx_reap = TX_BUF_START;
@@ -606,7 +605,7 @@
 
 	if (status & 0x4000) { /* Packet received. */
 		if (net_debug > 5)
-			printk("Received packet, rx_head %04x.\n", lp->rx_head);
+			pr_debug("Received packet, rx_head %04x.\n", lp->rx_head);
 		el16_rx(dev);
 	}
 
@@ -615,7 +614,7 @@
 
 	if ((status & 0x0700) != 0x0200 && netif_running(dev)) {
 		if (net_debug)
-			printk("%s: Command unit stopped, status %04x, restarting.\n",
+			pr_debug("%s: Command unit stopped, status %04x, restarting.\n",
 				   dev->name, status);
 		/* If this ever occurs we should really re-write the idle loop, reset
 		   the Tx list, and do a complete restart of the command unit.
@@ -627,7 +626,7 @@
 		/* The Rx unit is not ready, it must be hung.  Restart the receiver by
 		   initializing the rx buffers, and issuing an Rx start command. */
 		if (net_debug)
-			printk("%s: Rx unit stopped, status %04x, restarting.\n",
+			pr_debug("%s: Rx unit stopped, status %04x, restarting.\n",
 				   dev->name, status);
 		init_rx_bufs(dev);
 		writew(RX_BUF_START,shmem+iSCB_RFA);
@@ -753,9 +752,8 @@
 		int boguscnt = 50;
 		while (readw(shmem+iSCB_STATUS) == 0)
 			if (--boguscnt == 0) {
-				printk("%s: i82586 initialization timed out with status %04x, "
-					   "cmd %04x.\n", dev->name,
-					   readw(shmem+iSCB_STATUS), readw(shmem+iSCB_CMD));
+				pr_warning("%s: i82586 initialization timed out with status %04x, cmd %04x.\n",
+					dev->name, readw(shmem+iSCB_STATUS), readw(shmem+iSCB_CMD));
 				break;
 			}
 		/* Issue channel-attn -- the 82586 won't start. */
@@ -765,7 +763,7 @@
 	/* Disable loopback and enable interrupts. */
 	outb(0x84, ioaddr + MISC_CTRL);
 	if (net_debug > 4)
-		printk("%s: Initialized 82586, status %04x.\n", dev->name,
+		pr_debug("%s: Initialized 82586, status %04x.\n", dev->name,
 			   readw(shmem+iSCB_STATUS));
 	return;
 }
@@ -810,7 +808,7 @@
 		lp->tx_head = TX_BUF_START;
 
 	if (net_debug > 4) {
-		printk("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n",
+		pr_debug("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n",
 			   dev->name, ioaddr, length, tx_block, lp->tx_head);
 	}
 
@@ -838,7 +836,7 @@
 
 		if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22
 			|| (pkt_len & 0xC000) != 0xC000) {
-			printk(KERN_ERR "%s: Rx frame at %#x corrupted, "
+			pr_err("%s: Rx frame at %#x corrupted, "
 			       "status %04x cmd %04x next %04x "
 			       "data-buf @%04x %04x.\n",
 			       dev->name, rx_head, frame_status, rfd_cmd,
@@ -858,8 +856,7 @@
 			pkt_len &= 0x3fff;
 			skb = dev_alloc_skb(pkt_len+2);
 			if (skb == NULL) {
-				printk(KERN_ERR "%s: Memory squeeze, "
-				       "dropping packet.\n",
+				pr_err("%s: Memory squeeze, dropping packet.\n",
 				       dev->name);
 				dev->stats.rx_dropped++;
 				break;
@@ -926,7 +923,7 @@
 int __init init_module(void)
 {
 	if (io == 0)
-		printk("3c507: You should not use auto-probing with insmod!\n");
+		pr_notice("3c507: You should not use auto-probing with insmod!\n");
 	dev_3c507 = el16_probe(-1);
 	return IS_ERR(dev_3c507) ? PTR_ERR(dev_3c507) : 0;
 }
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index 393e4e7..8d9aa49 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -257,7 +257,7 @@
 			    && !memcmp(phys_addr, el3_devs[i]->dev_addr,
 				       ETH_ALEN)) {
 				if (el3_debug > 3)
-					printk(KERN_DEBUG "3c509 with address %02x %02x %02x %02x %02x %02x was found by ISAPnP\n",
+					pr_debug("3c509 with address %02x %02x %02x %02x %02x %02x was found by ISAPnP\n",
 						phys_addr[0] & 0xff, phys_addr[0] >> 8,
 						phys_addr[1] & 0xff, phys_addr[1] >> 8,
 						phys_addr[2] & 0xff, phys_addr[2] >> 8);
@@ -574,19 +574,18 @@
 
 	err = register_netdev(dev);
 	if (err) {
-		printk(KERN_ERR "Failed to register 3c5x9 at %#3.3lx, IRQ %d.\n",
+		pr_err("Failed to register 3c5x9 at %#3.3lx, IRQ %d.\n",
 			dev->base_addr, dev->irq);
 		release_region(dev->base_addr, EL3_IO_EXTENT);
 		return err;
 	}
 
-	printk(KERN_INFO "%s: 3c5x9 found at %#3.3lx, %s port, "
-	       "address %pM, IRQ %d.\n",
+	pr_info("%s: 3c5x9 found at %#3.3lx, %s port, address %pM, IRQ %d.\n",
 	       dev->name, dev->base_addr, if_names[(dev->if_port & 0x03)],
 	       dev->dev_addr, dev->irq);
 
 	if (el3_debug > 0)
-		printk(KERN_INFO "%s", version);
+		pr_info("%s", version);
 	return 0;
 
 }
@@ -625,8 +624,8 @@
 	irq = pos5 & 0x0f;
 
 
-	printk(KERN_INFO "3c529: found %s at slot %d\n",
-		   el3_mca_adapter_names[mdev->index], slot + 1);
+	pr_info("3c529: found %s at slot %d\n",
+		el3_mca_adapter_names[mdev->index], slot + 1);
 
 	/* claim the slot */
 	strncpy(mdev->name, el3_mca_adapter_names[mdev->index],
@@ -638,7 +637,7 @@
 	irq = mca_device_transform_irq(mdev, irq);
 	ioaddr = mca_device_transform_ioport(mdev, ioaddr);
 	if (el3_debug > 2) {
-			printk(KERN_DEBUG "3c529: irq %d  ioaddr 0x%x  ifport %d\n", irq, ioaddr, if_port);
+		pr_debug("3c529: irq %d  ioaddr 0x%x  ifport %d\n", irq, ioaddr, if_port);
 	}
 	EL3WINDOW(0);
 	for (i = 0; i < 3; i++)
@@ -761,7 +760,7 @@
 		word = (word << 1) + (inb(id_port) & 0x01);
 
 	if (el3_debug > 3)
-		printk(KERN_DEBUG "  3c509 EEPROM word %d %#4.4x.\n", index, word);
+		pr_debug("  3c509 EEPROM word %d %#4.4x.\n", index, word);
 
 	return word;
 }
@@ -783,13 +782,13 @@
 
 	EL3WINDOW(0);
 	if (el3_debug > 3)
-		printk(KERN_DEBUG "%s: Opening, IRQ %d	 status@%x %4.4x.\n", dev->name,
+		pr_debug("%s: Opening, IRQ %d	 status@%x %4.4x.\n", dev->name,
 			   dev->irq, ioaddr + EL3_STATUS, inw(ioaddr + EL3_STATUS));
 
 	el3_up(dev);
 
 	if (el3_debug > 3)
-		printk(KERN_DEBUG "%s: Opened 3c509  IRQ %d  status %4.4x.\n",
+		pr_debug("%s: Opened 3c509  IRQ %d  status %4.4x.\n",
 			   dev->name, dev->irq, inw(ioaddr + EL3_STATUS));
 
 	return 0;
@@ -801,8 +800,7 @@
 	int ioaddr = dev->base_addr;
 
 	/* Transmitter timeout, serious problems. */
-	printk(KERN_WARNING "%s: transmit timed out, Tx_status %2.2x status %4.4x "
-		   "Tx FIFO room %d.\n",
+	pr_warning("%s: transmit timed out, Tx_status %2.2x status %4.4x Tx FIFO room %d.\n",
 		   dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS),
 		   inw(ioaddr + TX_FREE));
 	dev->stats.tx_errors++;
@@ -826,7 +824,7 @@
 	dev->stats.tx_bytes += skb->len;
 
 	if (el3_debug > 4) {
-		printk(KERN_DEBUG "%s: el3_start_xmit(length = %u) called, status %4.4x.\n",
+		pr_debug("%s: el3_start_xmit(length = %u) called, status %4.4x.\n",
 			   dev->name, skb->len, inw(ioaddr + EL3_STATUS));
 	}
 #if 0
@@ -835,7 +833,7 @@
 		ushort status = inw(ioaddr + EL3_STATUS);
 		if (status & 0x0001 		/* IRQ line active, missed one. */
 			&& inw(ioaddr + EL3_STATUS) & 1) { 			/* Make sure. */
-			printk(KERN_DEBUG "%s: Missed interrupt, status then %04x now %04x"
+			pr_debug("%s: Missed interrupt, status then %04x now %04x"
 				   "  Tx %2.2x Rx %4.4x.\n", dev->name, status,
 				   inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS),
 				   inw(ioaddr + RX_STATUS));
@@ -909,7 +907,7 @@
 
 	if (el3_debug > 4) {
 		status = inw(ioaddr + EL3_STATUS);
-		printk(KERN_DEBUG "%s: interrupt, status %4.4x.\n", dev->name, status);
+		pr_debug("%s: interrupt, status %4.4x.\n", dev->name, status);
 	}
 
 	while ((status = inw(ioaddr + EL3_STATUS)) &
@@ -920,7 +918,7 @@
 
 		if (status & TxAvailable) {
 			if (el3_debug > 5)
-				printk(KERN_DEBUG "	TX room bit was handled.\n");
+				pr_debug("	TX room bit was handled.\n");
 			/* There's room in the FIFO for a full-sized packet. */
 			outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
 			netif_wake_queue (dev);
@@ -958,7 +956,7 @@
 		}
 
 		if (--i < 0) {
-			printk(KERN_ERR "%s: Infinite loop in interrupt, status %4.4x.\n",
+			pr_err("%s: Infinite loop in interrupt, status %4.4x.\n",
 				   dev->name, status);
 			/* Clear all interrupts. */
 			outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
@@ -969,7 +967,7 @@
 	}
 
 	if (el3_debug > 4) {
-		printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n", dev->name,
+		pr_debug("%s: exiting interrupt, status %4.4x.\n", dev->name,
 			   inw(ioaddr + EL3_STATUS));
 	}
 	spin_unlock(&lp->lock);
@@ -1017,7 +1015,7 @@
 	int ioaddr = dev->base_addr;
 
 	if (el3_debug > 5)
-		printk("   Updating the statistics.\n");
+		pr_debug("   Updating the statistics.\n");
 	/* Turn off statistics updates while reading. */
 	outw(StatsDisable, ioaddr + EL3_CMD);
 	/* Switch to the stats window, and read everything. */
@@ -1047,7 +1045,7 @@
 	short rx_status;
 
 	if (el3_debug > 5)
-		printk("   In rx_packet(), status %4.4x, rx_status %4.4x.\n",
+		pr_debug("   In rx_packet(), status %4.4x, rx_status %4.4x.\n",
 			   inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS));
 	while ((rx_status = inw(ioaddr + RX_STATUS)) > 0) {
 		if (rx_status & 0x4000) { /* Error, update stats. */
@@ -1069,7 +1067,7 @@
 
 			skb = dev_alloc_skb(pkt_len+5);
 			if (el3_debug > 4)
-				printk("Receiving packet size %d status %4.4x.\n",
+				pr_debug("Receiving packet size %d status %4.4x.\n",
 					   pkt_len, rx_status);
 			if (skb != NULL) {
 				skb_reserve(skb, 2);     /* Align IP on 16 byte */
@@ -1088,12 +1086,12 @@
 			outw(RxDiscard, ioaddr + EL3_CMD);
 			dev->stats.rx_dropped++;
 			if (el3_debug)
-				printk("%s: Couldn't allocate a sk_buff of size %d.\n",
+				pr_debug("%s: Couldn't allocate a sk_buff of size %d.\n",
 					   dev->name, pkt_len);
 		}
 		inw(ioaddr + EL3_STATUS); 				/* Delay. */
 		while (inw(ioaddr + EL3_STATUS) & 0x1000)
-			printk(KERN_DEBUG "	Waiting for 3c509 to discard packet, status %x.\n",
+			pr_debug("	Waiting for 3c509 to discard packet, status %x.\n",
 				   inw(ioaddr + EL3_STATUS) );
 	}
 
@@ -1114,7 +1112,7 @@
 		static int old;
 		if (old != dev->mc_count) {
 			old = dev->mc_count;
-			printk("%s: Setting Rx mode to %d addresses.\n", dev->name, dev->mc_count);
+			pr_debug("%s: Setting Rx mode to %d addresses.\n", dev->name, dev->mc_count);
 		}
 	}
 	spin_lock_irqsave(&lp->lock, flags);
@@ -1137,7 +1135,7 @@
 	struct el3_private *lp = netdev_priv(dev);
 
 	if (el3_debug > 2)
-		printk("%s: Shutting down ethercard.\n", dev->name);
+		pr_debug("%s: Shutting down ethercard.\n", dev->name);
 
 	el3_down(dev);
 
@@ -1384,30 +1382,30 @@
 		EL3WINDOW(4);
 		net_diag = inw(ioaddr + WN4_NETDIAG);
 		net_diag = (net_diag | FD_ENABLE); /* temporarily assume full-duplex will be set */
-		printk("%s: ", dev->name);
+		pr_info("%s: ", dev->name);
 		switch (dev->if_port & 0x0c) {
 			case 12:
 				/* force full-duplex mode if 3c5x9b */
 				if (sw_info & 0x000f) {
-					printk("Forcing 3c5x9b full-duplex mode");
+					pr_cont("Forcing 3c5x9b full-duplex mode");
 					break;
 				}
 			case 8:
 				/* set full-duplex mode based on eeprom config setting */
 				if ((sw_info & 0x000f) && (sw_info & 0x8000)) {
-					printk("Setting 3c5x9b full-duplex mode (from EEPROM configuration bit)");
+					pr_cont("Setting 3c5x9b full-duplex mode (from EEPROM configuration bit)");
 					break;
 				}
 			default:
 				/* xcvr=(0 || 4) OR user has an old 3c5x9 non "B" model */
-				printk("Setting 3c5x9/3c5x9B half-duplex mode");
+				pr_cont("Setting 3c5x9/3c5x9B half-duplex mode");
 				net_diag = (net_diag & ~FD_ENABLE); /* disable full duplex */
 		}
 
 		outw(net_diag, ioaddr + WN4_NETDIAG);
-		printk(" if_port: %d, sw_info: %4.4x\n", dev->if_port, sw_info);
+		pr_cont(" if_port: %d, sw_info: %4.4x\n", dev->if_port, sw_info);
 		if (el3_debug > 3)
-			printk("%s: 3c5x9 net diag word is now: %4.4x.\n", dev->name, net_diag);
+			pr_debug("%s: 3c5x9 net diag word is now: %4.4x.\n", dev->name, net_diag);
 		/* Enable link beat and jabber check. */
 		outw(inw(ioaddr + WN4_MEDIA) | MEDIA_TP, ioaddr + WN4_MEDIA);
 	}
@@ -1535,7 +1533,7 @@
 	}
 	if (id_port >= 0x200) {
 		id_port = 0;
-		printk(KERN_ERR "No I/O port available for 3c509 activation.\n");
+		pr_err("No I/O port available for 3c509 activation.\n");
 	} else {
 		ret = isa_register_driver(&el3_isa_driver, EL3_MAX_CARDS);
 		if (!ret)
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index 167bf23..7fd0ff7 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -420,7 +420,7 @@
 	if (debug >= 0)
 		corkscrew_debug = debug;
 	if (corkscrew_debug)
-		printk(version);
+		pr_debug("%s", version);
 	while (corkscrew_scan(-1))
 		found++;
 	return found ? 0 : -ENODEV;
@@ -437,7 +437,7 @@
 
 	if (corkscrew_debug > 0 && !printed) {
 		printed = 1;
-		printk(version);
+		pr_debug("%s", version);
 	}
 
 	return dev;
@@ -516,7 +516,7 @@
 			if (pnp_device_attach(idev) < 0)
 				continue;
 			if (pnp_activate_dev(idev) < 0) {
-				printk("pnp activate failed (out of resources?)\n");
+				pr_warning("pnp activate failed (out of resources?)\n");
 				pnp_device_detach(idev);
 				continue;
 			}
@@ -531,9 +531,9 @@
 				continue;
 			}
 			if(corkscrew_debug)
-				printk ("ISAPNP reports %s at i/o 0x%x, irq %d\n",
+				pr_debug("ISAPNP reports %s at i/o 0x%x, irq %d\n",
 					(char*) corkscrew_isapnp_adapters[i].driver_data, ioaddr, irq);
-			printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
+			pr_info("3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
 		     		inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
 			/* irq = inw(ioaddr + 0x2002) & 15; */ /* Use the irq from isapnp */
 			SET_NETDEV_DEV(dev, &idev->dev);
@@ -552,7 +552,7 @@
 		if (!check_device(ioaddr))
 			continue;
 
-		printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
+		pr_info("3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
 		     inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
 		err = corkscrew_setup(dev, ioaddr, NULL, cards_found++);
 		if (!err)
@@ -625,7 +625,7 @@
 	list_add(&vp->list, &root_corkscrew_dev);
 #endif
 
-	printk(KERN_INFO "%s: 3Com %s at %#3x,", dev->name, vp->product_name, ioaddr);
+	pr_info("%s: 3Com %s at %#3x,", dev->name, vp->product_name, ioaddr);
 
 	spin_lock_init(&vp->lock);
 
@@ -648,19 +648,19 @@
 	}
 	checksum = (checksum ^ (checksum >> 8)) & 0xff;
 	if (checksum != 0x00)
-		printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
-	printk(" %pM", dev->dev_addr);
+		pr_cont(" ***INVALID CHECKSUM %4.4x*** ", checksum);
+	pr_cont(" %pM", dev->dev_addr);
 	if (eeprom[16] == 0x11c7) {	/* Corkscrew */
 		if (request_dma(dev->dma, "3c515")) {
-			printk(", DMA %d allocation failed", dev->dma);
+			pr_cont(", DMA %d allocation failed", dev->dma);
 			dev->dma = 0;
 		} else
-			printk(", DMA %d", dev->dma);
+			pr_cont(", DMA %d", dev->dma);
 	}
-	printk(", IRQ %d\n", dev->irq);
+	pr_cont(", IRQ %d\n", dev->irq);
 	/* Tell them about an invalid IRQ. */
 	if (corkscrew_debug && (dev->irq <= 0 || dev->irq > 15))
-		printk(KERN_WARNING " *** Warning: this IRQ is unlikely to work! ***\n");
+		pr_warning(" *** Warning: this IRQ is unlikely to work! ***\n");
 
 	{
 		char *ram_split[] = { "5:3", "3:1", "1:1", "3:5" };
@@ -669,9 +669,9 @@
 		vp->available_media = inw(ioaddr + Wn3_Options);
 		config = inl(ioaddr + Wn3_Config);
 		if (corkscrew_debug > 1)
-			printk(KERN_INFO "  Internal config register is %4.4x, transceivers %#x.\n",
+			pr_info("  Internal config register is %4.4x, transceivers %#x.\n",
 				config, inw(ioaddr + Wn3_Options));
-		printk(KERN_INFO "  %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
+		pr_info("  %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
 			8 << config & Ram_size,
 			config & Ram_width ? "word" : "byte",
 			ram_split[(config & Ram_split) >> Ram_split_shift],
@@ -682,7 +682,7 @@
 		dev->if_port = vp->default_media;
 	}
 	if (vp->media_override != 7) {
-		printk(KERN_INFO "  Media override to transceiver type %d (%s).\n",
+		pr_info("  Media override to transceiver type %d (%s).\n",
 		       vp->media_override,
 		       media_tbl[vp->media_override].name);
 		dev->if_port = vp->media_override;
@@ -718,7 +718,7 @@
 
 	if (vp->media_override != 7) {
 		if (corkscrew_debug > 1)
-			printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n",
+			pr_info("%s: Media override to transceiver %d (%s).\n",
 				dev->name, vp->media_override,
 				media_tbl[vp->media_override].name);
 		dev->if_port = vp->media_override;
@@ -729,7 +729,7 @@
 			dev->if_port = media_tbl[dev->if_port].next;
 
 		if (corkscrew_debug > 1)
-			printk("%s: Initial media type %s.\n",
+			pr_debug("%s: Initial media type %s.\n",
 			       dev->name, media_tbl[dev->if_port].name);
 
 		init_timer(&vp->timer);
@@ -744,7 +744,7 @@
 	outl(config, ioaddr + Wn3_Config);
 
 	if (corkscrew_debug > 1) {
-		printk("%s: corkscrew_open() InternalConfig %8.8x.\n",
+		pr_debug("%s: corkscrew_open() InternalConfig %8.8x.\n",
 		       dev->name, config);
 	}
 
@@ -777,7 +777,7 @@
 
 	if (corkscrew_debug > 1) {
 		EL3WINDOW(4);
-		printk("%s: corkscrew_open() irq %d media status %4.4x.\n",
+		pr_debug("%s: corkscrew_open() irq %d media status %4.4x.\n",
 		       dev->name, dev->irq, inw(ioaddr + Wn4_Media));
 	}
 
@@ -814,8 +814,7 @@
 	if (vp->full_bus_master_rx) {	/* Boomerang bus master. */
 		vp->cur_rx = vp->dirty_rx = 0;
 		if (corkscrew_debug > 2)
-			printk("%s:  Filling in the Rx ring.\n",
-			       dev->name);
+			pr_debug("%s:  Filling in the Rx ring.\n", dev->name);
 		for (i = 0; i < RX_RING_SIZE; i++) {
 			struct sk_buff *skb;
 			if (i < (RX_RING_SIZE - 1))
@@ -877,7 +876,7 @@
 	int ok = 0;
 
 	if (corkscrew_debug > 1)
-		printk("%s: Media selection timer tick happened, %s.\n",
+		pr_debug("%s: Media selection timer tick happened, %s.\n",
 		       dev->name, media_tbl[dev->if_port].name);
 
 	spin_lock_irqsave(&vp->lock, flags);
@@ -894,12 +893,12 @@
 			if (media_status & Media_LnkBeat) {
 				ok = 1;
 				if (corkscrew_debug > 1)
-					printk("%s: Media %s has link beat, %x.\n",
+					pr_debug("%s: Media %s has link beat, %x.\n",
 						dev->name,
 						media_tbl[dev->if_port].name,
 						media_status);
 			} else if (corkscrew_debug > 1)
-				printk("%s: Media %s is has no link beat, %x.\n",
+				pr_debug("%s: Media %s is has no link beat, %x.\n",
 					dev->name,
 					media_tbl[dev->if_port].name,
 					media_status);
@@ -907,7 +906,7 @@
 			break;
 		default:	/* Other media types handled by Tx timeouts. */
 			if (corkscrew_debug > 1)
-				printk("%s: Media %s is has no indication, %x.\n",
+				pr_debug("%s: Media %s is has no indication, %x.\n",
 					dev->name,
 					media_tbl[dev->if_port].name,
 					media_status);
@@ -925,12 +924,12 @@
 			if (dev->if_port == 8) {	/* Go back to default. */
 				dev->if_port = vp->default_media;
 				if (corkscrew_debug > 1)
-					printk("%s: Media selection failing, using default %s port.\n",
+					pr_debug("%s: Media selection failing, using default %s port.\n",
 						dev->name,
 						media_tbl[dev->if_port].name);
 			} else {
 				if (corkscrew_debug > 1)
-					printk("%s: Media selection failed, now trying %s port.\n",
+					pr_debug("%s: Media selection failed, now trying %s port.\n",
 						dev->name,
 						media_tbl[dev->if_port].name);
 				vp->timer.expires = jiffies + media_tbl[dev->if_port].wait;
@@ -953,7 +952,7 @@
 
 	spin_unlock_irqrestore(&vp->lock, flags);
 	if (corkscrew_debug > 1)
-		printk("%s: Media selection timer finished, %s.\n",
+		pr_debug("%s: Media selection timer finished, %s.\n",
 		       dev->name, media_tbl[dev->if_port].name);
 
 #endif				/* AUTOMEDIA */
@@ -966,23 +965,21 @@
 	struct corkscrew_private *vp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
-	printk(KERN_WARNING
-	       "%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
+	pr_warning("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
 	       dev->name, inb(ioaddr + TxStatus),
 	       inw(ioaddr + EL3_STATUS));
 	/* Slight code bloat to be user friendly. */
 	if ((inb(ioaddr + TxStatus) & 0x88) == 0x88)
-		printk(KERN_WARNING
-		       "%s: Transmitter encountered 16 collisions -- network"
+		pr_warning("%s: Transmitter encountered 16 collisions --"
 		       " network cable problem?\n", dev->name);
 #ifndef final_version
-	printk("  Flags; bus-master %d, full %d; dirty %d current %d.\n",
+	pr_debug("  Flags; bus-master %d, full %d; dirty %d current %d.\n",
 	       vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx,
 	       vp->cur_tx);
-	printk("  Down list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr),
+	pr_debug("  Down list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr),
 	       &vp->tx_ring[0]);
 	for (i = 0; i < TX_RING_SIZE; i++) {
-		printk("  %d: %p  length %8.8x status %8.8x\n", i,
+		pr_debug("  %d: %p  length %8.8x status %8.8x\n", i,
 		       &vp->tx_ring[i],
 		       vp->tx_ring[i].length, vp->tx_ring[i].status);
 	}
@@ -1023,7 +1020,7 @@
 		else
 			prev_entry = NULL;
 		if (corkscrew_debug > 3)
-			printk("%s: Trying to send a packet, Tx index %d.\n",
+			pr_debug("%s: Trying to send a packet, Tx index %d.\n",
 				dev->name, vp->cur_tx);
 		/* vp->tx_full = 1; */
 		vp->tx_skbuff[entry] = skb;
@@ -1102,7 +1099,7 @@
 		while (--i > 0 && (tx_status = inb(ioaddr + TxStatus)) > 0) {
 			if (tx_status & 0x3C) {	/* A Tx-disabling error occurred.  */
 				if (corkscrew_debug > 2)
-					printk("%s: Tx error, status %2.2x.\n",
+					pr_debug("%s: Tx error, status %2.2x.\n",
 						dev->name, tx_status);
 				if (tx_status & 0x04)
 					dev->stats.tx_fifo_errors++;
@@ -1143,7 +1140,7 @@
 	status = inw(ioaddr + EL3_STATUS);
 
 	if (corkscrew_debug > 4)
-		printk("%s: interrupt, status %4.4x, timer %d.\n",
+		pr_debug("%s: interrupt, status %4.4x, timer %d.\n",
 			dev->name, status, latency);
 	if ((status & 0xE000) != 0xE000) {
 		static int donedidthis;
@@ -1151,7 +1148,7 @@
 		   Ignore a single early interrupt, but don't hang the machine for
 		   other interrupt problems. */
 		if (donedidthis++ > 100) {
-			printk(KERN_ERR "%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n",
+			pr_err("%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n",
 				   dev->name, status, netif_running(dev));
 			free_irq(dev->irq, dev);
 			dev->irq = -1;
@@ -1160,14 +1157,14 @@
 
 	do {
 		if (corkscrew_debug > 5)
-			printk("%s: In interrupt loop, status %4.4x.\n",
+			pr_debug("%s: In interrupt loop, status %4.4x.\n",
 			       dev->name, status);
 		if (status & RxComplete)
 			corkscrew_rx(dev);
 
 		if (status & TxAvailable) {
 			if (corkscrew_debug > 5)
-				printk("	TX room bit was handled.\n");
+				pr_debug("	TX room bit was handled.\n");
 			/* There's room in the FIFO for a full-sized packet. */
 			outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
 			netif_wake_queue(dev);
@@ -1212,19 +1209,20 @@
 			if (status & StatsFull) {	/* Empty statistics. */
 				static int DoneDidThat;
 				if (corkscrew_debug > 4)
-					printk("%s: Updating stats.\n", dev->name);
+					pr_debug("%s: Updating stats.\n", dev->name);
 				update_stats(ioaddr, dev);
 				/* DEBUG HACK: Disable statistics as an interrupt source. */
 				/* This occurs when we have the wrong media type! */
 				if (DoneDidThat == 0 && inw(ioaddr + EL3_STATUS) & StatsFull) {
 					int win, reg;
-					printk("%s: Updating stats failed, disabling stats as an"
-					     " interrupt source.\n", dev->name);
+					pr_notice("%s: Updating stats failed, disabling stats as an interrupt source.\n",
+						dev->name);
 					for (win = 0; win < 8; win++) {
 						EL3WINDOW(win);
-						printk("\n Vortex window %d:", win);
+						pr_notice("Vortex window %d:", win);
 						for (reg = 0; reg < 16; reg++)
-							printk(" %2.2x", inb(ioaddr + reg));
+							pr_cont(" %2.2x", inb(ioaddr + reg));
+						pr_cont("\n");
 					}
 					EL3WINDOW(7);
 					outw(SetIntrEnb | TxAvailable |
@@ -1246,9 +1244,8 @@
 		}
 
 		if (--i < 0) {
-			printk(KERN_ERR "%s: Too much work in interrupt, status %4.4x.  "
-			     "Disabling functions (%4.4x).\n", dev->name,
-			     status, SetStatusEnb | ((~status) & 0x7FE));
+			pr_err("%s: Too much work in interrupt, status %4.4x. Disabling functions (%4.4x).\n",
+				dev->name, status, SetStatusEnb | ((~status) & 0x7FE));
 			/* Disable all pending interrupts. */
 			outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD);
 			outw(AckIntr | 0x7FF, ioaddr + EL3_CMD);
@@ -1262,7 +1259,7 @@
 	spin_unlock(&lp->lock);
 
 	if (corkscrew_debug > 4)
-		printk("%s: exiting interrupt, status %4.4x.\n", dev->name, status);
+		pr_debug("%s: exiting interrupt, status %4.4x.\n", dev->name, status);
 	return IRQ_HANDLED;
 }
 
@@ -1273,13 +1270,13 @@
 	short rx_status;
 
 	if (corkscrew_debug > 5)
-		printk("   In rx_packet(), status %4.4x, rx_status %4.4x.\n",
+		pr_debug("   In rx_packet(), status %4.4x, rx_status %4.4x.\n",
 		     inw(ioaddr + EL3_STATUS), inw(ioaddr + RxStatus));
 	while ((rx_status = inw(ioaddr + RxStatus)) > 0) {
 		if (rx_status & 0x4000) {	/* Error, update stats. */
 			unsigned char rx_error = inb(ioaddr + RxErrors);
 			if (corkscrew_debug > 2)
-				printk(" Rx error: status %2.2x.\n",
+				pr_debug(" Rx error: status %2.2x.\n",
 				       rx_error);
 			dev->stats.rx_errors++;
 			if (rx_error & 0x01)
@@ -1299,7 +1296,7 @@
 
 			skb = dev_alloc_skb(pkt_len + 5 + 2);
 			if (corkscrew_debug > 4)
-				printk("Receiving packet size %d status %4.4x.\n",
+				pr_debug("Receiving packet size %d status %4.4x.\n",
 				     pkt_len, rx_status);
 			if (skb != NULL) {
 				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
@@ -1318,7 +1315,7 @@
 						break;
 				continue;
 			} else if (corkscrew_debug)
-				printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len);
+				pr_debug("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len);
 		}
 		outw(RxDiscard, ioaddr + EL3_CMD);
 		dev->stats.rx_dropped++;
@@ -1338,13 +1335,13 @@
 	int rx_status;
 
 	if (corkscrew_debug > 5)
-		printk("   In boomerang_rx(), status %4.4x, rx_status %4.4x.\n",
+		pr_debug("   In boomerang_rx(), status %4.4x, rx_status %4.4x.\n",
 			inw(ioaddr + EL3_STATUS), inw(ioaddr + RxStatus));
 	while ((rx_status = vp->rx_ring[entry].status) & RxDComplete) {
 		if (rx_status & RxDError) {	/* Error, update stats. */
 			unsigned char rx_error = rx_status >> 16;
 			if (corkscrew_debug > 2)
-				printk(" Rx error: status %2.2x.\n",
+				pr_debug(" Rx error: status %2.2x.\n",
 				       rx_error);
 			dev->stats.rx_errors++;
 			if (rx_error & 0x01)
@@ -1364,7 +1361,7 @@
 
 			dev->stats.rx_bytes += pkt_len;
 			if (corkscrew_debug > 4)
-				printk("Receiving packet size %d status %4.4x.\n",
+				pr_debug("Receiving packet size %d status %4.4x.\n",
 				     pkt_len, rx_status);
 
 			/* Check if the packet is long enough to just accept without
@@ -1385,7 +1382,7 @@
 				temp = skb_put(skb, pkt_len);
 				/* Remove this checking code for final release. */
 				if (isa_bus_to_virt(vp->rx_ring[entry].addr) != temp)
-					    printk("%s: Warning -- the skbuff addresses do not match"
+					pr_warning("%s: Warning -- the skbuff addresses do not match"
 					     " in boomerang_rx: %p vs. %p / %p.\n",
 					     dev->name,
 					     isa_bus_to_virt(vp->
@@ -1427,12 +1424,11 @@
 	netif_stop_queue(dev);
 
 	if (corkscrew_debug > 1) {
-		printk("%s: corkscrew_close() status %4.4x, Tx status %2.2x.\n",
+		pr_debug("%s: corkscrew_close() status %4.4x, Tx status %2.2x.\n",
 		     dev->name, inw(ioaddr + EL3_STATUS),
 		     inb(ioaddr + TxStatus));
-		printk("%s: corkscrew close stats: rx_nocopy %d rx_copy %d"
-		       " tx_queued %d.\n", dev->name, rx_nocopy, rx_copy,
-		       queued_packet);
+		pr_debug("%s: corkscrew close stats: rx_nocopy %d rx_copy %d tx_queued %d.\n",
+			dev->name, rx_nocopy, rx_copy, queued_packet);
 	}
 
 	del_timer(&vp->timer);
@@ -1534,7 +1530,7 @@
 
 	if (dev->flags & IFF_PROMISC) {
 		if (corkscrew_debug > 3)
-			printk("%s: Setting promiscuous mode.\n",
+			pr_debug("%s: Setting promiscuous mode.\n",
 			       dev->name);
 		new_mode = SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm;
 	} else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) {
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index 8f734d7..cdd955c 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -176,7 +176,7 @@
     if(!p->scb->cmd) break; \
     DELAY_16(); \
     if(i == 1023) { \
-      printk(KERN_WARNING "%s:%d: scb_cmd timed out .. resetting i82586\n",\
+      pr_warning("%s:%d: scb_cmd timed out .. resetting i82586\n",\
       	dev->name,__LINE__); \
       elmc_id_reset586(); } } }
 
@@ -291,7 +291,7 @@
 	ret = request_irq(dev->irq, &elmc_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM,
 			  dev->name, dev);
 	if (ret) {
-		printk(KERN_ERR "%s: couldn't get irq %d\n", dev->name, dev->irq);
+		pr_err("%s: couldn't get irq %d\n", dev->name, dev->irq);
 		elmc_id_reset586();
 		return ret;
 	}
@@ -371,9 +371,9 @@
 
 	DELAY(2);
 
-	if (p->iscp->busy) {
-		printk(KERN_ERR "%s: Init-Problems (alloc).\n", dev->name);
-	}
+	if (p->iscp->busy)
+		pr_err("%s: Init-Problems (alloc).\n", dev->name);
+
 	memset((char *) p->scb, 0, sizeof(struct scb_struct));
 }
 
@@ -470,7 +470,7 @@
 	mca_set_adapter_procfn(slot, (MCA_ProcFn) elmc_getinfo, dev);
 
 	/* if we get this far, adapter has been found - carry on */
-	printk(KERN_INFO "%s: 3c523 adapter found in slot %d\n", dev->name, slot + 1);
+	pr_info("%s: 3c523 adapter found in slot %d\n", dev->name, slot + 1);
 
 	/* Now we extract configuration info from the card.
 	   The 3c523 provides information in two of the POS registers, but
@@ -507,7 +507,7 @@
 	memset(pr, 0, sizeof(struct priv));
 	pr->slot = slot;
 
-	printk(KERN_INFO "%s: 3Com 3c523 Rev 0x%x at %#lx\n", dev->name, (int) revision,
+	pr_info("%s: 3Com 3c523 Rev 0x%x at %#lx\n", dev->name, (int) revision,
 	       dev->base_addr);
 
 	/* Determine if we're using the on-board transceiver (i.e. coax) or
@@ -529,7 +529,7 @@
 
 	size = 0x4000;		/* check for 16K mem */
 	if (!check586(dev, dev->mem_start, size)) {
-		printk(KERN_ERR "%s: memprobe, Can't find memory at 0x%lx!\n", dev->name,
+		pr_err("%s: memprobe, Can't find memory at 0x%lx!\n", dev->name,
 		       dev->mem_start);
 		retval = -ENODEV;
 		goto err_out;
@@ -546,7 +546,7 @@
 	pr->num_recv_buffs = NUM_RECV_BUFFS_16;
 
 	/* dump all the assorted information */
-	printk(KERN_INFO "%s: IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->name,
+	pr_info("%s: IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->name,
 	       dev->irq, dev->if_port ? "ex" : "in",
 	       dev->mem_start, dev->mem_end - 1);
 
@@ -555,7 +555,7 @@
 	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = inb(dev->base_addr + i);
 
-	printk(KERN_INFO "%s: hardware address %pM\n",
+	pr_info("%s: hardware address %pM\n",
 	       dev->name, dev->dev_addr);
 
 	dev->netdev_ops = &netdev_ops;
@@ -660,7 +660,7 @@
 	}
 
 	if ((cfg_cmd->cmd_status & (STAT_OK | STAT_COMPL)) != (STAT_COMPL | STAT_OK)) {
-		printk(KERN_WARNING "%s (elmc): configure command failed: %x\n", dev->name, cfg_cmd->cmd_status);
+		pr_warning("%s (elmc): configure command failed: %x\n", dev->name, cfg_cmd->cmd_status);
 		return 1;
 	}
 	/*
@@ -686,7 +686,8 @@
 	}
 
 	if ((ias_cmd->cmd_status & (STAT_OK | STAT_COMPL)) != (STAT_OK | STAT_COMPL)) {
-		printk(KERN_WARNING "%s (elmc): individual address setup command failed: %04x\n", dev->name, ias_cmd->cmd_status);
+		pr_warning("%s (elmc): individual address setup command failed: %04x\n",
+			dev->name, ias_cmd->cmd_status);
 		return 1;
 	}
 	/*
@@ -707,7 +708,7 @@
 	s = jiffies;
 	while (!(tdr_cmd->cmd_status & STAT_COMPL)) {
 		if (time_after(jiffies, s + 30*HZ/100)) {
-			printk(KERN_WARNING "%s: %d Problems while running the TDR.\n", dev->name, __LINE__);
+			pr_warning("%s: %d Problems while running the TDR.\n", dev->name, __LINE__);
 			result = 1;
 			break;
 		}
@@ -723,14 +724,14 @@
 		if (result & TDR_LNK_OK) {
 			/* empty */
 		} else if (result & TDR_XCVR_PRB) {
-			printk(KERN_WARNING "%s: TDR: Transceiver problem!\n", dev->name);
+			pr_warning("%s: TDR: Transceiver problem!\n", dev->name);
 		} else if (result & TDR_ET_OPN) {
-			printk(KERN_WARNING "%s: TDR: No correct termination %d clocks away.\n", dev->name, result & TDR_TIMEMASK);
+			pr_warning("%s: TDR: No correct termination %d clocks away.\n", dev->name, result & TDR_TIMEMASK);
 		} else if (result & TDR_ET_SRT) {
 			if (result & TDR_TIMEMASK)	/* time == 0 -> strange :-) */
-				printk(KERN_WARNING "%s: TDR: Detected a short circuit %d clocks away.\n", dev->name, result & TDR_TIMEMASK);
+				pr_warning("%s: TDR: Detected a short circuit %d clocks away.\n", dev->name, result & TDR_TIMEMASK);
 		} else {
-			printk(KERN_WARNING "%s: TDR: Unknown status %04x\n", dev->name, result);
+			pr_warning("%s: TDR: Unknown status %04x\n", dev->name, result);
 		}
 	}
 	/*
@@ -774,11 +775,11 @@
 		/* I don't understand this: do we really need memory after the init? */
 		int len = ((char *) p->iscp - (char *) ptr - 8) / 6;
 		if (len <= 0) {
-			printk(KERN_ERR "%s: Ooooops, no memory for MC-Setup!\n", dev->name);
+			pr_err("%s: Ooooops, no memory for MC-Setup!\n", dev->name);
 		} else {
 			if (len < num_addrs) {
 				num_addrs = len;
-				printk(KERN_WARNING "%s: Sorry, can only apply %d MC-Address(es).\n",
+				pr_warning("%s: Sorry, can only apply %d MC-Address(es).\n",
 				       dev->name, num_addrs);
 			}
 			mc_cmd = (struct mcsetup_cmd_struct *) ptr;
@@ -799,7 +800,7 @@
 					break;
 			}
 			if (!(mc_cmd->cmd_status & STAT_COMPL)) {
-				printk(KERN_WARNING "%s: Can't apply multicast-address-list.\n", dev->name);
+				pr_warning("%s: Can't apply multicast-address-list.\n", dev->name);
 			}
 		}
 	}
@@ -812,7 +813,7 @@
 		p->xmit_buffs[i] = (struct tbd_struct *) ptr;	/* TBD */
 		ptr = (char *) ptr + sizeof(struct tbd_struct);
 		if ((void *) ptr > (void *) p->iscp) {
-			printk(KERN_ERR "%s: not enough shared-mem for your configuration!\n", dev->name);
+			pr_err("%s: not enough shared-mem for your configuration!\n", dev->name);
 			return 1;
 		}
 		memset((char *) (p->xmit_cmds[i]), 0, sizeof(struct transmit_cmd_struct));
@@ -936,7 +937,8 @@
 		if (stat & STAT_CNA) {
 			/* CU went 'not ready' */
 			if (netif_running(dev)) {
-				printk(KERN_WARNING "%s: oops! CU has left active state. stat: %04x/%04x.\n", dev->name, (int) stat, (int) p->scb->status);
+				pr_warning("%s: oops! CU has left active state. stat: %04x/%04x.\n",
+					dev->name, (int) stat, (int) p->scb->status);
 			}
 		}
 #endif
@@ -951,7 +953,8 @@
 				p->scb->cmd = RUC_RESUME;
 				elmc_attn586();
 			} else {
-				printk(KERN_WARNING "%s: Receiver-Unit went 'NOT READY': %04x/%04x.\n", dev->name, (int) stat, (int) p->scb->status);
+				pr_warning("%s: Receiver-Unit went 'NOT READY': %04x/%04x.\n",
+					dev->name, (int) stat, (int) p->scb->status);
 				elmc_rnr_int(dev);
 			}
 		}
@@ -995,11 +998,11 @@
 					dev->stats.rx_dropped++;
 				}
 			} else {
-				printk(KERN_WARNING "%s: received oversized frame.\n", dev->name);
+				pr_warning("%s: received oversized frame.\n", dev->name);
 				dev->stats.rx_dropped++;
 			}
 		} else {	/* frame !(ok), only with 'save-bad-frames' */
-			printk(KERN_WARNING "%s: oops! rfd-error-status: %04x\n", dev->name, status);
+			pr_warning("%s: oops! rfd-error-status: %04x\n", dev->name, status);
 			dev->stats.rx_errors++;
 		}
 		p->rfd_top->status = 0;
@@ -1028,7 +1031,7 @@
 	alloc_rfa(dev, (char *) p->rfd_first);
 	startrecv586(dev);	/* restart RU */
 
-	printk(KERN_WARNING "%s: Receive-Unit restarted. Status: %04x\n", dev->name, p->scb->status);
+	pr_warning("%s: Receive-Unit restarted. Status: %04x\n", dev->name, p->scb->status);
 
 }
 
@@ -1043,7 +1046,7 @@
 
 	status = p->xmit_cmds[p->xmit_last]->cmd_status;
 	if (!(status & STAT_COMPL)) {
-		printk(KERN_WARNING "%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name);
+		pr_warning("%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name);
 	}
 	if (status & STAT_OK) {
 		dev->stats.tx_packets++;
@@ -1051,18 +1054,18 @@
 	} else {
 		dev->stats.tx_errors++;
 		if (status & TCMD_LATECOLL) {
-			printk(KERN_WARNING "%s: late collision detected.\n", dev->name);
+			pr_warning("%s: late collision detected.\n", dev->name);
 			dev->stats.collisions++;
 		} else if (status & TCMD_NOCARRIER) {
 			dev->stats.tx_carrier_errors++;
-			printk(KERN_WARNING "%s: no carrier detected.\n", dev->name);
+			pr_warning("%s: no carrier detected.\n", dev->name);
 		} else if (status & TCMD_LOSTCTS) {
-			printk(KERN_WARNING "%s: loss of CTS detected.\n", dev->name);
+			pr_warning("%s: loss of CTS detected.\n", dev->name);
 		} else if (status & TCMD_UNDERRUN) {
 			dev->stats.tx_fifo_errors++;
-			printk(KERN_WARNING "%s: DMA underrun detected.\n", dev->name);
+			pr_warning("%s: DMA underrun detected.\n", dev->name);
 		} else if (status & TCMD_MAXCOLL) {
-			printk(KERN_WARNING "%s: Max. collisions exceeded.\n", dev->name);
+			pr_warning("%s: Max. collisions exceeded.\n", dev->name);
 			dev->stats.collisions += 16;
 		}
 	}
@@ -1099,10 +1102,11 @@
 	struct priv *p = netdev_priv(dev);
 	/* COMMAND-UNIT active? */
 	if (p->scb->status & CU_ACTIVE) {
-#ifdef DEBUG
-		printk("%s: strange ... timeout with CU active?!?\n", dev->name);
-		printk("%s: X0: %04x N0: %04x N1: %04x %d\n", dev->name, (int) p->xmit_cmds[0]->cmd_status, (int) p->nop_cmds[0]->cmd_status, (int) p->nop_cmds[1]->cmd_status, (int) p->nop_point);
-#endif
+		pr_debug("%s: strange ... timeout with CU active?!?\n", dev->name);
+		pr_debug("%s: X0: %04x N0: %04x N1: %04x %d\n", dev->name,
+			(int)p->xmit_cmds[0]->cmd_status,
+			(int)p->nop_cmds[0]->cmd_status,
+			(int)p->nop_cmds[1]->cmd_status, (int)p->nop_point);
 		p->scb->cmd = CUC_ABORT;
 		elmc_attn586();
 		WAIT_4_SCB_CMD();
@@ -1112,10 +1116,10 @@
 		WAIT_4_SCB_CMD();
 		netif_wake_queue(dev);
 	} else {
-#ifdef DEBUG
-		printk("%s: xmitter timed out, try to restart! stat: %04x\n", dev->name, p->scb->status);
-		printk("%s: command-stats: %04x %04x\n", dev->name, p->xmit_cmds[0]->cmd_status, p->xmit_cmds[1]->cmd_status);
-#endif
+		pr_debug("%s: xmitter timed out, try to restart! stat: %04x\n",
+			dev->name, p->scb->status);
+		pr_debug("%s: command-stats: %04x %04x\n", dev->name,
+			p->xmit_cmds[0]->cmd_status, p->xmit_cmds[1]->cmd_status);
 		elmc_close(dev);
 		elmc_open(dev);
 	}
@@ -1162,7 +1166,7 @@
 			break;
 		}
 		if (i == 15) {
-			printk(KERN_WARNING "%s: Can't start transmit-command.\n", dev->name);
+			pr_warning("%s: Can't start transmit-command.\n", dev->name);
 		}
 	}
 #else
@@ -1287,11 +1291,12 @@
 		free_netdev(dev);
 		if (io[this_dev]==0)
 			break;
-		printk(KERN_WARNING "3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]);
+		pr_warning("3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]);
 	}
 
 	if(found==0) {
-		if(io[0]==0) printk(KERN_NOTICE "3c523.c: No 3c523 cards found\n");
+		if (io[0]==0)
+			pr_notice("3c523.c: No 3c523 cards found\n");
 		return -ENXIO;
 	} else return 0;
 }
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index b61073c..c10ca30 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -125,8 +125,6 @@
 #define NET_DEBUG 2
 #endif
 
-#undef DEBUG_IRQ
-
 static unsigned int mc32_debug = NET_DEBUG;
 
 /* The number of low I/O ports used by the ethercard. */
@@ -351,15 +349,15 @@
 	/* Time to play MCA games */
 
 	if (mc32_debug  &&  version_printed++ == 0)
-		printk(KERN_DEBUG "%s", version);
+		pr_debug("%s", version);
 
-	printk(KERN_INFO "%s: %s found in slot %d:", dev->name, cardname, slot);
+	pr_info("%s: %s found in slot %d: ", dev->name, cardname, slot);
 
 	POS = mca_read_stored_pos(slot, 2);
 
 	if(!(POS&1))
 	{
-		printk(" disabled.\n");
+		pr_cont("disabled.\n");
 		return -ENODEV;
 	}
 
@@ -370,7 +368,7 @@
 	POS = mca_read_stored_pos(slot, 4);
 	if(!(POS&1))
 	{
-		printk("memory window disabled.\n");
+		pr_cont("memory window disabled.\n");
 		return -ENODEV;
 	}
 
@@ -379,7 +377,7 @@
 	i=(POS>>4)&3;
 	if(i==3)
 	{
-		printk("invalid memory window.\n");
+		pr_cont("invalid memory window.\n");
 		return -ENODEV;
 	}
 
@@ -392,11 +390,11 @@
 
 	if(!request_region(dev->base_addr, MC32_IO_EXTENT, cardname))
 	{
-		printk("io 0x%3lX, which is busy.\n", dev->base_addr);
+		pr_cont("io 0x%3lX, which is busy.\n", dev->base_addr);
 		return -EBUSY;
 	}
 
-	printk("io 0x%3lX irq %d mem 0x%lX (%dK)\n",
+	pr_cont("io 0x%3lX irq %d mem 0x%lX (%dK)\n",
 		dev->base_addr, dev->irq, dev->mem_start, i/1024);
 
 
@@ -416,7 +414,7 @@
 		dev->dev_addr[i] = mca_read_pos(slot,3);
 	}
 
-	printk("%s: Address %pM", dev->name, dev->dev_addr);
+	pr_info("%s: Address %pM ", dev->name, dev->dev_addr);
 
 	mca_write_pos(slot, 6, 0);
 	mca_write_pos(slot, 7, 0);
@@ -424,9 +422,9 @@
 	POS = mca_read_stored_pos(slot, 4);
 
 	if(POS&2)
-		printk(" : BNC port selected.\n");
+		pr_cont(": BNC port selected.\n");
 	else
-		printk(" : AUI port selected.\n");
+		pr_cont(": AUI port selected.\n");
 
 	POS=inb(dev->base_addr+HOST_CTRL);
 	POS|=HOST_CTRL_ATTN|HOST_CTRL_RESET;
@@ -447,7 +445,7 @@
 	err = request_irq(dev->irq, &mc32_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM, DRV_NAME, dev);
 	if (err) {
 		release_region(dev->base_addr, MC32_IO_EXTENT);
-		printk(KERN_ERR "%s: unable to get IRQ %d.\n", DRV_NAME, dev->irq);
+		pr_err("%s: unable to get IRQ %d.\n", DRV_NAME, dev->irq);
 		goto err_exit_ports;
 	}
 
@@ -463,7 +461,7 @@
 		i++;
 		if(i == 1000)
 		{
-			printk(KERN_ERR "%s: failed to boot adapter.\n", dev->name);
+			pr_err("%s: failed to boot adapter.\n", dev->name);
 			err = -ENODEV;
 			goto err_exit_irq;
 		}
@@ -475,10 +473,10 @@
 	if(base>0)
 	{
 		if(base < 0x0C)
-			printk(KERN_ERR "%s: %s%s.\n", dev->name, failures[base-1],
+			pr_err("%s: %s%s.\n", dev->name, failures[base-1],
 				base<0x0A?" test failure":"");
 		else
-			printk(KERN_ERR "%s: unknown failure %d.\n", dev->name, base);
+			pr_err("%s: unknown failure %d.\n", dev->name, base);
 		err = -ENODEV;
 		goto err_exit_irq;
 	}
@@ -494,7 +492,7 @@
 			udelay(50);
 			if(n>100)
 			{
-				printk(KERN_ERR "%s: mailbox read fail (%d).\n", dev->name, i);
+				pr_err("%s: mailbox read fail (%d).\n", dev->name, i);
 				err = -ENODEV;
 				goto err_exit_irq;
 			}
@@ -527,7 +525,7 @@
 	init_completion(&lp->execution_cmd);
 	init_completion(&lp->xceiver_cmd);
 
-	printk("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n",
+	pr_info("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n",
 		dev->name, lp->exec_box->data[12], lp->rx_len, lp->tx_len, lp->base);
 
 	dev->netdev_ops		= &netdev_ops;
@@ -939,7 +937,7 @@
 	 */
 
 	if(mc32_command(dev, 8, descnumbuffs, 4)) {
-		printk("%s: %s rejected our buffer configuration!\n",
+		pr_info("%s: %s rejected our buffer configuration!\n",
 	 	       dev->name, cardname);
 		mc32_close(dev);
 		return -ENOBUFS;
@@ -995,7 +993,7 @@
 
 static void mc32_timeout(struct net_device *dev)
 {
-	printk(KERN_WARNING "%s: transmit timed out?\n", dev->name);
+	pr_warning("%s: transmit timed out?\n", dev->name);
 	/* Try to restart the adaptor. */
 	netif_wake_queue(dev);
 }
@@ -1335,11 +1333,9 @@
 	{
 		status=inb(ioaddr+HOST_CMD);
 
-#ifdef DEBUG_IRQ
-		printk("Status TX%d RX%d EX%d OV%d BC%d\n",
+		pr_debug("Status TX%d RX%d EX%d OV%d BC%d\n",
 			(status&7), (status>>3)&7, (status>>6)&1,
 			(status>>7)&1, boguscount);
-#endif
 
 		switch(status&7)
 		{
@@ -1354,7 +1350,7 @@
 				complete(&lp->xceiver_cmd);
 				break;
 			default:
-				printk("%s: strange tx ack %d\n", dev->name, status&7);
+				pr_notice("%s: strange tx ack %d\n", dev->name, status&7);
 		}
 		status>>=3;
 		switch(status&7)
@@ -1376,7 +1372,7 @@
 				mc32_start_transceiver(dev);
 				break;
 			default:
-				printk("%s: strange rx ack %d\n",
+				pr_notice("%s: strange rx ack %d\n",
 					dev->name, status&7);
 		}
 		status>>=3;
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index c566984..a6e8a2d 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -828,14 +828,14 @@
 		pci_restore_state(pdev);
 		err = pci_enable_device(pdev);
 		if (err) {
-			printk(KERN_WARNING "%s: Could not enable device \n",
+			pr_warning("%s: Could not enable device\n",
 				dev->name);
 			return err;
 		}
 		pci_set_master(pdev);
 		if (request_irq(dev->irq, vp->full_bus_master_rx ?
 				&boomerang_interrupt : &vortex_interrupt, IRQF_SHARED, dev->name, dev)) {
-			printk(KERN_WARNING "%s: Could not reserve IRQ %d\n", dev->name, dev->irq);
+			pr_warning("%s: Could not reserve IRQ %d\n", dev->name, dev->irq);
 			pci_disable_device(pdev);
 			return -EBUSY;
 		}
@@ -894,7 +894,7 @@
 	dev = eisa_get_drvdata(edev);
 
 	if (!dev) {
-		printk("vortex_eisa_remove called for Compaq device!\n");
+		pr_err("vortex_eisa_remove called for Compaq device!\n");
 		BUG();
 	}
 
@@ -1051,7 +1051,7 @@
 	struct eisa_device *edev = NULL;
 
 	if (!printed_version) {
-		printk (version);
+		pr_info("%s", version);
 		printed_version = 1;
 	}
 
@@ -1068,7 +1068,7 @@
 	dev = alloc_etherdev(sizeof(*vp));
 	retval = -ENOMEM;
 	if (!dev) {
-		printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n");
+		pr_err(PFX "unable to allocate etherdev, aborting\n");
 		goto out;
 	}
 	SET_NETDEV_DEV(dev, gendev);
@@ -1100,9 +1100,9 @@
 
 	print_info = (vortex_debug > 1);
 	if (print_info)
-		printk (KERN_INFO "See Documentation/networking/vortex.txt\n");
+		pr_info("See Documentation/networking/vortex.txt\n");
 
-	printk(KERN_INFO "%s: 3Com %s %s at %p.\n",
+	pr_info("%s: 3Com %s %s at %p.\n",
 	       print_name,
 	       pdev ? "PCI" : "EISA",
 	       vci->name,
@@ -1144,10 +1144,9 @@
 			   chip only. */
 			pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
 			if (pci_latency < new_latency) {
-				printk(KERN_INFO "%s: Overriding PCI latency"
-					" timer (CFLT) setting of %d, new value is %d.\n",
+				pr_info("%s: Overriding PCI latency timer (CFLT) setting of %d, new value is %d.\n",
 					print_name, pci_latency, new_latency);
-					pci_write_config_byte(pdev, PCI_LATENCY_TIMER, new_latency);
+				pci_write_config_byte(pdev, PCI_LATENCY_TIMER, new_latency);
 			}
 		}
 	}
@@ -1236,17 +1235,17 @@
 		checksum = (checksum ^ (checksum >> 8)) & 0xff;
 	}
 	if ((checksum != 0x00) && !(vci->drv_flags & IS_TORNADO))
-		printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
+		pr_cont(" ***INVALID CHECKSUM %4.4x*** ", checksum);
 	for (i = 0; i < 3; i++)
 		((__be16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]);
 	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 	if (print_info)
-		printk(" %pM", dev->dev_addr);
+		pr_cont(" %pM", dev->dev_addr);
 	/* Unfortunately an all zero eeprom passes the checksum and this
 	   gets found in the wild in failure cases. Crypto is hard 8) */
 	if (!is_valid_ether_addr(dev->dev_addr)) {
 		retval = -EINVAL;
-		printk(KERN_ERR "*** EEPROM MAC address is invalid.\n");
+		pr_err("*** EEPROM MAC address is invalid.\n");
 		goto free_ring;	/* With every pack */
 	}
 	EL3WINDOW(2);
@@ -1254,17 +1253,17 @@
 		iowrite8(dev->dev_addr[i], ioaddr + i);
 
 	if (print_info)
-		printk(", IRQ %d\n", dev->irq);
+		pr_cont(", IRQ %d\n", dev->irq);
 	/* Tell them about an invalid IRQ. */
 	if (dev->irq <= 0 || dev->irq >= nr_irqs)
-		printk(KERN_WARNING " *** Warning: IRQ %d is unlikely to work! ***\n",
+		pr_warning(" *** Warning: IRQ %d is unlikely to work! ***\n",
 			   dev->irq);
 
 	EL3WINDOW(4);
 	step = (ioread8(ioaddr + Wn4_NetDiag) & 0x1e) >> 1;
 	if (print_info) {
-		printk(KERN_INFO "  product code %02x%02x rev %02x.%d date %02d-"
-			"%02d-%02d\n", eeprom[6]&0xff, eeprom[6]>>8, eeprom[0x14],
+		pr_info("  product code %02x%02x rev %02x.%d date %02d-%02d-%02d\n",
+			eeprom[6]&0xff, eeprom[6]>>8, eeprom[0x14],
 			step, (eeprom[4]>>5) & 15, eeprom[4] & 31, eeprom[4]>>9);
 	}
 
@@ -1279,8 +1278,7 @@
 		}
 
 		if (print_info) {
-			printk(KERN_INFO "%s: CardBus functions mapped "
-				"%16.16llx->%p\n",
+			pr_info("%s: CardBus functions mapped %16.16llx->%p\n",
 				print_name,
 				(unsigned long long)pci_resource_start(pdev, 2),
 				vp->cb_fn_base);
@@ -1307,7 +1305,7 @@
 	if (vp->info1 & 0x8000) {
 		vp->full_duplex = 1;
 		if (print_info)
-			printk(KERN_INFO "Full duplex capable\n");
+			pr_info("Full duplex capable\n");
 	}
 
 	{
@@ -1319,9 +1317,9 @@
 			vp->available_media = 0x40;
 		config = ioread32(ioaddr + Wn3_Config);
 		if (print_info) {
-			printk(KERN_DEBUG "  Internal config register is %4.4x, "
-				   "transceivers %#x.\n", config, ioread16(ioaddr + Wn3_Options));
-			printk(KERN_INFO "  %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
+			pr_debug("  Internal config register is %4.4x, transceivers %#x.\n",
+				config, ioread16(ioaddr + Wn3_Options));
+			pr_info("  %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
 				   8 << RAM_SIZE(config),
 				   RAM_WIDTH(config) ? "word" : "byte",
 				   ram_split[RAM_SPLIT(config)],
@@ -1336,7 +1334,7 @@
 	}
 
 	if (vp->media_override != 7) {
-		printk(KERN_INFO "%s:  Media override to transceiver type %d (%s).\n",
+		pr_info("%s:  Media override to transceiver type %d (%s).\n",
 				print_name, vp->media_override,
 				media_tbl[vp->media_override].name);
 		dev->if_port = vp->media_override;
@@ -1369,8 +1367,8 @@
 			if (mii_status  &&  mii_status != 0xffff) {
 				vp->phys[phy_idx++] = phyx;
 				if (print_info) {
-					printk(KERN_INFO "  MII transceiver found at address %d,"
-						" status %4x.\n", phyx, mii_status);
+					pr_info("  MII transceiver found at address %d, status %4x.\n",
+						phyx, mii_status);
 				}
 				if ((mii_status & 0x0040) == 0)
 					mii_preamble_required++;
@@ -1378,7 +1376,7 @@
 		}
 		mii_preamble_required--;
 		if (phy_idx == 0) {
-			printk(KERN_WARNING"  ***WARNING*** No MII transceivers found!\n");
+			pr_warning("  ***WARNING*** No MII transceivers found!\n");
 			vp->phys[0] = 24;
 		} else {
 			vp->advertising = mdio_read(dev, vp->phys[0], MII_ADVERTISE);
@@ -1394,7 +1392,7 @@
 	if (vp->capabilities & CapBusMaster) {
 		vp->full_bus_master_tx = 1;
 		if (print_info) {
-			printk(KERN_INFO "  Enabling bus-master transmits and %s receives.\n",
+			pr_info("  Enabling bus-master transmits and %s receives.\n",
 			(vp->info2 & 1) ? "early" : "whole-frame" );
 		}
 		vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2;
@@ -1414,7 +1412,7 @@
 		dev->netdev_ops =  &vortex_netdev_ops;
 
 	if (print_info) {
-		printk(KERN_INFO "%s: scatter/gather %sabled. h/w checksums %sabled\n",
+		pr_info("%s: scatter/gather %sabled. h/w checksums %sabled\n",
 				print_name,
 				(dev->features & NETIF_F_SG) ? "en":"dis",
 				(dev->features & NETIF_F_IP_CSUM) ? "en":"dis");
@@ -1442,7 +1440,7 @@
 	if (vp->must_free_region)
 		release_region(dev->base_addr, vci->io_size);
 	free_netdev(dev);
-	printk(KERN_ERR PFX "vortex_probe1 fails.  Returns %d\n", retval);
+	pr_err(PFX "vortex_probe1 fails.  Returns %d\n", retval);
 out:
 	return retval;
 }
@@ -1464,13 +1462,13 @@
 	for (i = 0; i < 100000; i++) {
 		if (!(ioread16(ioaddr + EL3_STATUS) & CmdInProgress)) {
 			if (vortex_debug > 1)
-				printk(KERN_INFO "%s: command 0x%04x took %d usecs\n",
+				pr_info("%s: command 0x%04x took %d usecs\n",
 					   dev->name, cmd, i * 10);
 			return;
 		}
 		udelay(10);
 	}
-	printk(KERN_ERR "%s: command 0x%04x did not complete! Status=0x%x\n",
+	pr_err("%s: command 0x%04x did not complete! Status=0x%x\n",
 			   dev->name, cmd, ioread16(ioaddr + EL3_STATUS));
 }
 
@@ -1480,7 +1478,7 @@
 	struct vortex_private *vp = netdev_priv(dev);
 	void __iomem *ioaddr = vp->ioaddr;
 
-	printk(KERN_INFO "%s:  setting %s-duplex.\n",
+	pr_info("%s:  setting %s-duplex.\n",
 		dev->name, (vp->full_duplex) ? "full" : "half");
 
 	EL3WINDOW(3);
@@ -1522,7 +1520,7 @@
 			pci_restore_state(VORTEX_PCI(vp));
 		err = pci_enable_device(VORTEX_PCI(vp));
 		if (err) {
-			printk(KERN_WARNING "%s: Could not enable device \n",
+			pr_warning("%s: Could not enable device\n",
 				dev->name);
 			goto err_out;
 		}
@@ -1533,14 +1531,14 @@
 	config = ioread32(ioaddr + Wn3_Config);
 
 	if (vp->media_override != 7) {
-		printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n",
+		pr_info("%s: Media override to transceiver %d (%s).\n",
 			   dev->name, vp->media_override,
 			   media_tbl[vp->media_override].name);
 		dev->if_port = vp->media_override;
 	} else if (vp->autoselect) {
 		if (vp->has_nway) {
 			if (vortex_debug > 1)
-				printk(KERN_INFO "%s: using NWAY device table, not %d\n",
+				pr_info("%s: using NWAY device table, not %d\n",
 								dev->name, dev->if_port);
 			dev->if_port = XCVR_NWAY;
 		} else {
@@ -1549,13 +1547,13 @@
 			while (! (vp->available_media & media_tbl[dev->if_port].mask))
 				dev->if_port = media_tbl[dev->if_port].next;
 			if (vortex_debug > 1)
-				printk(KERN_INFO "%s: first available media type: %s\n",
+				pr_info("%s: first available media type: %s\n",
 					dev->name, media_tbl[dev->if_port].name);
 		}
 	} else {
 		dev->if_port = vp->default_media;
 		if (vortex_debug > 1)
-			printk(KERN_INFO "%s: using default media %s\n",
+			pr_info("%s: using default media %s\n",
 				dev->name, media_tbl[dev->if_port].name);
 	}
 
@@ -1570,13 +1568,13 @@
 	vp->rx_oom_timer.function = rx_oom_timer;
 
 	if (vortex_debug > 1)
-		printk(KERN_DEBUG "%s: Initial media type %s.\n",
+		pr_debug("%s: Initial media type %s.\n",
 			   dev->name, media_tbl[dev->if_port].name);
 
 	vp->full_duplex = vp->mii.force_media;
 	config = BFINS(config, dev->if_port, 20, 4);
 	if (vortex_debug > 6)
-		printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n", config);
+		pr_debug("vortex_up(): writing 0x%x to InternalConfig\n", config);
 	iowrite32(config, ioaddr + Wn3_Config);
 
 	if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
@@ -1602,7 +1600,7 @@
 
 	if (vortex_debug > 1) {
 		EL3WINDOW(4);
-		printk(KERN_DEBUG "%s: vortex_up() irq %d media status %4.4x.\n",
+		pr_debug("%s: vortex_up() irq %d media status %4.4x.\n",
 			   dev->name, dev->irq, ioread16(ioaddr + Wn4_Media));
 	}
 
@@ -1704,13 +1702,13 @@
 	/* Use the now-standard shared IRQ implementation. */
 	if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ?
 				&boomerang_interrupt : &vortex_interrupt, IRQF_SHARED, dev->name, dev))) {
-		printk(KERN_ERR "%s: Could not reserve IRQ %d\n", dev->name, dev->irq);
+		pr_err("%s: Could not reserve IRQ %d\n", dev->name, dev->irq);
 		goto err;
 	}
 
 	if (vp->full_bus_master_rx) { /* Boomerang bus master. */
 		if (vortex_debug > 2)
-			printk(KERN_DEBUG "%s:  Filling in the Rx ring.\n", dev->name);
+			pr_debug("%s:  Filling in the Rx ring.\n", dev->name);
 		for (i = 0; i < RX_RING_SIZE; i++) {
 			struct sk_buff *skb;
 			vp->rx_ring[i].next = cpu_to_le32(vp->rx_ring_dma + sizeof(struct boom_rx_desc) * (i+1));
@@ -1728,7 +1726,7 @@
 		}
 		if (i != RX_RING_SIZE) {
 			int j;
-			printk(KERN_EMERG "%s: no memory for rx ring\n", dev->name);
+			pr_emerg("%s: no memory for rx ring\n", dev->name);
 			for (j = 0; j < i; j++) {
 				if (vp->rx_skbuff[j]) {
 					dev_kfree_skb(vp->rx_skbuff[j]);
@@ -1750,7 +1748,7 @@
 	free_irq(dev->irq, dev);
 err:
 	if (vortex_debug > 1)
-		printk(KERN_ERR "%s: vortex_open() fails: returning %d\n", dev->name, retval);
+		pr_err("%s: vortex_open() fails: returning %d\n", dev->name, retval);
 out:
 	return retval;
 }
@@ -1766,9 +1764,9 @@
 	int media_status, old_window;
 
 	if (vortex_debug > 2) {
-		printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n",
+		pr_debug("%s: Media selection timer tick happened, %s.\n",
 			   dev->name, media_tbl[dev->if_port].name);
-		printk(KERN_DEBUG "dev->watchdog_timeo=%d\n", dev->watchdog_timeo);
+		pr_debug("dev->watchdog_timeo=%d\n", dev->watchdog_timeo);
 	}
 
 	disable_irq_lockdep(dev->irq);
@@ -1781,12 +1779,12 @@
 			netif_carrier_on(dev);
 			ok = 1;
 			if (vortex_debug > 1)
-				printk(KERN_DEBUG "%s: Media %s has link beat, %x.\n",
+				pr_debug("%s: Media %s has link beat, %x.\n",
 					   dev->name, media_tbl[dev->if_port].name, media_status);
 		} else {
 			netif_carrier_off(dev);
 			if (vortex_debug > 1) {
-				printk(KERN_DEBUG "%s: Media %s has no link beat, %x.\n",
+				pr_debug("%s: Media %s has no link beat, %x.\n",
 					   dev->name, media_tbl[dev->if_port].name, media_status);
 			}
 		}
@@ -1802,7 +1800,7 @@
 		break;
 	  default:					/* Other media types handled by Tx timeouts. */
 		if (vortex_debug > 1)
-		  printk(KERN_DEBUG "%s: Media %s has no indication, %x.\n",
+		  pr_debug("%s: Media %s has no indication, %x.\n",
 				 dev->name, media_tbl[dev->if_port].name, media_status);
 		ok = 1;
 	}
@@ -1822,13 +1820,11 @@
 		if (dev->if_port == XCVR_Default) { /* Go back to default. */
 		  dev->if_port = vp->default_media;
 		  if (vortex_debug > 1)
-			printk(KERN_DEBUG "%s: Media selection failing, using default "
-				   "%s port.\n",
+			pr_debug("%s: Media selection failing, using default %s port.\n",
 				   dev->name, media_tbl[dev->if_port].name);
 		} else {
 			if (vortex_debug > 1)
-				printk(KERN_DEBUG "%s: Media selection failed, now trying "
-					   "%s port.\n",
+				pr_debug("%s: Media selection failed, now trying %s port.\n",
 					   dev->name, media_tbl[dev->if_port].name);
 			next_tick = media_tbl[dev->if_port].wait;
 		}
@@ -1843,13 +1839,13 @@
 		iowrite16(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax,
 			 ioaddr + EL3_CMD);
 		if (vortex_debug > 1)
-			printk(KERN_DEBUG "wrote 0x%08x to Wn3_Config\n", config);
+			pr_debug("wrote 0x%08x to Wn3_Config\n", config);
 		/* AKPM: FIXME: Should reset Rx & Tx here.  P60 of 3c90xc.pdf */
 	}
 
 leave_media_alone:
 	if (vortex_debug > 2)
-	  printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n",
+	  pr_debug("%s: Media selection timer finished, %s.\n",
 			 dev->name, media_tbl[dev->if_port].name);
 
 	EL3WINDOW(old_window);
@@ -1865,21 +1861,21 @@
 	struct vortex_private *vp = netdev_priv(dev);
 	void __iomem *ioaddr = vp->ioaddr;
 
-	printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
+	pr_err("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
 		   dev->name, ioread8(ioaddr + TxStatus),
 		   ioread16(ioaddr + EL3_STATUS));
 	EL3WINDOW(4);
-	printk(KERN_ERR "  diagnostics: net %04x media %04x dma %08x fifo %04x\n",
+	pr_err("  diagnostics: net %04x media %04x dma %08x fifo %04x\n",
 			ioread16(ioaddr + Wn4_NetDiag),
 			ioread16(ioaddr + Wn4_Media),
 			ioread32(ioaddr + PktStatus),
 			ioread16(ioaddr + Wn4_FIFODiag));
 	/* Slight code bloat to be user friendly. */
 	if ((ioread8(ioaddr + TxStatus) & 0x88) == 0x88)
-		printk(KERN_ERR "%s: Transmitter encountered 16 collisions --"
+		pr_err("%s: Transmitter encountered 16 collisions --"
 			   " network cable problem?\n", dev->name);
 	if (ioread16(ioaddr + EL3_STATUS) & IntLatch) {
-		printk(KERN_ERR "%s: Interrupt posted but not delivered --"
+		pr_err("%s: Interrupt posted but not delivered --"
 			   " IRQ blocked by another device?\n", dev->name);
 		/* Bad idea here.. but we might as well handle a few events. */
 		{
@@ -1903,7 +1899,7 @@
 
 	dev->stats.tx_errors++;
 	if (vp->full_bus_master_tx) {
-		printk(KERN_DEBUG "%s: Resetting the Tx ring pointer.\n", dev->name);
+		pr_debug("%s: Resetting the Tx ring pointer.\n", dev->name);
 		if (vp->cur_tx - vp->dirty_tx > 0  &&  ioread32(ioaddr + DownListPtr) == 0)
 			iowrite32(vp->tx_ring_dma + (vp->dirty_tx % TX_RING_SIZE) * sizeof(struct boom_tx_desc),
 				 ioaddr + DownListPtr);
@@ -1938,7 +1934,7 @@
 	unsigned char tx_status = 0;
 
 	if (vortex_debug > 2) {
-		printk(KERN_ERR "%s: vortex_error(), status=0x%x\n", dev->name, status);
+		pr_err("%s: vortex_error(), status=0x%x\n", dev->name, status);
 	}
 
 	if (status & TxComplete) {			/* Really "TxError" for us. */
@@ -1946,10 +1942,10 @@
 		/* Presumably a tx-timeout. We must merely re-enable. */
 		if (vortex_debug > 2
 			|| (tx_status != 0x88 && vortex_debug > 0)) {
-			printk(KERN_ERR "%s: Transmit error, Tx status register %2.2x.\n",
+			pr_err("%s: Transmit error, Tx status register %2.2x.\n",
 				   dev->name, tx_status);
 			if (tx_status == 0x82) {
-				printk(KERN_ERR "Probably a duplex mismatch.  See "
+				pr_err("Probably a duplex mismatch.  See "
 						"Documentation/networking/vortex.txt\n");
 			}
 			dump_tx_ring(dev);
@@ -1975,13 +1971,13 @@
 	if (status & StatsFull) {			/* Empty statistics. */
 		static int DoneDidThat;
 		if (vortex_debug > 4)
-			printk(KERN_DEBUG "%s: Updating stats.\n", dev->name);
+			pr_debug("%s: Updating stats.\n", dev->name);
 		update_stats(ioaddr, dev);
 		/* HACK: Disable statistics as an interrupt source. */
 		/* This occurs when we have the wrong media type! */
 		if (DoneDidThat == 0  &&
 			ioread16(ioaddr + EL3_STATUS) & StatsFull) {
-			printk(KERN_WARNING "%s: Updating statistics failed, disabling "
+			pr_warning("%s: Updating statistics failed, disabling "
 				   "stats as an interrupt source.\n", dev->name);
 			EL3WINDOW(5);
 			iowrite16(SetIntrEnb | (ioread16(ioaddr + 10) & ~StatsFull), ioaddr + EL3_CMD);
@@ -1998,7 +1994,7 @@
 		u16 fifo_diag;
 		EL3WINDOW(4);
 		fifo_diag = ioread16(ioaddr + Wn4_FIFODiag);
-		printk(KERN_ERR "%s: Host error, FIFO diagnostic register %4.4x.\n",
+		pr_err("%s: Host error, FIFO diagnostic register %4.4x.\n",
 			   dev->name, fifo_diag);
 		/* Adapter failure requires Tx/Rx reset and reinit. */
 		if (vp->full_bus_master_tx) {
@@ -2006,7 +2002,7 @@
 			/* 0x80000000 PCI master abort. */
 			/* 0x40000000 PCI target abort. */
 			if (vortex_debug)
-				printk(KERN_ERR "%s: PCI bus error, bus status %8.8x\n", dev->name, bus_status);
+				pr_err("%s: PCI bus error, bus status %8.8x\n", dev->name, bus_status);
 
 			/* In this case, blow the card away */
 			/* Must not enter D3 or we can't legally issue the reset! */
@@ -2075,7 +2071,7 @@
 		while (--i > 0	&&	(tx_status = ioread8(ioaddr + TxStatus)) > 0) {
 			if (tx_status & 0x3C) {		/* A Tx-disabling error occurred.  */
 				if (vortex_debug > 2)
-				  printk(KERN_DEBUG "%s: Tx error, status %2.2x.\n",
+				  pr_debug("%s: Tx error, status %2.2x.\n",
 						 dev->name, tx_status);
 				if (tx_status & 0x04) dev->stats.tx_fifo_errors++;
 				if (tx_status & 0x38) dev->stats.tx_aborted_errors++;
@@ -2101,14 +2097,14 @@
 	unsigned long flags;
 
 	if (vortex_debug > 6) {
-		printk(KERN_DEBUG "boomerang_start_xmit()\n");
-		printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n",
+		pr_debug("boomerang_start_xmit()\n");
+		pr_debug("%s: Trying to send a packet, Tx index %d.\n",
 			   dev->name, vp->cur_tx);
 	}
 
 	if (vp->cur_tx - vp->dirty_tx >= TX_RING_SIZE) {
 		if (vortex_debug > 0)
-			printk(KERN_WARNING "%s: BUG! Tx Ring full, refusing to send buffer.\n",
+			pr_warning("%s: BUG! Tx Ring full, refusing to send buffer.\n",
 				   dev->name);
 		netif_stop_queue(dev);
 		return 1;
@@ -2204,7 +2200,7 @@
 	status = ioread16(ioaddr + EL3_STATUS);
 
 	if (vortex_debug > 6)
-		printk("vortex_interrupt(). status=0x%4x\n", status);
+		pr_debug("vortex_interrupt(). status=0x%4x\n", status);
 
 	if ((status & IntLatch) == 0)
 		goto handler_exit;		/* No interrupt: shared IRQs cause this */
@@ -2219,19 +2215,19 @@
 		goto handler_exit;
 
 	if (vortex_debug > 4)
-		printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n",
+		pr_debug("%s: interrupt, status %4.4x, latency %d ticks.\n",
 			   dev->name, status, ioread8(ioaddr + Timer));
 
 	do {
 		if (vortex_debug > 5)
-				printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n",
+				pr_debug("%s: In interrupt loop, status %4.4x.\n",
 					   dev->name, status);
 		if (status & RxComplete)
 			vortex_rx(dev);
 
 		if (status & TxAvailable) {
 			if (vortex_debug > 5)
-				printk(KERN_DEBUG "	TX room bit was handled.\n");
+				pr_debug("	TX room bit was handled.\n");
 			/* There's room in the FIFO for a full-sized packet. */
 			iowrite16(AckIntr | TxAvailable, ioaddr + EL3_CMD);
 			netif_wake_queue (dev);
@@ -2263,8 +2259,8 @@
 		}
 
 		if (--work_done < 0) {
-			printk(KERN_WARNING "%s: Too much work in interrupt, status "
-				   "%4.4x.\n", dev->name, status);
+			pr_warning("%s: Too much work in interrupt, status %4.4x.\n",
+				dev->name, status);
 			/* Disable all pending interrupts. */
 			do {
 				vp->deferred |= status;
@@ -2281,7 +2277,7 @@
 	} while ((status = ioread16(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
 
 	if (vortex_debug > 4)
-		printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n",
+		pr_debug("%s: exiting interrupt, status %4.4x.\n",
 			   dev->name, status);
 handler_exit:
 	spin_unlock(&vp->lock);
@@ -2313,14 +2309,14 @@
 	status = ioread16(ioaddr + EL3_STATUS);
 
 	if (vortex_debug > 6)
-		printk(KERN_DEBUG "boomerang_interrupt. status=0x%4x\n", status);
+		pr_debug("boomerang_interrupt. status=0x%4x\n", status);
 
 	if ((status & IntLatch) == 0)
 		goto handler_exit;		/* No interrupt: shared IRQs can cause this */
 
 	if (status == 0xffff) {		/* h/w no longer present (hotplug)? */
 		if (vortex_debug > 1)
-			printk(KERN_DEBUG "boomerang_interrupt(1): status = 0xffff\n");
+			pr_debug("boomerang_interrupt(1): status = 0xffff\n");
 		goto handler_exit;
 	}
 
@@ -2330,16 +2326,16 @@
 	}
 
 	if (vortex_debug > 4)
-		printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n",
+		pr_debug("%s: interrupt, status %4.4x, latency %d ticks.\n",
 			   dev->name, status, ioread8(ioaddr + Timer));
 	do {
 		if (vortex_debug > 5)
-				printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n",
+				pr_debug("%s: In interrupt loop, status %4.4x.\n",
 					   dev->name, status);
 		if (status & UpComplete) {
 			iowrite16(AckIntr | UpComplete, ioaddr + EL3_CMD);
 			if (vortex_debug > 5)
-				printk(KERN_DEBUG "boomerang_interrupt->boomerang_rx\n");
+				pr_debug("boomerang_interrupt->boomerang_rx\n");
 			boomerang_rx(dev);
 		}
 
@@ -2374,7 +2370,7 @@
 					dev_kfree_skb_irq(skb);
 					vp->tx_skbuff[entry] = NULL;
 				} else {
-					printk(KERN_DEBUG "boomerang_interrupt: no skb!\n");
+					pr_debug("boomerang_interrupt: no skb!\n");
 				}
 				/* dev->stats.tx_packets++;  Counted below. */
 				dirty_tx++;
@@ -2382,7 +2378,7 @@
 			vp->dirty_tx = dirty_tx;
 			if (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1) {
 				if (vortex_debug > 6)
-					printk(KERN_DEBUG "boomerang_interrupt: wake queue\n");
+					pr_debug("boomerang_interrupt: wake queue\n");
 				netif_wake_queue (dev);
 			}
 		}
@@ -2392,8 +2388,8 @@
 			vortex_error(dev, status);
 
 		if (--work_done < 0) {
-			printk(KERN_WARNING "%s: Too much work in interrupt, status "
-				   "%4.4x.\n", dev->name, status);
+			pr_warning("%s: Too much work in interrupt, status %4.4x.\n",
+				dev->name, status);
 			/* Disable all pending interrupts. */
 			do {
 				vp->deferred |= status;
@@ -2413,7 +2409,7 @@
 	} while ((status = ioread16(ioaddr + EL3_STATUS)) & IntLatch);
 
 	if (vortex_debug > 4)
-		printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n",
+		pr_debug("%s: exiting interrupt, status %4.4x.\n",
 			   dev->name, status);
 handler_exit:
 	spin_unlock(&vp->lock);
@@ -2428,13 +2424,13 @@
 	short rx_status;
 
 	if (vortex_debug > 5)
-		printk(KERN_DEBUG "vortex_rx(): status %4.4x, rx_status %4.4x.\n",
+		pr_debug("vortex_rx(): status %4.4x, rx_status %4.4x.\n",
 			   ioread16(ioaddr+EL3_STATUS), ioread16(ioaddr+RxStatus));
 	while ((rx_status = ioread16(ioaddr + RxStatus)) > 0) {
 		if (rx_status & 0x4000) { /* Error, update stats. */
 			unsigned char rx_error = ioread8(ioaddr + RxErrors);
 			if (vortex_debug > 2)
-				printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error);
+				pr_debug(" Rx error: status %2.2x.\n", rx_error);
 			dev->stats.rx_errors++;
 			if (rx_error & 0x01)  dev->stats.rx_over_errors++;
 			if (rx_error & 0x02)  dev->stats.rx_length_errors++;
@@ -2448,7 +2444,7 @@
 
 			skb = dev_alloc_skb(pkt_len + 5);
 			if (vortex_debug > 4)
-				printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n",
+				pr_debug("Receiving packet size %d status %4.4x.\n",
 					   pkt_len, rx_status);
 			if (skb != NULL) {
 				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
@@ -2478,8 +2474,8 @@
 						break;
 				continue;
 			} else if (vortex_debug > 0)
-				printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of "
-					   "size %d.\n", dev->name, pkt_len);
+				pr_notice("%s: No memory to allocate a sk_buff of size %d.\n",
+					dev->name, pkt_len);
 			dev->stats.rx_dropped++;
 		}
 		issue_and_wait(dev, RxDiscard);
@@ -2498,7 +2494,7 @@
 	int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx;
 
 	if (vortex_debug > 5)
-		printk(KERN_DEBUG "boomerang_rx(): status %4.4x\n", ioread16(ioaddr+EL3_STATUS));
+		pr_debug("boomerang_rx(): status %4.4x\n", ioread16(ioaddr+EL3_STATUS));
 
 	while ((rx_status = le32_to_cpu(vp->rx_ring[entry].status)) & RxDComplete){
 		if (--rx_work_limit < 0)
@@ -2506,7 +2502,7 @@
 		if (rx_status & RxDError) { /* Error, update stats. */
 			unsigned char rx_error = rx_status >> 16;
 			if (vortex_debug > 2)
-				printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error);
+				pr_debug(" Rx error: status %2.2x.\n", rx_error);
 			dev->stats.rx_errors++;
 			if (rx_error & 0x01)  dev->stats.rx_over_errors++;
 			if (rx_error & 0x02)  dev->stats.rx_length_errors++;
@@ -2520,7 +2516,7 @@
 			dma_addr_t dma = le32_to_cpu(vp->rx_ring[entry].addr);
 
 			if (vortex_debug > 4)
-				printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n",
+				pr_debug("Receiving packet size %d status %4.4x.\n",
 					   pkt_len, rx_status);
 
 			/* Check if the packet is long enough to just accept without
@@ -2566,7 +2562,7 @@
 			if (skb == NULL) {
 				static unsigned long last_jif;
 				if (time_after(jiffies, last_jif + 10 * HZ)) {
-					printk(KERN_WARNING "%s: memory shortage\n", dev->name);
+					pr_warning("%s: memory shortage\n", dev->name);
 					last_jif = jiffies;
 				}
 				if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE)
@@ -2598,7 +2594,7 @@
 	if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE)	/* This test is redundant, but makes me feel good */
 		boomerang_rx(dev);
 	if (vortex_debug > 1) {
-		printk(KERN_DEBUG "%s: rx_oom_timer %s\n", dev->name,
+		pr_debug("%s: rx_oom_timer %s\n", dev->name,
 			((vp->cur_rx - vp->dirty_rx) != RX_RING_SIZE) ? "succeeded" : "retrying");
 	}
 	spin_unlock_irq(&vp->lock);
@@ -2655,9 +2651,9 @@
 		vortex_down(dev, 1);
 
 	if (vortex_debug > 1) {
-		printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
+		pr_debug("%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
 			   dev->name, ioread16(ioaddr + EL3_STATUS), ioread8(ioaddr + TxStatus));
-		printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d"
+		pr_debug("%s: vortex close stats: rx_nocopy %d rx_copy %d"
 			   " tx_queued %d Rx pre-checksummed %d.\n",
 			   dev->name, vp->rx_nocopy, vp->rx_copy, vp->queued_packet, vp->rx_csumhits);
 	}
@@ -2666,8 +2662,7 @@
 	if (vp->rx_csumhits &&
 	    (vp->drv_flags & HAS_HWCKSM) == 0 &&
 	    (vp->card_idx >= MAX_UNITS || hw_checksums[vp->card_idx] == -1)) {
-			printk(KERN_WARNING "%s supports hardware checksums, and we're "
-						"not using them!\n", dev->name);
+		pr_warning("%s supports hardware checksums, and we're not using them!\n", dev->name);
 	}
 #endif
 
@@ -2717,16 +2712,16 @@
 			int i;
 			int stalled = ioread32(ioaddr + PktStatus) & 0x04;	/* Possible racy. But it's only debug stuff */
 
-			printk(KERN_ERR "  Flags; bus-master %d, dirty %d(%d) current %d(%d)\n",
+			pr_err("  Flags; bus-master %d, dirty %d(%d) current %d(%d)\n",
 					vp->full_bus_master_tx,
 					vp->dirty_tx, vp->dirty_tx % TX_RING_SIZE,
 					vp->cur_tx, vp->cur_tx % TX_RING_SIZE);
-			printk(KERN_ERR "  Transmit list %8.8x vs. %p.\n",
+			pr_err("  Transmit list %8.8x vs. %p.\n",
 				   ioread32(ioaddr + DownListPtr),
 				   &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]);
 			issue_and_wait(dev, DownStall);
 			for (i = 0; i < TX_RING_SIZE; i++) {
-				printk(KERN_ERR "  %d: @%p  length %8.8x status %8.8x\n", i,
+				pr_err("  %d: @%p  length %8.8x status %8.8x\n", i,
 					   &vp->tx_ring[i],
 #if DO_ZEROCOPY
 					   le32_to_cpu(vp->tx_ring[i].frag[0].length),
@@ -2970,7 +2965,7 @@
 
 	if (dev->flags & IFF_PROMISC) {
 		if (vortex_debug > 3)
-			printk(KERN_NOTICE "%s: Setting promiscuous mode.\n", dev->name);
+			pr_notice("%s: Setting promiscuous mode.\n", dev->name);
 		new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm;
 	} else	if ((dev->mc_list)  ||  (dev->flags & IFF_ALLMULTI)) {
 		new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast;
@@ -3145,8 +3140,7 @@
 		iowrite16(RxEnable, ioaddr + EL3_CMD);
 
 		if (pci_enable_wake(VORTEX_PCI(vp), PCI_D3hot, 1)) {
-			printk(KERN_INFO "%s: WOL not supported.\n",
-					pci_name(VORTEX_PCI(vp)));
+			pr_info("%s: WOL not supported.\n", pci_name(VORTEX_PCI(vp)));
 
 			vp->enable_wol = 0;
 			return;
@@ -3164,7 +3158,7 @@
 	struct vortex_private *vp;
 
 	if (!dev) {
-		printk("vortex_remove_one called for Compaq device!\n");
+		pr_err("vortex_remove_one called for Compaq device!\n");
 		BUG();
 	}
 
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 02330f3..c9fc0ff 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -471,8 +471,7 @@
 			    u32 status, u32 len)
 {
 	if (netif_msg_rx_err (cp))
-		printk (KERN_DEBUG
-			"%s: rx err, slot %d status 0x%x len %d\n",
+		pr_debug("%s: rx err, slot %d status 0x%x len %d\n",
 			cp->dev->name, rx_tail, status, len);
 	cp->dev->stats.rx_errors++;
 	if (status & RxErrFrame)
@@ -547,7 +546,7 @@
 		}
 
 		if (netif_msg_rx_status(cp))
-			printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d\n",
+			pr_debug("%s: rx slot %d status 0x%x len %d\n",
 			       dev->name, rx_tail, status, len);
 
 		buflen = cp->rx_buf_sz + NET_IP_ALIGN;
@@ -626,7 +625,7 @@
 		return IRQ_NONE;
 
 	if (netif_msg_intr(cp))
-		printk(KERN_DEBUG "%s: intr, status %04x cmd %02x cpcmd %04x\n",
+		pr_debug("%s: intr, status %04x cmd %02x cpcmd %04x\n",
 		        dev->name, status, cpr8(Cmd), cpr16(CpCmd));
 
 	cpw16(IntrStatus, status & ~cp_rx_intr_mask);
@@ -658,7 +657,7 @@
 
 		pci_read_config_word(cp->pdev, PCI_STATUS, &pci_status);
 		pci_write_config_word(cp->pdev, PCI_STATUS, pci_status);
-		printk(KERN_ERR "%s: PCI bus error, status=%04x, PCI status=%04x\n",
+		pr_err("%s: PCI bus error, status=%04x, PCI status=%04x\n",
 		       dev->name, status, pci_status);
 
 		/* TODO: reset hardware */
@@ -705,7 +704,7 @@
 		if (status & LastFrag) {
 			if (status & (TxError | TxFIFOUnder)) {
 				if (netif_msg_tx_err(cp))
-					printk(KERN_DEBUG "%s: tx err, status 0x%x\n",
+					pr_debug("%s: tx err, status 0x%x\n",
 					       cp->dev->name, status);
 				cp->dev->stats.tx_errors++;
 				if (status & TxOWC)
@@ -722,7 +721,7 @@
 				cp->dev->stats.tx_packets++;
 				cp->dev->stats.tx_bytes += skb->len;
 				if (netif_msg_tx_done(cp))
-					printk(KERN_DEBUG "%s: tx done, slot %d\n", cp->dev->name, tx_tail);
+					pr_debug("%s: tx done, slot %d\n", cp->dev->name, tx_tail);
 			}
 			dev_kfree_skb_irq(skb);
 		}
@@ -755,7 +754,7 @@
 	if (TX_BUFFS_AVAIL(cp) <= (skb_shinfo(skb)->nr_frags + 1)) {
 		netif_stop_queue(dev);
 		spin_unlock_irqrestore(&cp->lock, intr_flags);
-		printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
+		pr_err(PFX "%s: BUG! Tx Ring full when queue awake!\n",
 		       dev->name);
 		return 1;
 	}
@@ -882,7 +881,7 @@
 	}
 	cp->tx_head = entry;
 	if (netif_msg_tx_queued(cp))
-		printk(KERN_DEBUG "%s: tx queued, slot %d, skblen %d\n",
+		pr_debug("%s: tx queued, slot %d, skblen %d\n",
 		       dev->name, entry, skb->len);
 	if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1))
 		netif_stop_queue(dev);
@@ -996,7 +995,7 @@
 		schedule_timeout_uninterruptible(10);
 	}
 
-	printk(KERN_ERR "%s: hardware reset timeout\n", cp->dev->name);
+	pr_err("%s: hardware reset timeout\n", cp->dev->name);
 }
 
 static inline void cp_start_hw (struct cp_private *cp)
@@ -1166,7 +1165,7 @@
 	int rc;
 
 	if (netif_msg_ifup(cp))
-		printk(KERN_DEBUG "%s: enabling interface\n", dev->name);
+		pr_debug("%s: enabling interface\n", dev->name);
 
 	rc = cp_alloc_rings(cp);
 	if (rc)
@@ -1201,7 +1200,7 @@
 	napi_disable(&cp->napi);
 
 	if (netif_msg_ifdown(cp))
-		printk(KERN_DEBUG "%s: disabling interface\n", dev->name);
+		pr_debug("%s: disabling interface\n", dev->name);
 
 	spin_lock_irqsave(&cp->lock, flags);
 
@@ -1224,7 +1223,7 @@
 	unsigned long flags;
 	int rc;
 
-	printk(KERN_WARNING "%s: Transmit timeout, status %2x %4x %4x %4x\n",
+	pr_warning("%s: Transmit timeout, status %2x %4x %4x %4x\n",
 	       dev->name, cpr8(Cmd), cpr16(CpCmd),
 	       cpr16(IntrStatus), cpr16(IntrMask));
 
@@ -1873,7 +1872,7 @@
 #ifndef MODULE
 	static int version_printed;
 	if (version_printed++ == 0)
-		printk("%s", version);
+		pr_info("%s", version);
 #endif
 
 	if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
@@ -1995,8 +1994,7 @@
 	if (rc)
 		goto err_out_iomap;
 
-	printk (KERN_INFO "%s: RTL-8139C+ at 0x%lx, "
-		"%pM, IRQ %d\n",
+	pr_info("%s: RTL-8139C+ at 0x%lx, %pM, IRQ %d\n",
 		dev->name,
 		dev->base_addr,
 		dev->dev_addr,
@@ -2113,7 +2111,7 @@
 static int __init cp_init (void)
 {
 #ifdef MODULE
-	printk("%s", version);
+	pr_info("%s", version);
 #endif
 	return pci_register_driver(&cp_driver);
 }
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index d901775..8ae72ec 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -126,19 +126,12 @@
 #undef RTL8139_NDEBUG
 
 
-#if RTL8139_DEBUG
-/* note: prints function name for you */
-#  define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
-#else
-#  define DPRINTK(fmt, args...)
-#endif
-
 #ifdef RTL8139_NDEBUG
 #  define assert(expr) do {} while (0)
 #else
 #  define assert(expr) \
         if(unlikely(!(expr))) {				        \
-        printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n",	\
+        pr_err("Assertion failed! %s,%s,%s,line=%d\n",	\
 	#expr, __FILE__, __func__, __LINE__);			\
         }
 #endif
@@ -784,8 +777,8 @@
 
 	/* set this immediately, we need to know before
 	 * we talk to the chip directly */
-	DPRINTK("PIO region size == 0x%02X\n", pio_len);
-	DPRINTK("MMIO region size == 0x%02lX\n", mmio_len);
+	pr_debug("PIO region size == 0x%02lX\n", pio_len);
+	pr_debug("MMIO region size == 0x%02lX\n", mmio_len);
 
 retry:
 	if (use_io) {
@@ -865,19 +858,17 @@
 		}
 
 	/* if unknown chip, assume array element #0, original RTL-8139 in this case */
-	dev_printk (KERN_DEBUG, &pdev->dev,
-		    "unknown chip version, assuming RTL-8139\n");
-	dev_printk (KERN_DEBUG, &pdev->dev,
-		    "TxConfig = 0x%lx\n", RTL_R32 (TxConfig));
+	dev_dbg(&pdev->dev, "unknown chip version, assuming RTL-8139\n");
+	dev_dbg(&pdev->dev, "TxConfig = 0x%lx\n", RTL_R32 (TxConfig));
 	tp->chipset = 0;
 
 match:
-	DPRINTK ("chipset id (%d) == index %d, '%s'\n",
+	pr_debug("chipset id (%d) == index %d, '%s'\n",
 		 version, i, rtl_chip_info[i].name);
 
 	if (tp->chipset >= CH_8139B) {
 		u8 new_tmp8 = tmp8 = RTL_R8 (Config1);
-		DPRINTK("PCI PM wakeup\n");
+		pr_debug("PCI PM wakeup\n");
 		if ((rtl_chip_info[tp->chipset].flags & HasLWake) &&
 		    (tmp8 & LWAKE))
 			new_tmp8 &= ~LWAKE;
@@ -896,7 +887,7 @@
 			}
 		}
 	} else {
-		DPRINTK("Old chip wakeup\n");
+		pr_debug("Old chip wakeup\n");
 		tmp8 = RTL_R8 (Config1);
 		tmp8 &= ~(SLEEP | PWRDN);
 		RTL_W8 (Config1, tmp8);
@@ -949,7 +940,7 @@
 	{
 		static int printed_version;
 		if (!printed_version++)
-			printk (KERN_INFO RTL8139_DRIVER_NAME "\n");
+			pr_info(RTL8139_DRIVER_NAME "\n");
 	}
 #endif
 
@@ -965,7 +956,7 @@
 	    pdev->device == PCI_DEVICE_ID_REALTEK_8139 &&
 	    pdev->subsystem_vendor == PCI_VENDOR_ID_ATHEROS &&
 	    pdev->subsystem_device == PCI_DEVICE_ID_REALTEK_8139) {
-		printk(KERN_INFO "8139too: OQO Model 2 detected. Forcing PIO\n");
+		pr_info("8139too: OQO Model 2 detected. Forcing PIO\n");
 		use_io = 1;
 	}
 
@@ -1018,21 +1009,20 @@
 	tp->mii.reg_num_mask = 0x1f;
 
 	/* dev is fully set up and ready to use now */
-	DPRINTK("about to register device named %s (%p)...\n", dev->name, dev);
+	pr_debug("about to register device named %s (%p)...\n", dev->name, dev);
 	i = register_netdev (dev);
 	if (i) goto err_out;
 
 	pci_set_drvdata (pdev, dev);
 
-	printk (KERN_INFO "%s: %s at 0x%lx, "
-		"%pM, IRQ %d\n",
+	pr_info("%s: %s at 0x%lx, %pM, IRQ %d\n",
 		dev->name,
 		board_info[ent->driver_data].name,
 		dev->base_addr,
 		dev->dev_addr,
 		dev->irq);
 
-	printk (KERN_DEBUG "%s:  Identified 8139 chip type '%s'\n",
+	pr_debug("%s:  Identified 8139 chip type '%s'\n",
 		dev->name, rtl_chip_info[tp->chipset].name);
 
 	/* Find the connected MII xcvrs.
@@ -1046,14 +1036,12 @@
 			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
 				u16 advertising = mdio_read(dev, phy, 4);
 				tp->phys[phy_idx++] = phy;
-				printk(KERN_INFO "%s: MII transceiver %d status 0x%4.4x "
-					   "advertising %4.4x.\n",
+				pr_info("%s: MII transceiver %d status 0x%4.4x advertising %4.4x.\n",
 					   dev->name, phy, mii_status, advertising);
 			}
 		}
 		if (phy_idx == 0) {
-			printk(KERN_INFO "%s: No MII transceivers found!  Assuming SYM "
-				   "transceiver.\n",
+			pr_info("%s: No MII transceivers found! Assuming SYM transceiver.\n",
 				   dev->name);
 			tp->phys[0] = 32;
 		}
@@ -1073,13 +1061,13 @@
 	if (board_idx < MAX_UNITS  &&  full_duplex[board_idx] > 0)
 		tp->mii.full_duplex = full_duplex[board_idx];
 	if (tp->mii.full_duplex) {
-		printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
+		pr_info("%s: Media type forced to Full Duplex.\n", dev->name);
 		/* Changing the MII-advertised media because might prevent
 		   re-connection. */
 		tp->mii.force_media = 1;
 	}
 	if (tp->default_port) {
-		printk(KERN_INFO "  Forcing %dMbps %s-duplex operation.\n",
+		pr_info("  Forcing %dMbps %s-duplex operation.\n",
 			   (option & 0x20 ? 100 : 10),
 			   (option & 0x10 ? "full" : "half"));
 		mdio_write(dev, tp->phys[0], 0,
@@ -1342,7 +1330,7 @@
 	netif_start_queue (dev);
 
 	if (netif_msg_ifup(tp))
-		printk(KERN_DEBUG "%s: rtl8139_open() ioaddr %#llx IRQ %d"
+		pr_debug("%s: rtl8139_open() ioaddr %#llx IRQ %d"
 			" GP Pins %2.2x %s-duplex.\n", dev->name,
 			(unsigned long long)pci_resource_start (tp->pci_dev, 1),
 			dev->irq, RTL_R8 (MediaStatus),
@@ -1404,7 +1392,7 @@
 		RTL_W8 (Config3, RTL_R8 (Config3) & ~Cfg3_Magic);
 	}
 
-	DPRINTK("init buffer addresses\n");
+	pr_debug("init buffer addresses\n");
 
 	/* Lock Config[01234] and BMCR register writes */
 	RTL_W8 (Cfg9346, Cfg9346_Lock);
@@ -1566,14 +1554,13 @@
 			tp->mii.full_duplex = duplex;
 
 			if (mii_lpa) {
-				printk (KERN_INFO
-					"%s: Setting %s-duplex based on MII #%d link"
+				pr_info("%s: Setting %s-duplex based on MII #%d link"
 					" partner ability of %4.4x.\n",
 					dev->name,
 					tp->mii.full_duplex ? "full" : "half",
 					tp->phys[0], mii_lpa);
 			} else {
-				printk(KERN_INFO"%s: media is unconnected, link down, or incompatible connection\n",
+				pr_info("%s: media is unconnected, link down, or incompatible connection\n",
 				       dev->name);
 			}
 #if 0
@@ -1588,11 +1575,11 @@
 
 	rtl8139_tune_twister (dev, tp);
 
-	DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n",
+	pr_debug("%s: Media selection tick, Link partner %4.4x.\n",
 		 dev->name, RTL_R16 (NWayLPAR));
-	DPRINTK ("%s:  Other registers are IntMask %4.4x IntStatus %4.4x\n",
+	pr_debug("%s:  Other registers are IntMask %4.4x IntStatus %4.4x\n",
 		 dev->name, RTL_R16 (IntrMask), RTL_R16 (IntrStatus));
-	DPRINTK ("%s:  Chip config %2.2x %2.2x.\n",
+	pr_debug("%s:  Chip config %2.2x %2.2x.\n",
 		 dev->name, RTL_R8 (Config0),
 		 RTL_R8 (Config1));
 }
@@ -1652,14 +1639,14 @@
 	int i;
 	u8 tmp8;
 
-	printk (KERN_DEBUG "%s: Transmit timeout, status %2.2x %4.4x %4.4x "
-		"media %2.2x.\n", dev->name, RTL_R8 (ChipCmd),
+	pr_debug("%s: Transmit timeout, status %2.2x %4.4x %4.4x media %2.2x.\n",
+		dev->name, RTL_R8 (ChipCmd),
 		RTL_R16(IntrStatus), RTL_R16(IntrMask), RTL_R8(MediaStatus));
 	/* Emit info to figure out what went wrong. */
-	printk (KERN_DEBUG "%s: Tx queue start entry %ld  dirty entry %ld.\n",
+	pr_debug("%s: Tx queue start entry %ld  dirty entry %ld.\n",
 		dev->name, tp->cur_tx, tp->dirty_tx);
 	for (i = 0; i < NUM_TX_DESC; i++)
-		printk (KERN_DEBUG "%s:  Tx descriptor %d is %8.8lx.%s\n",
+		pr_debug("%s:  Tx descriptor %d is %8.8lx.%s\n",
 			dev->name, i, RTL_R32 (TxStatus0 + (i * 4)),
 			i == tp->dirty_tx % NUM_TX_DESC ?
 				" (queue head)" : "");
@@ -1741,7 +1728,7 @@
 	spin_unlock_irqrestore(&tp->lock, flags);
 
 	if (netif_msg_tx_queued(tp))
-		printk (KERN_DEBUG "%s: Queued Tx packet size %u to slot %d.\n",
+		pr_debug("%s: Queued Tx packet size %u to slot %d.\n",
 			dev->name, len, entry);
 
 	return 0;
@@ -1772,7 +1759,7 @@
 		if (txstatus & (TxOutOfWindow | TxAborted)) {
 			/* There was an major error, log it. */
 			if (netif_msg_tx_err(tp))
-				printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
+				pr_debug("%s: Transmit error, Tx status %8.8x.\n",
 					dev->name, txstatus);
 			dev->stats.tx_errors++;
 			if (txstatus & TxAborted) {
@@ -1803,7 +1790,7 @@
 
 #ifndef RTL8139_NDEBUG
 	if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {
-		printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n",
+		pr_err("%s: Out-of-sync dirty pointer, %ld vs. %ld.\n",
 		        dev->name, dirty_tx, tp->cur_tx);
 		dirty_tx += NUM_TX_DESC;
 	}
@@ -1828,12 +1815,12 @@
 #endif
 
 	if (netif_msg_rx_err (tp))
-		printk(KERN_DEBUG "%s: Ethernet frame had errors, status %8.8x.\n",
+		pr_debug("%s: Ethernet frame had errors, status %8.8x.\n",
 			dev->name, rx_status);
 	dev->stats.rx_errors++;
 	if (!(rx_status & RxStatusOK)) {
 		if (rx_status & RxTooLong) {
-			DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n",
+			pr_debug("%s: Oversized Ethernet frame, status %4.4x!\n",
 			 	dev->name, rx_status);
 			/* A.C.: The chip hangs here. */
 		}
@@ -1866,7 +1853,7 @@
 			break;
 	}
 	if (tmp_work <= 0)
-		printk (KERN_WARNING PFX "rx stop wait too long\n");
+		pr_warning(PFX "rx stop wait too long\n");
 	/* restart receive */
 	tmp_work = 200;
 	while (--tmp_work > 0) {
@@ -1877,7 +1864,7 @@
 			break;
 	}
 	if (tmp_work <= 0)
-		printk (KERN_WARNING PFX "tx/rx enable wait too long\n");
+		pr_warning(PFX "tx/rx enable wait too long\n");
 
 	/* and reinitialize all rx related registers */
 	RTL_W8_F (Cfg9346, Cfg9346_Unlock);
@@ -1888,7 +1875,7 @@
 	RTL_W32 (RxConfig, tp->rx_config);
 	tp->cur_rx = 0;
 
-	DPRINTK("init buffer addresses\n");
+	pr_debug("init buffer addresses\n");
 
 	/* Lock Config[01234] and BMCR register writes */
 	RTL_W8 (Cfg9346, Cfg9346_Lock);
@@ -1942,7 +1929,7 @@
 	unsigned int cur_rx = tp->cur_rx;
 	unsigned int rx_size = 0;
 
-	DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x,"
+	pr_debug("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x,"
 		 " free to %4.4x, Cmd %2.2x.\n", dev->name, (u16)cur_rx,
 		 RTL_R16 (RxBufAddr),
 		 RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
@@ -1962,17 +1949,17 @@
 		pkt_size = rx_size - 4;
 
 		if (netif_msg_rx_status(tp))
-			printk(KERN_DEBUG "%s:  rtl8139_rx() status %4.4x, size %4.4x,"
+			pr_debug("%s:  rtl8139_rx() status %4.4x, size %4.4x,"
 				" cur %4.4x.\n", dev->name, rx_status,
 			 rx_size, cur_rx);
 #if RTL8139_DEBUG > 2
 		{
 			int i;
-			DPRINTK ("%s: Frame contents ", dev->name);
+			pr_debug("%s: Frame contents ", dev->name);
 			for (i = 0; i < 70; i++)
-				printk (" %2.2x",
+				pr_cont(" %2.2x",
 					rx_ring[ring_offset + i]);
-			printk (".\n");
+			pr_cont(".\n");
 		}
 #endif
 
@@ -1984,12 +1971,12 @@
 			if (!tp->fifo_copy_timeout)
 				tp->fifo_copy_timeout = jiffies + 2;
 			else if (time_after(jiffies, tp->fifo_copy_timeout)) {
-				DPRINTK ("%s: hung FIFO. Reset.", dev->name);
+				pr_debug("%s: hung FIFO. Reset.", dev->name);
 				rx_size = 0;
 				goto no_early_rx;
 			}
 			if (netif_msg_intr(tp)) {
-				printk(KERN_DEBUG "%s: fifo copy in progress.",
+				pr_debug("%s: fifo copy in progress.",
 				       dev->name);
 			}
 			tp->xstats.early_rx++;
@@ -2033,8 +2020,7 @@
 			netif_receive_skb (skb);
 		} else {
 			if (net_ratelimit())
-				printk (KERN_WARNING
-					"%s: Memory squeeze, dropping packet.\n",
+				pr_warning("%s: Memory squeeze, dropping packet.\n",
 					dev->name);
 			dev->stats.rx_dropped++;
 		}
@@ -2049,12 +2035,10 @@
 	if (unlikely(!received || rx_size == 0xfff0))
 		rtl8139_isr_ack(tp);
 
-#if RTL8139_DEBUG > 1
-	DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x,"
+	pr_debug("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x,"
 		 " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx,
 		 RTL_R16 (RxBufAddr),
 		 RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
-#endif
 
 	tp->cur_rx = cur_rx;
 
@@ -2075,7 +2059,7 @@
 				     void __iomem *ioaddr,
 				     int status, int link_changed)
 {
-	DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n",
+	pr_debug("%s: Abnormal interrupt, status %8.8x.\n",
 		 dev->name, status);
 
 	assert (dev != NULL);
@@ -2104,7 +2088,7 @@
 		pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status);
 		pci_write_config_word (tp->pci_dev, PCI_STATUS, pci_cmd_status);
 
-		printk (KERN_ERR "%s: PCI Bus error %4.4x.\n",
+		pr_err("%s: PCI Bus error %4.4x.\n",
 			dev->name, pci_cmd_status);
 	}
 }
@@ -2198,7 +2182,7 @@
  out:
 	spin_unlock (&tp->lock);
 
-	DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n",
+	pr_debug("%s: exiting interrupt, intr_status=%#4.4x.\n",
 		 dev->name, RTL_R16 (IntrStatus));
 	return IRQ_RETVAL(handled);
 }
@@ -2249,7 +2233,7 @@
 	napi_disable(&tp->napi);
 
 	if (netif_msg_ifdown(tp))
-		printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n",
+		pr_debug("%s: Shutting down ethercard, status was 0x%4.4x.\n",
 			dev->name, RTL_R16 (IntrStatus));
 
 	spin_lock_irqsave (&tp->lock, flags);
@@ -2527,7 +2511,7 @@
 	int i, rx_mode;
 	u32 tmp;
 
-	DPRINTK ("%s:   rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8lx.\n",
+	pr_debug("%s:   rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8lx.\n",
 			dev->name, dev->flags, RTL_R32 (RxConfig));
 
 	/* Note: do not reorder, GCC is clever about common statements. */
@@ -2643,7 +2627,7 @@
 	 * even if no 8139 board is found.
 	 */
 #ifdef MODULE
-	printk (KERN_INFO RTL8139_DRIVER_NAME "\n");
+	pr_info(RTL8139_DRIVER_NAME "\n");
 #endif
 
 	return pci_register_driver(&rtl8139_pci_driver);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 0fb446e..43a5254 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -25,15 +25,6 @@
 # that for each of the symbols.
 if NETDEVICES
 
-config COMPAT_NET_DEV_OPS
-       default y
-       bool "Enable older network device API compatibility"
-       ---help---
-          This option enables kernel compatibility with older network devices
-          that do not use net_device_ops interface.
-
-	  If unsure, say Y.
-
 config IFB
 	tristate "Intermediate Functional Block support"
 	depends on NET_CLS_ACT
@@ -525,15 +516,16 @@
 config SH_ETH
 	tristate "Renesas SuperH Ethernet support"
 	depends on SUPERH && \
-		(CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712 || CPU_SUBTYPE_SH7763 || \
-		 CPU_SUBTYPE_SH7619)
+		(CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712 || \
+		 CPU_SUBTYPE_SH7763 || CPU_SUBTYPE_SH7619 || \
+		 CPU_SUBTYPE_SH7724)
 	select CRC32
 	select MII
 	select MDIO_BITBANG
 	select PHYLIB
 	help
 	  Renesas SuperH Ethernet device driver.
-	  This driver support SH7710, SH7712, SH7763 and SH7619.
+	  This driver support SH7710, SH7712, SH7763, SH7619, and SH7724.
 
 config SUNLANCE
 	tristate "Sun LANCE support"
@@ -2360,7 +2352,7 @@
 
 config MV643XX_ETH
 	tristate "Marvell Discovery (643XX) and Orion ethernet support"
-	depends on MV64360 || MV64X60 || PPC32 || PLAT_ORION
+	depends on MV64X60 || PPC32 || PLAT_ORION
 	select INET_LRO
 	select PHYLIB
 	help
diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c
index f939e92..9832b75 100644
--- a/drivers/net/appletalk/ipddp.c
+++ b/drivers/net/appletalk/ipddp.c
@@ -39,6 +39,7 @@
 static const char version[] = KERN_INFO "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n";
 
 static struct ipddp_route *ipddp_route_list;
+static DEFINE_SPINLOCK(ipddp_route_lock);
 
 #ifdef CONFIG_IPDDP_ENCAP
 static int ipddp_mode = IPDDP_ENCAP;
@@ -50,7 +51,7 @@
 static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev);
 static int ipddp_create(struct ipddp_route *new_rt);
 static int ipddp_delete(struct ipddp_route *rt);
-static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt);
+static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt);
 static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
 
 static const struct net_device_ops ipddp_netdev_ops = {
@@ -119,6 +120,8 @@
         struct ipddp_route *rt;
         struct atalk_addr *our_addr;
 
+	spin_lock(&ipddp_route_lock);
+
 	/*
          * Find appropriate route to use, based only on IP number.
          */
@@ -127,8 +130,10 @@
                 if(rt->ip == paddr)
                         break;
         }
-        if(rt == NULL)
+        if(rt == NULL) {
+		spin_unlock(&ipddp_route_lock);
                 return 0;
+	}
 
         our_addr = atalk_find_dev_addr(rt->dev);
 
@@ -174,6 +179,8 @@
         if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0)
                 dev_kfree_skb(skb);
 
+	spin_unlock(&ipddp_route_lock);
+
         return 0;
 }
 
@@ -196,7 +203,9 @@
                 return -ENETUNREACH;
         }
 
-	if (ipddp_find_route(rt)) {
+	spin_lock_bh(&ipddp_route_lock);
+	if (__ipddp_find_route(rt)) {
+		spin_unlock_bh(&ipddp_route_lock);
 		kfree(rt);
 		return -EEXIST;
 	}
@@ -204,6 +213,8 @@
         rt->next = ipddp_route_list;
         ipddp_route_list = rt;
 
+	spin_unlock_bh(&ipddp_route_lock);
+
         return 0;
 }
 
@@ -216,6 +227,7 @@
         struct ipddp_route **r = &ipddp_route_list;
         struct ipddp_route *tmp;
 
+	spin_lock_bh(&ipddp_route_lock);
         while((tmp = *r) != NULL)
         {
                 if(tmp->ip == rt->ip
@@ -223,19 +235,21 @@
                         && tmp->at.s_node == rt->at.s_node)
                 {
                         *r = tmp->next;
+			spin_unlock_bh(&ipddp_route_lock);
                         kfree(tmp);
                         return 0;
                 }
                 r = &tmp->next;
         }
 
+	spin_unlock_bh(&ipddp_route_lock);
         return (-ENOENT);
 }
 
 /*
  * Find a routing entry, we only return a FULL match
  */
-static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt)
+static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt)
 {
         struct ipddp_route *f;
 
@@ -253,7 +267,7 @@
 static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
         struct ipddp_route __user *rt = ifr->ifr_data;
-        struct ipddp_route rcp;
+        struct ipddp_route rcp, rcp2, *rp;
 
         if(!capable(CAP_NET_ADMIN))
                 return -EPERM;
@@ -267,9 +281,19 @@
                         return (ipddp_create(&rcp));
 
                 case SIOCFINDIPDDPRT:
-                        if(copy_to_user(rt, ipddp_find_route(&rcp), sizeof(struct ipddp_route)))
-                                return -EFAULT;
-                        return 0;
+			spin_lock_bh(&ipddp_route_lock);
+			rp = __ipddp_find_route(&rcp);
+			if (rp)
+				memcpy(&rcp2, rp, sizeof(rcp2));
+			spin_unlock_bh(&ipddp_route_lock);
+
+			if (rp) {
+				if (copy_to_user(rt, &rcp2,
+						 sizeof(struct ipddp_route)))
+					return -EFAULT;
+				return 0;
+			} else
+				return -ENOENT;
 
                 case SIOCDELIPDDPRT:
                         return (ipddp_delete(&rcp));
diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c
index a740053..322c49b 100644
--- a/drivers/net/arm/ixp4xx_eth.c
+++ b/drivers/net/arm/ixp4xx_eth.c
@@ -1149,7 +1149,7 @@
 	struct net_device *dev;
 	struct eth_plat_info *plat = pdev->dev.platform_data;
 	u32 regs_phys;
-	char phy_id[BUS_ID_SIZE];
+	char phy_id[MII_BUS_ID_SIZE + 3];
 	int err;
 
 	if (!(dev = alloc_etherdev(sizeof(struct port))))
@@ -1207,7 +1207,7 @@
 	__raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control);
 	udelay(50);
 
-	snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, "0", plat->phy);
+	snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, "0", plat->phy);
 	port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link, 0,
 				   PHY_INTERFACE_MODE_MII);
 	if ((err = IS_ERR(port->phydev)))
diff --git a/drivers/net/atl1e/atl1e.h b/drivers/net/atl1e/atl1e.h
index 2bf63b4..ba48220 100644
--- a/drivers/net/atl1e/atl1e.h
+++ b/drivers/net/atl1e/atl1e.h
@@ -429,7 +429,6 @@
 	struct mii_if_info  mii;    /* MII interface info */
 	struct atl1e_hw        hw;
 	struct atl1e_hw_stats  hw_stats;
-	struct net_device_stats net_stats;
 
 	bool have_msi;
 	u32 wol;
diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c
index adac061..c271b75 100644
--- a/drivers/net/atl1e/atl1e_main.c
+++ b/drivers/net/atl1e/atl1e_main.c
@@ -1153,7 +1153,7 @@
 {
 	struct atl1e_adapter *adapter = netdev_priv(netdev);
 	struct atl1e_hw_stats  *hw_stats = &adapter->hw_stats;
-	struct net_device_stats *net_stats = &adapter->net_stats;
+	struct net_device_stats *net_stats = &netdev->stats;
 
 	net_stats->rx_packets = hw_stats->rx_ok;
 	net_stats->tx_packets = hw_stats->tx_ok;
@@ -1181,7 +1181,7 @@
 	net_stats->tx_aborted_errors = hw_stats->tx_abort_col;
 	net_stats->tx_window_errors  = hw_stats->tx_late_col;
 
-	return &adapter->net_stats;
+	return net_stats;
 }
 
 static void atl1e_update_hw_stats(struct atl1e_adapter *adapter)
@@ -1309,7 +1309,7 @@
 
 		/* link event */
 		if (status & (ISR_GPHY | ISR_MANUAL)) {
-			adapter->net_stats.tx_carrier_errors++;
+			netdev->stats.tx_carrier_errors++;
 			atl1e_link_chg_event(adapter);
 			break;
 		}
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index b70b81e..36d4d37 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -782,7 +782,7 @@
 		drop_it:
 			b44_recycle_rx(bp, cons, bp->rx_prod);
 		drop_it_no_recycle:
-			bp->stats.rx_dropped++;
+			bp->dev->stats.rx_dropped++;
 			goto next_pkt;
 		}
 
@@ -1647,7 +1647,7 @@
 static struct net_device_stats *b44_get_stats(struct net_device *dev)
 {
 	struct b44 *bp = netdev_priv(dev);
-	struct net_device_stats *nstat = &bp->stats;
+	struct net_device_stats *nstat = &dev->stats;
 	struct b44_hw_stats *hwstat = &bp->hw_stats;
 
 	/* Convert HW stats into netdevice stats. */
diff --git a/drivers/net/b44.h b/drivers/net/b44.h
index e678498..0443f68 100644
--- a/drivers/net/b44.h
+++ b/drivers/net/b44.h
@@ -384,7 +384,6 @@
 
 	struct timer_list	timer;
 
-	struct net_device_stats	stats;
 	struct b44_hw_stats	hw_stats;
 
 	struct ssb_device	*sdev;
diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c
index af305c0..cfb4198 100644
--- a/drivers/net/cpmac.c
+++ b/drivers/net/cpmac.c
@@ -202,7 +202,7 @@
 	void __iomem *regs;
 	struct mii_bus *mii_bus;
 	struct phy_device *phy;
-	char phy_name[BUS_ID_SIZE];
+	char phy_name[MII_BUS_ID_SIZE + 3];
 	int oldlink, oldspeed, oldduplex;
 	u32 msg_enable;
 	struct net_device *dev;
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h
index d8b8229..6cdb703 100644
--- a/drivers/net/e1000e/hw.h
+++ b/drivers/net/e1000e/hw.h
@@ -253,7 +253,7 @@
 #define IGP01E1000_PLHR_SS_DOWNGRADE	0x8000
 
 #define IGP01E1000_PSSR_POLARITY_REVERSED	0x0002
-#define IGP01E1000_PSSR_MDIX			0x0008
+#define IGP01E1000_PSSR_MDIX			0x0800
 #define IGP01E1000_PSSR_SPEED_MASK		0xC000
 #define IGP01E1000_PSSR_SPEED_1000MBPS		0xC000
 
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 2bb038b..4ae1d25 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -1851,8 +1851,17 @@
 
 			if (unlikely(!newskb))
 				newskb = skb;
-			else if (skb)
+			else if (skb) {
+				/*
+				 * We need to reset ->data 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_queue_head(&priv->rx_recycle, skb);
+			}
 		} else {
 			/* Increment the number of packets */
 			dev->stats.rx_packets++;
diff --git a/drivers/net/igb/e1000_phy.h b/drivers/net/igb/e1000_phy.h
index 3228a86..ebe4b61 100644
--- a/drivers/net/igb/e1000_phy.h
+++ b/drivers/net/igb/e1000_phy.h
@@ -80,7 +80,7 @@
 #define IGP02E1000_PM_D3_LPLU             0x0004 /* For all other states */
 #define IGP01E1000_PLHR_SS_DOWNGRADE      0x8000
 #define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002
-#define IGP01E1000_PSSR_MDIX              0x0008
+#define IGP01E1000_PSSR_MDIX              0x0800
 #define IGP01E1000_PSSR_SPEED_MASK        0xC000
 #define IGP01E1000_PSSR_SPEED_1000MBPS    0xC000
 #define IGP02E1000_PHY_CHANNEL_NUM        4
diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h
index 0bd7728..6e59245 100644
--- a/drivers/net/igb/e1000_regs.h
+++ b/drivers/net/igb/e1000_regs.h
@@ -142,6 +142,7 @@
 #define E1000_SYNQF(_n) (0x055FC + (4 * (_n))) /* SYN Packet Queue Fltr */
 #define E1000_ETQF(_n)  (0x05CB0 + (4 * (_n))) /* EType Queue Fltr */
 
+#define E1000_RQDPC(_n) (0x0C030 + ((_n) * 0x40))
 /* Split and Replication RX Control - RW */
 /*
  * Convenience macros
diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h
index 154c5ac..b2c98de 100644
--- a/drivers/net/igb/igb.h
+++ b/drivers/net/igb/igb.h
@@ -137,11 +137,17 @@
 	};
 };
 
-struct igb_queue_stats {
+struct igb_tx_queue_stats {
 	u64 packets;
 	u64 bytes;
 };
 
+struct igb_rx_queue_stats {
+	u64 packets;
+	u64 bytes;
+	u64 drops;
+};
+
 struct igb_ring {
 	struct igb_adapter *adapter; /* backlink */
 	void *desc;                  /* descriptor ring memory */
@@ -167,12 +173,13 @@
 	union {
 		/* TX */
 		struct {
-			struct igb_queue_stats tx_stats;
+			struct igb_tx_queue_stats tx_stats;
 			bool detect_tx_hung;
 		};
 		/* RX */
 		struct {
-			struct igb_queue_stats rx_stats;
+			struct igb_rx_queue_stats rx_stats;
+			u64 rx_queue_drops;
 			struct napi_struct napi;
 			int set_itr;
 			struct igb_ring *buddy;
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c
index b8551a5..9598ac0 100644
--- a/drivers/net/igb/igb_ethtool.c
+++ b/drivers/net/igb/igb_ethtool.c
@@ -64,6 +64,7 @@
 	{ "rx_crc_errors", IGB_STAT(stats.crcerrs) },
 	{ "rx_frame_errors", IGB_STAT(net_stats.rx_frame_errors) },
 	{ "rx_no_buffer_count", IGB_STAT(stats.rnbc) },
+	{ "rx_queue_drop_packet_count", IGB_STAT(net_stats.rx_fifo_errors) },
 	{ "rx_missed_errors", IGB_STAT(stats.mpc) },
 	{ "tx_aborted_errors", IGB_STAT(stats.ecol) },
 	{ "tx_carrier_errors", IGB_STAT(stats.tncrs) },
@@ -96,9 +97,10 @@
 };
 
 #define IGB_QUEUE_STATS_LEN \
-	((((struct igb_adapter *)netdev_priv(netdev))->num_rx_queues + \
-	 ((struct igb_adapter *)netdev_priv(netdev))->num_tx_queues) * \
-	(sizeof(struct igb_queue_stats) / sizeof(u64)))
+	(((((struct igb_adapter *)netdev_priv(netdev))->num_rx_queues)* \
+	  (sizeof(struct igb_rx_queue_stats) / sizeof(u64))) + \
+	 ((((struct igb_adapter *)netdev_priv(netdev))->num_tx_queues) * \
+	  (sizeof(struct igb_tx_queue_stats) / sizeof(u64))))
 #define IGB_GLOBAL_STATS_LEN	\
 	sizeof(igb_gstrings_stats) / sizeof(struct igb_stats)
 #define IGB_STATS_LEN (IGB_GLOBAL_STATS_LEN + IGB_QUEUE_STATS_LEN)
@@ -1960,7 +1962,8 @@
 {
 	struct igb_adapter *adapter = netdev_priv(netdev);
 	u64 *queue_stat;
-	int stat_count = sizeof(struct igb_queue_stats) / sizeof(u64);
+	int stat_count_tx = sizeof(struct igb_tx_queue_stats) / sizeof(u64);
+	int stat_count_rx = sizeof(struct igb_rx_queue_stats) / sizeof(u64);
 	int j;
 	int i;
 
@@ -1973,14 +1976,14 @@
 	for (j = 0; j < adapter->num_tx_queues; j++) {
 		int k;
 		queue_stat = (u64 *)&adapter->tx_ring[j].tx_stats;
-		for (k = 0; k < stat_count; k++)
+		for (k = 0; k < stat_count_tx; k++)
 			data[i + k] = queue_stat[k];
 		i += k;
 	}
 	for (j = 0; j < adapter->num_rx_queues; j++) {
 		int k;
 		queue_stat = (u64 *)&adapter->rx_ring[j].rx_stats;
-		for (k = 0; k < stat_count; k++)
+		for (k = 0; k < stat_count_rx; k++)
 			data[i + k] = queue_stat[k];
 		i += k;
 	}
@@ -2014,6 +2017,8 @@
 			p += ETH_GSTRING_LEN;
 			sprintf(p, "rx_queue_%u_bytes", i);
 			p += ETH_GSTRING_LEN;
+			sprintf(p, "rx_queue_%u_drops", i);
+			p += ETH_GSTRING_LEN;
 		}
 /*		BUG_ON(p - data != IGB_STATS_LEN * ETH_GSTRING_LEN); */
 		break;
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index 2ec9809..8e93750 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -3588,8 +3588,35 @@
 
 	/* Rx Errors */
 
+	if (hw->mac.type != e1000_82575) {
+		u32 rqdpc_tmp;
+		u64 rqdpc_total = 0;
+		int i;
+		/* Read out drops stats per RX queue.  Notice RQDPC (Receive
+		 * Queue Drop Packet Count) stats only gets incremented, if
+		 * the DROP_EN but it set (in the SRRCTL register for that
+		 * queue).  If DROP_EN bit is NOT set, then the some what
+		 * equivalent count is stored in RNBC (not per queue basis).
+		 * Also note the drop count is due to lack of available
+		 * descriptors.
+		 */
+		for (i = 0; i < adapter->num_rx_queues; i++) {
+			rqdpc_tmp = rd32(E1000_RQDPC(i)) & 0xFFF;
+			adapter->rx_ring[i].rx_stats.drops += rqdpc_tmp;
+			rqdpc_total += adapter->rx_ring[i].rx_stats.drops;
+		}
+		adapter->net_stats.rx_fifo_errors = rqdpc_total;
+	}
+
+	/* Note RNBC (Receive No Buffers Count) is an not an exact
+	 * drop count as the hardware FIFO might save the day.  Thats
+	 * one of the reason for saving it in rx_fifo_errors, as its
+	 * potentially not a true drop.
+	 */
+	adapter->net_stats.rx_fifo_errors += adapter->stats.rnbc;
+
 	/* RLEC on some newer hardware can be incorrect so build
-	* our own version based on RUC and ROC */
+	 * our own version based on RUC and ROC */
 	adapter->net_stats.rx_errors = adapter->stats.rxerrc +
 		adapter->stats.crcerrs + adapter->stats.algnerrc +
 		adapter->stats.ruc + adapter->stats.roc +
diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c
index afc9fe3..88e8350 100644
--- a/drivers/net/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ixgbe/ixgbe_82598.c
@@ -698,6 +698,7 @@
 static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw)
 {
 	s32 status = 0;
+	s32 phy_status = 0;
 	u32 ctrl;
 	u32 gheccr;
 	u32 i;
@@ -745,13 +746,17 @@
 		/* PHY ops must be identified and initialized prior to reset */
 
 		/* Init PHY and function pointers, perform SFP setup */
-		status = hw->phy.ops.init(hw);
-		if (status == IXGBE_ERR_SFP_NOT_SUPPORTED)
+		phy_status = hw->phy.ops.init(hw);
+		if (phy_status == IXGBE_ERR_SFP_NOT_SUPPORTED)
 			goto reset_hw_out;
+		else if (phy_status == IXGBE_ERR_SFP_NOT_PRESENT)
+			goto no_phy_reset;
+
 
 		hw->phy.ops.reset(hw);
 	}
 
+no_phy_reset:
 	/*
 	 * Prevent the PCI-E bus from from hanging by disabling PCI-E master
 	 * access and verify no pending requests before reset
@@ -811,6 +816,9 @@
 	hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr);
 
 reset_hw_out:
+	if (phy_status)
+		status = phy_status;
+
 	return status;
 }
 
diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c
index fef7397..5d27830 100644
--- a/drivers/net/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ixgbe/ixgbe_82599.c
@@ -357,7 +357,6 @@
 	}
 
 	switch (hw->device_id) {
-	case IXGBE_DEV_ID_82599:
 	case IXGBE_DEV_ID_82599_KX4:
 	case IXGBE_DEV_ID_82599_XAUI_LOM:
 		/* Default device ID is mezzanine card KX/KX4 */
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index e52798c..dff1da8 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -2599,7 +2599,10 @@
 void ixgbe_reset(struct ixgbe_adapter *adapter)
 {
 	struct ixgbe_hw *hw = &adapter->hw;
-	if (hw->mac.ops.init_hw(hw))
+	int err;
+
+	err = hw->mac.ops.init_hw(hw);
+	if (err && (err != IXGBE_ERR_SFP_NOT_PRESENT))
 		dev_err(&adapter->pdev->dev, "Hardware Error\n");
 
 	/* reprogram the RAR[0] in case user changed it. */
@@ -5167,20 +5170,7 @@
 	INIT_WORK(&adapter->sfp_config_module_task,
 	          ixgbe_sfp_config_module_task);
 
-	err = ii->get_invariants(hw);
-	if (err == IXGBE_ERR_SFP_NOT_PRESENT) {
-		/* start a kernel thread to watch for a module to arrive */
-		set_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
-		mod_timer(&adapter->sfp_timer,
-		          round_jiffies(jiffies + (2 * HZ)));
-		err = 0;
-	} else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
-		DPRINTK(PROBE, ERR, "failed to load because an "
-		        "unsupported SFP+ module type was detected.\n");
-		goto err_hw_init;
-	} else if (err) {
-		goto err_hw_init;
-	}
+	ii->get_invariants(hw);
 
 	/* setup the private structure */
 	err = ixgbe_sw_init(adapter);
@@ -5200,7 +5190,18 @@
 
 	/* reset_hw fills in the perm_addr as well */
 	err = hw->mac.ops.reset_hw(hw);
-	if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
+	if (err == IXGBE_ERR_SFP_NOT_PRESENT &&
+	    hw->mac.type == ixgbe_mac_82598EB) {
+		/*
+		 * Start a kernel thread to watch for a module to arrive.
+		 * Only do this for 82598, since 82599 will generate
+		 * interrupts on module arrival.
+		 */
+		set_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
+		mod_timer(&adapter->sfp_timer,
+			  round_jiffies(jiffies + (2 * HZ)));
+		err = 0;
+	} else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
 		dev_err(&adapter->pdev->dev, "failed to load because an "
 		        "unsupported SFP+ module type was detected.\n");
 		goto err_sw_init;
@@ -5353,7 +5354,6 @@
 
 err_register:
 	ixgbe_release_hw_control(adapter);
-err_hw_init:
 	ixgbe_clear_interrupt_scheme(adapter);
 err_sw_init:
 err_eeprom:
diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c
index 8210b49..e43d624 100644
--- a/drivers/net/ixgbe/ixgbe_phy.c
+++ b/drivers/net/ixgbe/ixgbe_phy.c
@@ -530,11 +530,22 @@
 	u8 cable_tech = 0;
 	u16 enforce_sfp = 0;
 
+	if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber) {
+		hw->phy.sfp_type = ixgbe_sfp_type_not_present;
+		status = IXGBE_ERR_SFP_NOT_PRESENT;
+		goto out;
+	}
+
 	status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER,
 	                                     &identifier);
 
-	if (status == IXGBE_ERR_SFP_NOT_PRESENT) {
+	if (status == IXGBE_ERR_SFP_NOT_PRESENT || status == IXGBE_ERR_I2C) {
+		status = IXGBE_ERR_SFP_NOT_PRESENT;
 		hw->phy.sfp_type = ixgbe_sfp_type_not_present;
+		if (hw->phy.type != ixgbe_phy_nl) {
+			hw->phy.id = 0;
+			hw->phy.type = ixgbe_phy_unknown;
+		}
 		goto out;
 	}
 
diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h
index ba3ed0f..df1f703 100644
--- a/drivers/net/ixgbe/ixgbe_type.h
+++ b/drivers/net/ixgbe/ixgbe_type.h
@@ -46,7 +46,6 @@
 #define IXGBE_DEV_ID_82598_DA_DUAL_PORT  0x10F1
 #define IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM      0x10E1
 #define IXGBE_DEV_ID_82598EB_XF_LR       0x10F4
-#define IXGBE_DEV_ID_82599               0x10D8
 #define IXGBE_DEV_ID_82599_KX4           0x10F7
 #define IXGBE_DEV_ID_82599_SFP           0x10FB
 #define IXGBE_DEV_ID_82599_XAUI_LOM      0x10FC
diff --git a/drivers/net/mlx4/en_cq.c b/drivers/net/mlx4/en_cq.c
index a276125..21786ad 100644
--- a/drivers/net/mlx4/en_cq.c
+++ b/drivers/net/mlx4/en_cq.c
@@ -89,6 +89,9 @@
 	*cq->mcq.arm_db    = 0;
 	memset(cq->buf, 0, cq->buf_size);
 
+	if (!cq->is_tx)
+		cq->size = priv->rx_ring[cq->ring].actual_size;
+
 	err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, &mdev->priv_uar,
 			    cq->wqres.db.dma, &cq->mcq, cq->vector, cq->is_tx);
 	if (err)
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c
index 7bcc49d..0cd185a 100644
--- a/drivers/net/mlx4/en_netdev.c
+++ b/drivers/net/mlx4/en_netdev.c
@@ -556,10 +556,8 @@
 	struct mlx4_en_dev *mdev = priv->mdev;
 	struct mlx4_en_cq *cq;
 	struct mlx4_en_tx_ring *tx_ring;
-	struct mlx4_en_rx_ring *rx_ring;
 	int rx_index = 0;
 	int tx_index = 0;
-	u16 stride;
 	int err = 0;
 	int i;
 	int j;
@@ -573,12 +571,15 @@
 	dev->mtu = min(dev->mtu, priv->max_mtu);
 	mlx4_en_calc_rx_buf(dev);
 	mlx4_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_skb_size);
-	stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) +
-				    DS_SIZE * priv->num_frags);
+
 	/* Configure rx cq's and rings */
+	err = mlx4_en_activate_rx_rings(priv);
+	if (err) {
+		mlx4_err(mdev, "Failed to activate RX rings\n");
+		return err;
+	}
 	for (i = 0; i < priv->rx_ring_num; i++) {
 		cq = &priv->rx_cq[i];
-		rx_ring = &priv->rx_ring[i];
 
 		err = mlx4_en_activate_cq(priv, cq);
 		if (err) {
@@ -594,20 +595,14 @@
 			goto cq_err;
 		}
 		mlx4_en_arm_cq(priv, cq);
-
+		priv->rx_ring[i].cqn = cq->mcq.cqn;
 		++rx_index;
 	}
 
-	err = mlx4_en_activate_rx_rings(priv);
-	if (err) {
-		mlx4_err(mdev, "Failed to activate RX rings\n");
-		goto cq_err;
-	}
-
 	err = mlx4_en_config_rss_steer(priv);
 	if (err) {
 		mlx4_err(mdev, "Failed configuring rss steering\n");
-		goto rx_err;
+		goto cq_err;
 	}
 
 	/* Configure tx cq's and rings */
@@ -694,12 +689,11 @@
 	}
 
 	mlx4_en_release_rss_steer(priv);
-rx_err:
-	for (i = 0; i < priv->rx_ring_num; i++)
-		mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]);
 cq_err:
 	while (rx_index--)
 		mlx4_en_deactivate_cq(priv, &priv->rx_cq[rx_index]);
+	for (i = 0; i < priv->rx_ring_num; i++)
+		mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]);
 
 	return err; /* need to close devices */
 }
diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c
index 9ee873e..6bfab6e 100644
--- a/drivers/net/mlx4/en_rx.c
+++ b/drivers/net/mlx4/en_rx.c
@@ -202,12 +202,35 @@
 	*ring->wqres.db.db = cpu_to_be32(ring->prod & 0xffff);
 }
 
+static void mlx4_en_free_rx_desc(struct mlx4_en_priv *priv,
+				 struct mlx4_en_rx_ring *ring,
+				 int index)
+{
+	struct mlx4_en_dev *mdev = priv->mdev;
+	struct skb_frag_struct *skb_frags;
+	struct mlx4_en_rx_desc *rx_desc = ring->buf + (index << ring->log_stride);
+	dma_addr_t dma;
+	int nr;
+
+	skb_frags = ring->rx_info + (index << priv->log_rx_info);
+	for (nr = 0; nr < priv->num_frags; nr++) {
+		mlx4_dbg(DRV, priv, "Freeing fragment:%d\n", nr);
+		dma = be64_to_cpu(rx_desc->data[nr].addr);
+
+		mlx4_dbg(DRV, priv, "Unmaping buffer at dma:0x%llx\n", (u64) dma);
+		pci_unmap_single(mdev->pdev, dma, skb_frags[nr].size,
+				 PCI_DMA_FROMDEVICE);
+		put_page(skb_frags[nr].page);
+	}
+}
+
 static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv)
 {
 	struct mlx4_en_dev *mdev = priv->mdev;
 	struct mlx4_en_rx_ring *ring;
 	int ring_ind;
 	int buf_ind;
+	int new_size;
 
 	for (buf_ind = 0; buf_ind < priv->prof->rx_ring_size; buf_ind++) {
 		for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) {
@@ -220,18 +243,30 @@
 						       "enough rx buffers\n");
 					return -ENOMEM;
 				} else {
-					if (netif_msg_rx_err(priv))
-						mlx4_warn(mdev,
-							  "Only %d buffers allocated\n",
-							  ring->actual_size);
-					goto out;
+					new_size = rounddown_pow_of_two(ring->actual_size);
+					mlx4_warn(mdev, "Only %d buffers allocated "
+							"reducing ring size to %d",
+						  ring->actual_size, new_size);
+					goto reduce_rings;
 				}
 			}
 			ring->actual_size++;
 			ring->prod++;
 		}
 	}
-out:
+	return 0;
+
+reduce_rings:
+	for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) {
+		ring = &priv->rx_ring[ring_ind];
+		while (ring->actual_size > new_size) {
+			ring->actual_size--;
+			ring->prod--;
+			mlx4_en_free_rx_desc(priv, ring, ring->actual_size);
+		}
+		ring->size_mask = ring->actual_size - 1;
+	}
+
 	return 0;
 }
 
@@ -255,7 +290,7 @@
 		++num;
 		++ring->prod;
 	}
-	if ((u32) (ring->prod - ring->cons) == ring->size)
+	if ((u32) (ring->prod - ring->cons) == ring->actual_size)
 		ring->full = 1;
 
 	return num;
@@ -264,33 +299,17 @@
 static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv,
 				struct mlx4_en_rx_ring *ring)
 {
-	struct mlx4_en_dev *mdev = priv->mdev;
-	struct skb_frag_struct *skb_frags;
-	struct mlx4_en_rx_desc *rx_desc;
-	dma_addr_t dma;
 	int index;
-	int nr;
 
 	mlx4_dbg(DRV, priv, "Freeing Rx buf - cons:%d prod:%d\n",
 			ring->cons, ring->prod);
 
 	/* Unmap and free Rx buffers */
-	BUG_ON((u32) (ring->prod - ring->cons) > ring->size);
+	BUG_ON((u32) (ring->prod - ring->cons) > ring->actual_size);
 	while (ring->cons != ring->prod) {
 		index = ring->cons & ring->size_mask;
-		rx_desc = ring->buf + (index << ring->log_stride);
-		skb_frags = ring->rx_info + (index << priv->log_rx_info);
 		mlx4_dbg(DRV, priv, "Processing descriptor:%d\n", index);
-
-		for (nr = 0; nr < priv->num_frags; nr++) {
-			mlx4_dbg(DRV, priv, "Freeing fragment:%d\n", nr);
-			dma = be64_to_cpu(rx_desc->data[nr].addr);
-
-			mlx4_dbg(DRV, priv, "Unmaping buffer at dma:0x%llx\n", (u64) dma);
-			pci_unmap_single(mdev->pdev, dma, skb_frags[nr].size,
-					 PCI_DMA_FROMDEVICE);
-			put_page(skb_frags[nr].page);
-		}
+		mlx4_en_free_rx_desc(priv, ring, index);
 		++ring->cons;
 	}
 }
@@ -454,7 +473,7 @@
 		mlx4_en_update_rx_prod_db(ring);
 
 		/* Configure SRQ representing the ring */
-		ring->srq.max    = ring->size;
+		ring->srq.max    = ring->actual_size;
 		ring->srq.max_gs = max_gs;
 		ring->srq.wqe_shift = ilog2(ring->stride);
 
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index c9a9aca..7e28b46 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -75,7 +75,7 @@
 #include "myri10ge_mcp.h"
 #include "myri10ge_mcp_gen_header.h"
 
-#define MYRI10GE_VERSION_STR "1.5.0-1.415"
+#define MYRI10GE_VERSION_STR "1.5.0-1.418"
 
 MODULE_DESCRIPTION("Myricom 10G driver (10GbE)");
 MODULE_AUTHOR("Maintainer: help@myri.com");
@@ -327,10 +327,6 @@
 module_param(myri10ge_debug, int, 0);
 MODULE_PARM_DESC(myri10ge_debug, "Debug level (0=none,...,16=all)");
 
-static int myri10ge_lro = 1;
-module_param(myri10ge_lro, int, S_IRUGO);
-MODULE_PARM_DESC(myri10ge_lro, "Enable large receive offload");
-
 static int myri10ge_lro_max_pkts = MYRI10GE_LRO_MAX_PKTS;
 module_param(myri10ge_lro_max_pkts, int, S_IRUGO);
 MODULE_PARM_DESC(myri10ge_lro_max_pkts,
@@ -1422,6 +1418,7 @@
 {
 	struct myri10ge_rx_done *rx_done = &ss->rx_done;
 	struct myri10ge_priv *mgp = ss->mgp;
+	struct net_device *netdev = mgp->dev;
 	unsigned long rx_bytes = 0;
 	unsigned long rx_packets = 0;
 	unsigned long rx_ok;
@@ -1455,7 +1452,7 @@
 	ss->stats.rx_packets += rx_packets;
 	ss->stats.rx_bytes += rx_bytes;
 
-	if (myri10ge_lro)
+	if (netdev->features & NETIF_F_LRO)
 		lro_flush_all(&rx_done->lro_mgr);
 
 	/* restock receive rings if needed */
@@ -3917,8 +3914,13 @@
 
 	if (dac_enabled)
 		netdev->features |= NETIF_F_HIGHDMA;
-	if (myri10ge_lro)
-		netdev->features |= NETIF_F_LRO;
+	netdev->features |= NETIF_F_LRO;
+
+	netdev->vlan_features |= mgp->features;
+	if (mgp->fw_ver_tiny < 37)
+		netdev->vlan_features &= ~NETIF_F_TSO6;
+	if (mgp->fw_ver_tiny < 32)
+		netdev->vlan_features &= ~NETIF_F_TSO;
 
 	/* make sure we can get an irq, and that MSI can be
 	 * setup (if available).  Also ensure netdev->irq
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index 2b17453..0d9de5a 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -1317,7 +1317,7 @@
 
 	err = mdio_read(np, np->phy_addr,
 			BCM8704_PHYXS_DEV_ADDR, MII_BMCR);
-	if (err < 0)
+	if (err < 0 || err == 0xffff)
 		return err;
 	err |= BMCR_RESET;
 	err = mdio_write(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR,
@@ -2042,7 +2042,7 @@
 
 	err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR,
 			BCM8704_PMD_RCV_SIGDET);
-	if (err < 0)
+	if (err < 0 || err == 0xffff)
 		goto out;
 	if (!(err & PMD_RCV_SIGDET_GLOBAL)) {
 		err = 0;
@@ -2083,8 +2083,6 @@
 
 out:
 	*link_up_p = link_up;
-	if (np->flags & NIU_FLAGS_HOTPLUG_PHY)
-		err = 0;
 	return err;
 }
 
@@ -2220,10 +2218,17 @@
 		if (phy_present != phy_present_prev) {
 			/* state change */
 			if (phy_present) {
+				/* A NEM was just plugged in */
 				np->flags |= NIU_FLAGS_HOTPLUG_PHY_PRESENT;
 				if (np->phy_ops->xcvr_init)
 					err = np->phy_ops->xcvr_init(np);
 				if (err) {
+					err = mdio_read(np, np->phy_addr,
+						BCM8704_PHYXS_DEV_ADDR, MII_BMCR);
+					if (err == 0xffff) {
+						/* No mdio, back-to-back XAUI */
+						goto out;
+					}
 					/* debounce */
 					np->flags &= ~NIU_FLAGS_HOTPLUG_PHY_PRESENT;
 				}
@@ -2234,13 +2239,21 @@
 					np->dev->name);
 			}
 		}
-		if (np->flags & NIU_FLAGS_HOTPLUG_PHY_PRESENT)
+out:
+		if (np->flags & NIU_FLAGS_HOTPLUG_PHY_PRESENT) {
 			err = link_status_10g_bcm8706(np, link_up_p);
+			if (err == 0xffff) {
+				/* No mdio, back-to-back XAUI: it is C10NEM */
+				*link_up_p = 1;
+				np->link_config.active_speed = SPEED_10000;
+				np->link_config.active_duplex = DUPLEX_FULL;
+			}
+		}
 	}
 
 	spin_unlock_irqrestore(&np->lock, flags);
 
-	return err;
+	return 0;
 }
 
 static int niu_link_status(struct niu *np, int *link_up_p)
@@ -2312,6 +2325,12 @@
 	.link_status		= link_status_10g_hotplug,
 };
 
+static const struct niu_phy_ops phy_ops_niu_10g_hotplug = {
+	.serdes_init		= serdes_init_niu_10g_fiber,
+	.xcvr_init		= xcvr_init_10g_bcm8706,
+	.link_status		= link_status_10g_hotplug,
+};
+
 static const struct niu_phy_ops phy_ops_10g_copper = {
 	.serdes_init		= serdes_init_10g,
 	.link_status		= link_status_10g, /* XXX */
@@ -2358,6 +2377,11 @@
 	.phy_addr_base	= 8,
 };
 
+static const struct niu_phy_template phy_template_niu_10g_hotplug = {
+	.ops		= &phy_ops_niu_10g_hotplug,
+	.phy_addr_base	= 8,
+};
+
 static const struct niu_phy_template phy_template_10g_copper = {
 	.ops		= &phy_ops_10g_copper,
 	.phy_addr_base	= 10,
@@ -2542,8 +2566,16 @@
 		case NIU_FLAGS_10G | NIU_FLAGS_FIBER:
 			/* 10G Fiber */
 		default:
-			tp = &phy_template_niu_10g_fiber;
-			phy_addr_off += np->port;
+			if (np->flags & NIU_FLAGS_HOTPLUG_PHY) {
+				tp = &phy_template_niu_10g_hotplug;
+				if (np->port == 0)
+					phy_addr_off = 8;
+				if (np->port == 1)
+					phy_addr_off = 12;
+			} else {
+				tp = &phy_template_niu_10g_fiber;
+				phy_addr_off += np->port;
+			}
 			break;
 		}
 	} else {
@@ -2630,11 +2662,11 @@
 		msleep(200);
 	}
 	err = niu_serdes_init(np);
-	if (err)
+	if (err && !(np->flags & NIU_FLAGS_HOTPLUG_PHY))
 		return err;
 	msleep(200);
 	err = niu_xcvr_init(np);
-	if (!err)
+	if (!err || (np->flags & NIU_FLAGS_HOTPLUG_PHY))
 		niu_link_status(np, &ignore);
 	return 0;
 }
@@ -9346,6 +9378,11 @@
 	if (model)
 		strcpy(np->vpd.model, model);
 
+	if (of_find_property(dp, "hot-swappable-phy", &prop_len)) {
+		np->flags |= (NIU_FLAGS_10G | NIU_FLAGS_FIBER |
+			NIU_FLAGS_HOTPLUG_PHY);
+	}
+
 	return 0;
 #else
 	return -EINVAL;
diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c
index 1508b12..ed63d23 100644
--- a/drivers/net/r6040.c
+++ b/drivers/net/r6040.c
@@ -401,6 +401,9 @@
 	 * we may got called by r6040_tx_timeout which has left
 	 * some unsent tx buffers */
 	iowrite16(0x01, ioaddr + MTPR);
+
+	/* Check media */
+	mii_check_media(&lp->mii_if, 1, 1);
 }
 
 static void r6040_tx_timeout(struct net_device *dev)
@@ -528,6 +531,8 @@
 			phy_dat = 0x0000;
 	}
 
+	mii_check_media(&lp->mii_if, 0, 1);
+
 	return phy_dat;
 };
 
@@ -810,7 +815,6 @@
 		lp->phy_mode = phy_mode;
 		lp->mcr0 = (lp->mcr0 & 0x7fff) | phy_mode;
 		iowrite16(lp->mcr0, ioaddr);
-		printk(KERN_INFO "Link Change %x \n", ioread16(ioaddr));
 	}
 
 	/* Timer active again */
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index fb2e50d..0ec0605 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -94,6 +94,7 @@
 #define RTL_R32(reg)		((unsigned long) readl (ioaddr + (reg)))
 
 enum mac_version {
+	RTL_GIGA_MAC_NONE   = 0x00,
 	RTL_GIGA_MAC_VER_01 = 0x01, // 8169
 	RTL_GIGA_MAC_VER_02 = 0x02, // 8169S
 	RTL_GIGA_MAC_VER_03 = 0x03, // 8110S
@@ -1300,7 +1301,8 @@
 		{ 0xfc800000, 0x00800000,	RTL_GIGA_MAC_VER_02 },
 		{ 0xfc800000, 0x00000000,	RTL_GIGA_MAC_VER_01 },
 
-		{ 0x00000000, 0x00000000,	RTL_GIGA_MAC_VER_01 }	/* Catch-all */
+		/* Catch-all */
+		{ 0x00000000, 0x00000000,	RTL_GIGA_MAC_NONE   }
 	}, *p = mac_info;
 	u32 reg;
 
@@ -1308,12 +1310,6 @@
 	while ((reg & p->mask) != p->val)
 		p++;
 	tp->mac_version = p->mac_version;
-
-	if (p->mask == 0x00000000) {
-		struct pci_dev *pdev = tp->pci_dev;
-
-		dev_info(&pdev->dev, "unknown MAC (%08x)\n", reg);
-	}
 }
 
 static void rtl8169_print_mac_version(struct rtl8169_private *tp)
@@ -1889,6 +1885,7 @@
 	u16 intr_event;
 	u16 napi_event;
 	unsigned features;
+	u8 default_ver;
 } rtl_cfg_infos [] = {
 	[RTL_CFG_0] = {
 		.hw_start	= rtl_hw_start_8169,
@@ -1897,7 +1894,8 @@
 		.intr_event	= SYSErr | LinkChg | RxOverflow |
 				  RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
 		.napi_event	= RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
-		.features	= RTL_FEATURE_GMII
+		.features	= RTL_FEATURE_GMII,
+		.default_ver	= RTL_GIGA_MAC_VER_01,
 	},
 	[RTL_CFG_1] = {
 		.hw_start	= rtl_hw_start_8168,
@@ -1906,7 +1904,8 @@
 		.intr_event	= SYSErr | LinkChg | RxOverflow |
 				  TxErr | TxOK | RxOK | RxErr,
 		.napi_event	= TxErr | TxOK | RxOK | RxOverflow,
-		.features	= RTL_FEATURE_GMII | RTL_FEATURE_MSI
+		.features	= RTL_FEATURE_GMII | RTL_FEATURE_MSI,
+		.default_ver	= RTL_GIGA_MAC_VER_11,
 	},
 	[RTL_CFG_2] = {
 		.hw_start	= rtl_hw_start_8101,
@@ -1915,7 +1914,8 @@
 		.intr_event	= SYSErr | LinkChg | RxOverflow | PCSTimeout |
 				  RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
 		.napi_event	= RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
-		.features	= RTL_FEATURE_MSI
+		.features	= RTL_FEATURE_MSI,
+		.default_ver	= RTL_GIGA_MAC_VER_13,
 	}
 };
 
@@ -2096,6 +2096,15 @@
 	/* Identify chip attached to board */
 	rtl8169_get_mac_version(tp, ioaddr);
 
+	/* Use appropriate default if unknown */
+	if (tp->mac_version == RTL_GIGA_MAC_NONE) {
+		if (netif_msg_probe(tp)) {
+			dev_notice(&pdev->dev,
+				   "unknown MAC, using family default\n");
+		}
+		tp->mac_version = cfg->default_ver;
+	}
+
 	rtl8169_print_mac_version(tp);
 
 	for (i = 0; i < ARRAY_SIZE(rtl_chip_info); i++) {
@@ -2103,13 +2112,9 @@
 			break;
 	}
 	if (i == ARRAY_SIZE(rtl_chip_info)) {
-		/* Unknown chip: assume array element #0, original RTL-8169 */
-		if (netif_msg_probe(tp)) {
-			dev_printk(KERN_DEBUG, &pdev->dev,
-				"unknown chip version, assuming %s\n",
-				rtl_chip_info[0].name);
-		}
-		i = 0;
+		dev_err(&pdev->dev,
+			"driver bug, MAC version not found in rtl_chip_info\n");
+		goto err_out_msi_5;
 	}
 	tp->chipset = i;
 
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index 3ab28bb..0709b75 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -2,7 +2,7 @@
  *  SuperH Ethernet device driver
  *
  *  Copyright (C) 2006-2008 Nobuhiro Iwamatsu
- *  Copyright (C) 2008 Renesas Solutions Corp.
+ *  Copyright (C) 2008-2009 Renesas Solutions Corp.
  *
  *  This program is free software; you can redistribute it and/or modify it
  *  under the terms and conditions of the GNU General Public License,
@@ -33,6 +33,226 @@
 
 #include "sh_eth.h"
 
+/* There is CPU dependent code */
+#if defined(CONFIG_CPU_SUBTYPE_SH7724)
+#define SH_ETH_RESET_DEFAULT	1
+static void sh_eth_set_duplex(struct net_device *ndev)
+{
+	struct sh_eth_private *mdp = netdev_priv(ndev);
+	u32 ioaddr = ndev->base_addr;
+
+	if (mdp->duplex) /* Full */
+		ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR);
+	else		/* Half */
+		ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR);
+}
+
+static void sh_eth_set_rate(struct net_device *ndev)
+{
+	struct sh_eth_private *mdp = netdev_priv(ndev);
+	u32 ioaddr = ndev->base_addr;
+
+	switch (mdp->speed) {
+	case 10: /* 10BASE */
+		ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_RTM, ioaddr + ECMR);
+		break;
+	case 100:/* 100BASE */
+		ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_RTM, ioaddr + ECMR);
+		break;
+	default:
+		break;
+	}
+}
+
+/* SH7724 */
+static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
+	.set_duplex	= sh_eth_set_duplex,
+	.set_rate	= sh_eth_set_rate,
+
+	.ecsr_value	= ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD,
+	.ecsipr_value	= ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | ECSIPR_ICDIP,
+	.eesipr_value	= DMAC_M_RFRMER | DMAC_M_ECI | 0x01ff009f,
+
+	.tx_check	= EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_RTO,
+	.eesr_err_check	= EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE |
+			  EESR_RFRMER | EESR_TFE | EESR_TDE | EESR_ECI,
+	.tx_error_check	= EESR_TWB | EESR_TABT | EESR_TDE | EESR_TFE,
+
+	.apr		= 1,
+	.mpr		= 1,
+	.tpauser	= 1,
+	.hw_swap	= 1,
+};
+
+#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
+#define SH_ETH_HAS_TSU	1
+static void sh_eth_chip_reset(struct net_device *ndev)
+{
+	/* reset device */
+	ctrl_outl(ARSTR_ARSTR, ARSTR);
+	mdelay(1);
+}
+
+static void sh_eth_reset(struct net_device *ndev)
+{
+	u32 ioaddr = ndev->base_addr;
+	int cnt = 100;
+
+	ctrl_outl(EDSR_ENALL, ioaddr + EDSR);
+	ctrl_outl(ctrl_inl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR);
+	while (cnt > 0) {
+		if (!(ctrl_inl(ioaddr + EDMR) & 0x3))
+			break;
+		mdelay(1);
+		cnt--;
+	}
+	if (cnt < 0)
+		printk(KERN_ERR "Device reset fail\n");
+
+	/* Table Init */
+	ctrl_outl(0x0, ioaddr + TDLAR);
+	ctrl_outl(0x0, ioaddr + TDFAR);
+	ctrl_outl(0x0, ioaddr + TDFXR);
+	ctrl_outl(0x0, ioaddr + TDFFR);
+	ctrl_outl(0x0, ioaddr + RDLAR);
+	ctrl_outl(0x0, ioaddr + RDFAR);
+	ctrl_outl(0x0, ioaddr + RDFXR);
+	ctrl_outl(0x0, ioaddr + RDFFR);
+}
+
+static void sh_eth_set_duplex(struct net_device *ndev)
+{
+	struct sh_eth_private *mdp = netdev_priv(ndev);
+	u32 ioaddr = ndev->base_addr;
+
+	if (mdp->duplex) /* Full */
+		ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR);
+	else		/* Half */
+		ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR);
+}
+
+static void sh_eth_set_rate(struct net_device *ndev)
+{
+	struct sh_eth_private *mdp = netdev_priv(ndev);
+	u32 ioaddr = ndev->base_addr;
+
+	switch (mdp->speed) {
+	case 10: /* 10BASE */
+		ctrl_outl(GECMR_10, ioaddr + GECMR);
+		break;
+	case 100:/* 100BASE */
+		ctrl_outl(GECMR_100, ioaddr + GECMR);
+		break;
+	case 1000: /* 1000BASE */
+		ctrl_outl(GECMR_1000, ioaddr + GECMR);
+		break;
+	default:
+		break;
+	}
+}
+
+/* sh7763 */
+static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
+	.chip_reset	= sh_eth_chip_reset,
+	.set_duplex	= sh_eth_set_duplex,
+	.set_rate	= sh_eth_set_rate,
+
+	.ecsr_value	= ECSR_ICD | ECSR_MPD,
+	.ecsipr_value	= ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
+	.eesipr_value	= DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
+
+	.tx_check	= EESR_TC1 | EESR_FTC,
+	.eesr_err_check	= EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | \
+			  EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE | \
+			  EESR_ECI,
+	.tx_error_check	= EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_TDE | \
+			  EESR_TFE,
+
+	.apr		= 1,
+	.mpr		= 1,
+	.tpauser	= 1,
+	.bculr		= 1,
+	.hw_swap	= 1,
+	.rpadir		= 1,
+	.no_trimd	= 1,
+	.no_ade		= 1,
+};
+
+#elif defined(CONFIG_CPU_SUBTYPE_SH7619)
+#define SH_ETH_RESET_DEFAULT	1
+static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
+	.eesipr_value	= DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
+
+	.apr		= 1,
+	.mpr		= 1,
+	.tpauser	= 1,
+	.hw_swap	= 1,
+};
+#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
+#define SH_ETH_RESET_DEFAULT	1
+#define SH_ETH_HAS_TSU	1
+static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
+	.eesipr_value	= DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
+};
+#endif
+
+static void sh_eth_set_default_cpu_data(struct sh_eth_cpu_data *cd)
+{
+	if (!cd->ecsr_value)
+		cd->ecsr_value = DEFAULT_ECSR_INIT;
+
+	if (!cd->ecsipr_value)
+		cd->ecsipr_value = DEFAULT_ECSIPR_INIT;
+
+	if (!cd->fcftr_value)
+		cd->fcftr_value = DEFAULT_FIFO_F_D_RFF | \
+				  DEFAULT_FIFO_F_D_RFD;
+
+	if (!cd->fdr_value)
+		cd->fdr_value = DEFAULT_FDR_INIT;
+
+	if (!cd->rmcr_value)
+		cd->rmcr_value = DEFAULT_RMCR_VALUE;
+
+	if (!cd->tx_check)
+		cd->tx_check = DEFAULT_TX_CHECK;
+
+	if (!cd->eesr_err_check)
+		cd->eesr_err_check = DEFAULT_EESR_ERR_CHECK;
+
+	if (!cd->tx_error_check)
+		cd->tx_error_check = DEFAULT_TX_ERROR_CHECK;
+}
+
+#if defined(SH_ETH_RESET_DEFAULT)
+/* Chip Reset */
+static void sh_eth_reset(struct net_device *ndev)
+{
+	u32 ioaddr = ndev->base_addr;
+
+	ctrl_outl(ctrl_inl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR);
+	mdelay(3);
+	ctrl_outl(ctrl_inl(ioaddr + EDMR) & ~EDMR_SRST, ioaddr + EDMR);
+}
+#endif
+
+#if defined(CONFIG_CPU_SH4)
+static void sh_eth_set_receive_align(struct sk_buff *skb)
+{
+	int reserve;
+
+	reserve = SH4_SKB_RX_ALIGN - ((u32)skb->data & (SH4_SKB_RX_ALIGN - 1));
+	if (reserve)
+		skb_reserve(skb, reserve);
+}
+#else
+static void sh_eth_set_receive_align(struct sk_buff *skb)
+{
+	skb_reserve(skb, SH2_SH3_SKB_RX_ALIGN);
+}
+#endif
+
+
 /* CPU <-> EDMAC endian convert */
 static inline __u32 cpu_to_edmac(struct sh_eth_private *mdp, u32 x)
 {
@@ -165,41 +385,6 @@
 	.get_mdio_data = sh_get_mdio,
 };
 
-/* Chip Reset */
-static void sh_eth_reset(struct net_device *ndev)
-{
-	u32 ioaddr = ndev->base_addr;
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7763)
-	int cnt = 100;
-
-	ctrl_outl(EDSR_ENALL, ioaddr + EDSR);
-	ctrl_outl(ctrl_inl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR);
-	while (cnt > 0) {
-		if (!(ctrl_inl(ioaddr + EDMR) & 0x3))
-			break;
-		mdelay(1);
-		cnt--;
-	}
-	if (cnt < 0)
-		printk(KERN_ERR "Device reset fail\n");
-
-	/* Table Init */
-	ctrl_outl(0x0, ioaddr + TDLAR);
-	ctrl_outl(0x0, ioaddr + TDFAR);
-	ctrl_outl(0x0, ioaddr + TDFXR);
-	ctrl_outl(0x0, ioaddr + TDFFR);
-	ctrl_outl(0x0, ioaddr + RDLAR);
-	ctrl_outl(0x0, ioaddr + RDFAR);
-	ctrl_outl(0x0, ioaddr + RDFXR);
-	ctrl_outl(0x0, ioaddr + RDFFR);
-#else
-	ctrl_outl(ctrl_inl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR);
-	mdelay(3);
-	ctrl_outl(ctrl_inl(ioaddr + EDMR) & ~EDMR_SRST, ioaddr + EDMR);
-#endif
-}
-
 /* free skb and descriptor buffer */
 static void sh_eth_ring_free(struct net_device *ndev)
 {
@@ -228,7 +413,7 @@
 /* format skb and descriptor buffer */
 static void sh_eth_ring_format(struct net_device *ndev)
 {
-	u32 ioaddr = ndev->base_addr, reserve = 0;
+	u32 ioaddr = ndev->base_addr;
 	struct sh_eth_private *mdp = netdev_priv(ndev);
 	int i;
 	struct sk_buff *skb;
@@ -250,37 +435,27 @@
 		mdp->rx_skbuff[i] = skb;
 		if (skb == NULL)
 			break;
+		dma_map_single(&ndev->dev, skb->tail, mdp->rx_buf_sz,
+				DMA_FROM_DEVICE);
 		skb->dev = ndev; /* Mark as being used by this device. */
-#if defined(CONFIG_CPU_SUBTYPE_SH7763)
-		reserve = SH7763_SKB_ALIGN
-			- ((uint32_t)skb->data & (SH7763_SKB_ALIGN-1));
-		if (reserve)
-			skb_reserve(skb, reserve);
-#else
-		skb_reserve(skb, RX_OFFSET);
-#endif
+		sh_eth_set_receive_align(skb);
+
 		/* RX descriptor */
 		rxdesc = &mdp->rx_ring[i];
-		rxdesc->addr = (u32)skb->data & ~0x3UL;
+		rxdesc->addr = virt_to_phys(PTR_ALIGN(skb->data, 4));
 		rxdesc->status = cpu_to_edmac(mdp, RD_RACT | RD_RFP);
 
 		/* The size of the buffer is 16 byte boundary. */
-		rxdesc->buffer_length = (mdp->rx_buf_sz + 16) & ~0x0F;
+		rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16);
 		/* Rx descriptor address set */
 		if (i == 0) {
-			ctrl_outl((u32)rxdesc, ioaddr + RDLAR);
+			ctrl_outl(mdp->rx_desc_dma, ioaddr + RDLAR);
 #if defined(CONFIG_CPU_SUBTYPE_SH7763)
-			ctrl_outl((u32)rxdesc, ioaddr + RDFAR);
+			ctrl_outl(mdp->rx_desc_dma, ioaddr + RDFAR);
 #endif
 		}
 	}
 
-	/* Rx descriptor address set */
-#if defined(CONFIG_CPU_SUBTYPE_SH7763)
-	ctrl_outl((u32)rxdesc, ioaddr + RDFXR);
-	ctrl_outl(0x1, ioaddr + RDFFR);
-#endif
-
 	mdp->dirty_rx = (u32) (i - RX_RING_SIZE);
 
 	/* Mark the last entry as wrapping the ring. */
@@ -296,19 +471,13 @@
 		txdesc->buffer_length = 0;
 		if (i == 0) {
 			/* Tx descriptor address set */
-			ctrl_outl((u32)txdesc, ioaddr + TDLAR);
+			ctrl_outl(mdp->tx_desc_dma, ioaddr + TDLAR);
 #if defined(CONFIG_CPU_SUBTYPE_SH7763)
-			ctrl_outl((u32)txdesc, ioaddr + TDFAR);
+			ctrl_outl(mdp->tx_desc_dma, ioaddr + TDFAR);
 #endif
 		}
 	}
 
-	/* Tx descriptor address set */
-#if defined(CONFIG_CPU_SUBTYPE_SH7763)
-	ctrl_outl((u32)txdesc, ioaddr + TDFXR);
-	ctrl_outl(0x1, ioaddr + TDFFR);
-#endif
-
 	txdesc->status |= cpu_to_edmac(mdp, TD_TDLE);
 }
 
@@ -331,7 +500,7 @@
 	mdp->rx_skbuff = kmalloc(sizeof(*mdp->rx_skbuff) * RX_RING_SIZE,
 				GFP_KERNEL);
 	if (!mdp->rx_skbuff) {
-		printk(KERN_ERR "%s: Cannot allocate Rx skb\n", ndev->name);
+		dev_err(&ndev->dev, "Cannot allocate Rx skb\n");
 		ret = -ENOMEM;
 		return ret;
 	}
@@ -339,7 +508,7 @@
 	mdp->tx_skbuff = kmalloc(sizeof(*mdp->tx_skbuff) * TX_RING_SIZE,
 				GFP_KERNEL);
 	if (!mdp->tx_skbuff) {
-		printk(KERN_ERR "%s: Cannot allocate Tx skb\n", ndev->name);
+		dev_err(&ndev->dev, "Cannot allocate Tx skb\n");
 		ret = -ENOMEM;
 		goto skb_ring_free;
 	}
@@ -350,8 +519,8 @@
 			GFP_KERNEL);
 
 	if (!mdp->rx_ring) {
-		printk(KERN_ERR "%s: Cannot allocate Rx Ring (size %d bytes)\n",
-			ndev->name, rx_ringsize);
+		dev_err(&ndev->dev, "Cannot allocate Rx Ring (size %d bytes)\n",
+			rx_ringsize);
 		ret = -ENOMEM;
 		goto desc_ring_free;
 	}
@@ -363,8 +532,8 @@
 	mdp->tx_ring = dma_alloc_coherent(NULL, tx_ringsize, &mdp->tx_desc_dma,
 			GFP_KERNEL);
 	if (!mdp->tx_ring) {
-		printk(KERN_ERR "%s: Cannot allocate Tx Ring (size %d bytes)\n",
-			ndev->name, tx_ringsize);
+		dev_err(&ndev->dev, "Cannot allocate Tx Ring (size %d bytes)\n",
+			tx_ringsize);
 		ret = -ENOMEM;
 		goto desc_ring_free;
 	}
@@ -394,44 +563,43 @@
 
 	/* Descriptor format */
 	sh_eth_ring_format(ndev);
-	ctrl_outl(RPADIR_INIT, ioaddr + RPADIR);
+	if (mdp->cd->rpadir)
+		ctrl_outl(mdp->cd->rpadir_value, ioaddr + RPADIR);
 
 	/* all sh_eth int mask */
 	ctrl_outl(0, ioaddr + EESIPR);
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7763)
-	ctrl_outl(EDMR_EL, ioaddr + EDMR);
-#else
-	ctrl_outl(0, ioaddr + EDMR);	/* Endian change */
+#if defined(__LITTLE_ENDIAN__)
+	if (mdp->cd->hw_swap)
+		ctrl_outl(EDMR_EL, ioaddr + EDMR);
+	else
 #endif
+		ctrl_outl(0, ioaddr + EDMR);
 
 	/* FIFO size set */
-	ctrl_outl((FIFO_SIZE_T | FIFO_SIZE_R), ioaddr + FDR);
+	ctrl_outl(mdp->cd->fdr_value, ioaddr + FDR);
 	ctrl_outl(0, ioaddr + TFTR);
 
 	/* Frame recv control */
-	ctrl_outl(0, ioaddr + RMCR);
+	ctrl_outl(mdp->cd->rmcr_value, ioaddr + RMCR);
 
 	rx_int_var = mdp->rx_int_var = DESC_I_RINT8 | DESC_I_RINT5;
 	tx_int_var = mdp->tx_int_var = DESC_I_TINT2;
 	ctrl_outl(rx_int_var | tx_int_var, ioaddr + TRSCER);
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7763)
-	/* Burst sycle set */
-	ctrl_outl(0x800, ioaddr + BCULR);
-#endif
+	if (mdp->cd->bculr)
+		ctrl_outl(0x800, ioaddr + BCULR);	/* Burst sycle set */
 
-	ctrl_outl((FIFO_F_D_RFF | FIFO_F_D_RFD), ioaddr + FCFTR);
+	ctrl_outl(mdp->cd->fcftr_value, ioaddr + FCFTR);
 
-#if !defined(CONFIG_CPU_SUBTYPE_SH7763)
-	ctrl_outl(0, ioaddr + TRIMD);
-#endif
+	if (!mdp->cd->no_trimd)
+		ctrl_outl(0, ioaddr + TRIMD);
 
 	/* Recv frame limit set register */
 	ctrl_outl(RFLR_VALUE, ioaddr + RFLR);
 
 	ctrl_outl(ctrl_inl(ioaddr + EESR), ioaddr + EESR);
-	ctrl_outl((DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff), ioaddr + EESIPR);
+	ctrl_outl(mdp->cd->eesipr_value, ioaddr + EESIPR);
 
 	/* PAUSE Prohibition */
 	val = (ctrl_inl(ioaddr + ECMR) & ECMR_DM) |
@@ -439,24 +607,25 @@
 
 	ctrl_outl(val, ioaddr + ECMR);
 
+	if (mdp->cd->set_rate)
+		mdp->cd->set_rate(ndev);
+
 	/* E-MAC Status Register clear */
-	ctrl_outl(ECSR_INIT, ioaddr + ECSR);
+	ctrl_outl(mdp->cd->ecsr_value, ioaddr + ECSR);
 
 	/* E-MAC Interrupt Enable register */
-	ctrl_outl(ECSIPR_INIT, ioaddr + ECSIPR);
+	ctrl_outl(mdp->cd->ecsipr_value, ioaddr + ECSIPR);
 
 	/* Set MAC address */
 	update_mac_address(ndev);
 
 	/* mask reset */
-#if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7763)
-	ctrl_outl(APR_AP, ioaddr + APR);
-	ctrl_outl(MPR_MP, ioaddr + MPR);
-	ctrl_outl(TPAUSER_UNLIMITED, ioaddr + TPAUSER);
-#endif
-#if defined(CONFIG_CPU_SUBTYPE_SH7710)
-	ctrl_outl(BCFR_UNLIMITED, ioaddr + BCFR);
-#endif
+	if (mdp->cd->apr)
+		ctrl_outl(APR_AP, ioaddr + APR);
+	if (mdp->cd->mpr)
+		ctrl_outl(MPR_MP, ioaddr + MPR);
+	if (mdp->cd->tpauser)
+		ctrl_outl(TPAUSER_UNLIMITED, ioaddr + TPAUSER);
 
 	/* Setting the Rx mode will start the Rx process. */
 	ctrl_outl(EDRRR_R, ioaddr + EDRRR);
@@ -505,7 +674,7 @@
 	int boguscnt = (mdp->dirty_rx + RX_RING_SIZE) - mdp->cur_rx;
 	struct sk_buff *skb;
 	u16 pkt_len = 0;
-	u32 desc_status, reserve = 0;
+	u32 desc_status;
 
 	rxdesc = &mdp->rx_ring[entry];
 	while (!(rxdesc->status & cpu_to_edmac(mdp, RD_RACT))) {
@@ -534,7 +703,10 @@
 			if (desc_status & RD_RFS10)
 				mdp->stats.rx_over_errors++;
 		} else {
-			swaps((char *)(rxdesc->addr & ~0x3), pkt_len + 2);
+			if (!mdp->cd->hw_swap)
+				sh_eth_soft_swap(
+					phys_to_virt(ALIGN(rxdesc->addr, 4)),
+					pkt_len + 2);
 			skb = mdp->rx_skbuff[entry];
 			mdp->rx_skbuff[entry] = NULL;
 			skb_put(skb, pkt_len);
@@ -545,6 +717,7 @@
 		}
 		rxdesc->status |= cpu_to_edmac(mdp, RD_RACT);
 		entry = (++mdp->cur_rx) % RX_RING_SIZE;
+		rxdesc = &mdp->rx_ring[entry];
 	}
 
 	/* Refill the Rx ring buffers. */
@@ -552,24 +725,20 @@
 		entry = mdp->dirty_rx % RX_RING_SIZE;
 		rxdesc = &mdp->rx_ring[entry];
 		/* The size of the buffer is 16 byte boundary. */
-		rxdesc->buffer_length = (mdp->rx_buf_sz + 16) & ~0x0F;
+		rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16);
 
 		if (mdp->rx_skbuff[entry] == NULL) {
 			skb = dev_alloc_skb(mdp->rx_buf_sz);
 			mdp->rx_skbuff[entry] = skb;
 			if (skb == NULL)
 				break;	/* Better luck next round. */
+			dma_map_single(&ndev->dev, skb->tail, mdp->rx_buf_sz,
+					DMA_FROM_DEVICE);
 			skb->dev = ndev;
-#if defined(CONFIG_CPU_SUBTYPE_SH7763)
-			reserve = SH7763_SKB_ALIGN
-				- ((uint32_t)skb->data & (SH7763_SKB_ALIGN-1));
-			if (reserve)
-				skb_reserve(skb, reserve);
-#else
-			skb_reserve(skb, RX_OFFSET);
-#endif
+			sh_eth_set_receive_align(skb);
+
 			skb->ip_summed = CHECKSUM_NONE;
-			rxdesc->addr = (u32)skb->data & ~0x3UL;
+			rxdesc->addr = virt_to_phys(PTR_ALIGN(skb->data, 4));
 		}
 		if (entry >= RX_RING_SIZE - 1)
 			rxdesc->status |=
@@ -593,6 +762,8 @@
 	struct sh_eth_private *mdp = netdev_priv(ndev);
 	u32 ioaddr = ndev->base_addr;
 	u32 felic_stat;
+	u32 link_stat;
+	u32 mask;
 
 	if (intr_status & EESR_ECI) {
 		felic_stat = ctrl_inl(ioaddr + ECSR);
@@ -601,7 +772,14 @@
 			mdp->stats.tx_carrier_errors++;
 		if (felic_stat & ECSR_LCHNG) {
 			/* Link Changed */
-			u32 link_stat = (ctrl_inl(ioaddr + PSR));
+			if (mdp->cd->no_psr) {
+				if (mdp->link == PHY_DOWN)
+					link_stat = 0;
+				else
+					link_stat = PHY_ST_LINK;
+			} else {
+				link_stat = (ctrl_inl(ioaddr + PSR));
+			}
 			if (!(link_stat & PHY_ST_LINK)) {
 				/* Link Down : disable tx and rx */
 				ctrl_outl(ctrl_inl(ioaddr + ECMR) &
@@ -633,17 +811,15 @@
 		if (intr_status & EESR_RFRMER) {
 			/* Receive Frame Overflow int */
 			mdp->stats.rx_frame_errors++;
-			printk(KERN_ERR "Receive Frame Overflow\n");
+			dev_err(&ndev->dev, "Receive Frame Overflow\n");
 		}
 	}
-#if !defined(CONFIG_CPU_SUBTYPE_SH7763)
-	if (intr_status & EESR_ADE) {
-		if (intr_status & EESR_TDE) {
-			if (intr_status & EESR_TFE)
-				mdp->stats.tx_fifo_errors++;
-		}
+
+	if (!mdp->cd->no_ade) {
+		if (intr_status & EESR_ADE && intr_status & EESR_TDE &&
+		    intr_status & EESR_TFE)
+			mdp->stats.tx_fifo_errors++;
 	}
-#endif
 
 	if (intr_status & EESR_RDE) {
 		/* Receive Descriptor Empty int */
@@ -651,24 +827,24 @@
 
 		if (ctrl_inl(ioaddr + EDRRR) ^ EDRRR_R)
 			ctrl_outl(EDRRR_R, ioaddr + EDRRR);
-		printk(KERN_ERR "Receive Descriptor Empty\n");
+		dev_err(&ndev->dev, "Receive Descriptor Empty\n");
 	}
 	if (intr_status & EESR_RFE) {
 		/* Receive FIFO Overflow int */
 		mdp->stats.rx_fifo_errors++;
-		printk(KERN_ERR "Receive FIFO Overflow\n");
+		dev_err(&ndev->dev, "Receive FIFO Overflow\n");
 	}
-	if (intr_status & (EESR_TWB | EESR_TABT |
-#if !defined(CONFIG_CPU_SUBTYPE_SH7763)
-			EESR_ADE |
-#endif
-			EESR_TDE | EESR_TFE)) {
+
+	mask = EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE;
+	if (mdp->cd->no_ade)
+		mask &= ~EESR_ADE;
+	if (intr_status & mask) {
 		/* Tx error */
 		u32 edtrr = ctrl_inl(ndev->base_addr + EDTRR);
 		/* dmesg */
-		printk(KERN_ERR "%s:TX error. status=%8.8x cur_tx=%8.8x ",
-				ndev->name, intr_status, mdp->cur_tx);
-		printk(KERN_ERR "dirty_tx=%8.8x state=%8.8x EDTRR=%8.8x.\n",
+		dev_err(&ndev->dev, "TX error. status=%8.8x cur_tx=%8.8x ",
+				intr_status, mdp->cur_tx);
+		dev_err(&ndev->dev, "dirty_tx=%8.8x state=%8.8x EDTRR=%8.8x.\n",
 				mdp->dirty_tx, (u32) ndev->state, edtrr);
 		/* dirty buffer free */
 		sh_eth_txfree(ndev);
@@ -687,6 +863,7 @@
 {
 	struct net_device *ndev = netdev;
 	struct sh_eth_private *mdp = netdev_priv(ndev);
+	struct sh_eth_cpu_data *cd = mdp->cd;
 	irqreturn_t ret = IRQ_NONE;
 	u32 ioaddr, boguscnt = RX_RING_SIZE;
 	u32 intr_status = 0;
@@ -699,7 +876,7 @@
 	/* Clear interrupt */
 	if (intr_status & (EESR_FRC | EESR_RMAF | EESR_RRF |
 			EESR_RTLF | EESR_RTSF | EESR_PRE | EESR_CERF |
-			TX_CHECK | EESR_ERR_CHECK)) {
+			cd->tx_check | cd->eesr_err_check)) {
 		ctrl_outl(intr_status, ioaddr + EESR);
 		ret = IRQ_HANDLED;
 	} else
@@ -716,12 +893,12 @@
 	}
 
 	/* Tx Check */
-	if (intr_status & TX_CHECK) {
+	if (intr_status & cd->tx_check) {
 		sh_eth_txfree(ndev);
 		netif_wake_queue(ndev);
 	}
 
-	if (intr_status & EESR_ERR_CHECK)
+	if (intr_status & cd->eesr_err_check)
 		sh_eth_error(ndev, intr_status);
 
 	if (--boguscnt < 0) {
@@ -756,32 +933,15 @@
 		if (phydev->duplex != mdp->duplex) {
 			new_state = 1;
 			mdp->duplex = phydev->duplex;
-#if defined(CONFIG_CPU_SUBTYPE_SH7763)
-			if (mdp->duplex) { /*  FULL */
-				ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_DM,
-						ioaddr + ECMR);
-			} else {	/* Half */
-				ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_DM,
-						ioaddr + ECMR);
-			}
-#endif
+			if (mdp->cd->set_duplex)
+				mdp->cd->set_duplex(ndev);
 		}
 
 		if (phydev->speed != mdp->speed) {
 			new_state = 1;
 			mdp->speed = phydev->speed;
-#if defined(CONFIG_CPU_SUBTYPE_SH7763)
-			switch (mdp->speed) {
-			case 10: /* 10BASE */
-				ctrl_outl(GECMR_10, ioaddr + GECMR); break;
-			case 100:/* 100BASE */
-				ctrl_outl(GECMR_100, ioaddr + GECMR); break;
-			case 1000: /* 1000BASE */
-				ctrl_outl(GECMR_1000, ioaddr + GECMR); break;
-			default:
-				break;
-			}
-#endif
+			if (mdp->cd->set_rate)
+				mdp->cd->set_rate(ndev);
 		}
 		if (mdp->link == PHY_DOWN) {
 			ctrl_outl((ctrl_inl(ioaddr + ECMR) & ~ECMR_TXF)
@@ -804,7 +964,7 @@
 static int sh_eth_phy_init(struct net_device *ndev)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
-	char phy_id[BUS_ID_SIZE];
+	char phy_id[MII_BUS_ID_SIZE + 3];
 	struct phy_device *phydev = NULL;
 
 	snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
@@ -821,8 +981,9 @@
 		dev_err(&ndev->dev, "phy_connect failed\n");
 		return PTR_ERR(phydev);
 	}
+
 	dev_info(&ndev->dev, "attached phy %i to driver %s\n",
-	phydev->addr, phydev->drv->name);
+		phydev->addr, phydev->drv->name);
 
 	mdp->phydev = phydev;
 
@@ -860,7 +1021,7 @@
 #endif
 				ndev->name, ndev);
 	if (ret) {
-		printk(KERN_ERR "Can not assign IRQ number to %s\n", CARDNAME);
+		dev_err(&ndev->dev, "Can not assign IRQ number\n");
 		return ret;
 	}
 
@@ -955,9 +1116,11 @@
 	entry = mdp->cur_tx % TX_RING_SIZE;
 	mdp->tx_skbuff[entry] = skb;
 	txdesc = &mdp->tx_ring[entry];
-	txdesc->addr = (u32)(skb->data);
+	txdesc->addr = virt_to_phys(skb->data);
 	/* soft swap. */
-	swaps((char *)(txdesc->addr & ~0x3), skb->len + 2);
+	if (!mdp->cd->hw_swap)
+		sh_eth_soft_swap(phys_to_virt(ALIGN(txdesc->addr, 4)),
+				 skb->len + 2);
 	/* write back */
 	__flush_purge_region(skb->data, skb->len);
 	if (skb->len < ETHERSMALL)
@@ -1059,7 +1222,7 @@
 	return phy_mii_ioctl(phydev, if_mii(rq), cmd);
 }
 
-
+#if defined(SH_ETH_HAS_TSU)
 /* Multicast reception directions set */
 static void sh_eth_set_multicast_list(struct net_device *ndev)
 {
@@ -1104,6 +1267,7 @@
 	ctrl_outl(0, ioaddr + TSU_POST3);	/* Disable CAM entry [16-23] */
 	ctrl_outl(0, ioaddr + TSU_POST4);	/* Disable CAM entry [24-31] */
 }
+#endif /* SH_ETH_HAS_TSU */
 
 /* MDIO bus release function */
 static int sh_mdio_release(struct net_device *ndev)
@@ -1193,7 +1357,9 @@
 	.ndo_stop		= sh_eth_close,
 	.ndo_start_xmit		= sh_eth_start_xmit,
 	.ndo_get_stats		= sh_eth_get_stats,
+#if defined(SH_ETH_HAS_TSU)
 	.ndo_set_multicast_list	= sh_eth_set_multicast_list,
+#endif
 	.ndo_tx_timeout		= sh_eth_tx_timeout,
 	.ndo_do_ioctl		= sh_eth_do_ioctl,
 	.ndo_validate_addr	= eth_validate_addr,
@@ -1219,7 +1385,7 @@
 
 	ndev = alloc_etherdev(sizeof(struct sh_eth_private));
 	if (!ndev) {
-		printk(KERN_ERR "%s: could not allocate device.\n", CARDNAME);
+		dev_err(&pdev->dev, "Could not allocate device.\n");
 		ret = -ENOMEM;
 		goto out;
 	}
@@ -1252,6 +1418,10 @@
 	/* EDMAC endian */
 	mdp->edmac_endian = pd->edmac_endian;
 
+	/* set cpu data */
+	mdp->cd = &sh_eth_my_cpu_data;
+	sh_eth_set_default_cpu_data(mdp->cd);
+
 	/* set function */
 	ndev->netdev_ops = &sh_eth_netdev_ops;
 	ndev->watchdog_timeo = TX_TIMEOUT;
@@ -1264,13 +1434,10 @@
 
 	/* First device only init */
 	if (!devno) {
-#if defined(ARSTR)
-		/* reset device */
-		ctrl_outl(ARSTR_ARSTR, ARSTR);
-		mdelay(1);
-#endif
+		if (mdp->cd->chip_reset)
+			mdp->cd->chip_reset(ndev);
 
-#if defined(SH_TSU_ADDR)
+#if defined(SH_ETH_HAS_TSU)
 		/* TSU init (Init only)*/
 		sh_eth_tsu_init(SH_TSU_ADDR);
 #endif
@@ -1287,8 +1454,8 @@
 		goto out_unregister;
 
 	/* pritnt device infomation */
-	printk(KERN_INFO "%s: %s at 0x%x, ",
-	       ndev->name, CARDNAME, (u32) ndev->base_addr);
+	pr_info("Base address at 0x%x, ",
+	       (u32)ndev->base_addr);
 
 	for (i = 0; i < 5; i++)
 		printk("%02X:", ndev->dev_addr[i]);
diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h
index 1537e13..9afe5b4 100644
--- a/drivers/net/sh_eth.h
+++ b/drivers/net/sh_eth.h
@@ -2,7 +2,7 @@
  *  SuperH Ethernet device driver
  *
  *  Copyright (C) 2006-2008 Nobuhiro Iwamatsu
- *  Copyright (C) 2008 Renesas Solutions Corp.
+ *  Copyright (C) 2008-2009 Renesas Solutions Corp.
  *
  *  This program is free software; you can redistribute it and/or modify it
  *  under the terms and conditions of the GNU General Public License,
@@ -39,12 +39,12 @@
 #define ETHERSMALL		60
 #define PKT_BUF_SZ		1538
 
-#ifdef CONFIG_CPU_SUBTYPE_SH7763
+#if defined(CONFIG_CPU_SUBTYPE_SH7763)
+/* This CPU register maps is very difference by other SH4 CPU */
 
-#define SH7763_SKB_ALIGN 32
 /* Chip Base Address */
 # define SH_TSU_ADDR	0xFEE01800
-# define ARSTR			SH_TSU_ADDR
+# define ARSTR		SH_TSU_ADDR
 
 /* Chip Registers */
 /* E-DMAC */
@@ -143,8 +143,60 @@
 # define FWNLCR1         0xB0
 # define FWALCR1         0x40
 
-#else /* CONFIG_CPU_SUBTYPE_SH7763 */
-# define RX_OFFSET 2	/* skb offset */
+#elif defined(CONFIG_CPU_SH4)	/* #if defined(CONFIG_CPU_SUBTYPE_SH7763) */
+/* EtherC */
+#define ECMR		0x100
+#define RFLR		0x108
+#define ECSR		0x110
+#define ECSIPR		0x118
+#define PIR		0x120
+#define PSR		0x128
+#define RDMLR		0x140
+#define IPGR		0x150
+#define APR		0x154
+#define MPR		0x158
+#define TPAUSER		0x164
+#define RFCF		0x160
+#define TPAUSECR	0x168
+#define BCFRR		0x16c
+#define MAHR		0x1c0
+#define MALR		0x1c8
+#define TROCR		0x1d0
+#define CDCR		0x1d4
+#define LCCR		0x1d8
+#define CNDCR		0x1dc
+#define CEFCR		0x1e4
+#define FRECR		0x1e8
+#define TSFRCR		0x1ec
+#define TLFRCR		0x1f0
+#define RFCR		0x1f4
+#define MAFCR		0x1f8
+#define RTRATE		0x1fc
+
+/* E-DMAC */
+#define EDMR		0x000
+#define EDTRR		0x008
+#define EDRRR		0x010
+#define TDLAR		0x018
+#define RDLAR		0x020
+#define EESR		0x028
+#define EESIPR		0x030
+#define TRSCER		0x038
+#define RMFCR		0x040
+#define TFTR		0x048
+#define FDR		0x050
+#define RMCR		0x058
+#define TFUCR		0x064
+#define RFOCR		0x068
+#define FCFTR		0x070
+#define RPADIR		0x078
+#define TRIMD		0x07c
+#define RBWAR		0x0c8
+#define RDFAR		0x0cc
+#define TBRAR		0x0d4
+#define TDFAR		0x0d8
+#else /* #elif defined(CONFIG_CPU_SH4) */
+/* This section is SH3 or SH2 */
 #ifndef CONFIG_CPU_SUBTYPE_SH7619
 /* Chip base address */
 # define SH_TSU_ADDR  0xA7000804
@@ -243,6 +295,30 @@
 
 #endif /* CONFIG_CPU_SUBTYPE_SH7763 */
 
+/* There are avoid compile error... */
+#if !defined(BCULR)
+#define BCULR	0x0fc
+#endif
+#if !defined(TRIMD)
+#define TRIMD	0x0fc
+#endif
+#if !defined(APR)
+#define APR	0x0fc
+#endif
+#if !defined(MPR)
+#define MPR	0x0fc
+#endif
+#if !defined(TPAUSER)
+#define TPAUSER	0x0fc
+#endif
+
+/* Driver's parameters */
+#if defined(CONFIG_CPU_SH4)
+#define SH4_SKB_RX_ALIGN	32
+#else
+#define SH2_SH3_SKB_RX_ALIGN	2
+#endif
+
 /*
  * Register's bits
  */
@@ -261,11 +337,10 @@
 
 /* EDMR */
 enum DMAC_M_BIT {
+	EDMR_EL = 0x40, /* Litte endian */
 	EDMR_DL1 = 0x20, EDMR_DL0 = 0x10,
 #ifdef CONFIG_CPU_SUBTYPE_SH7763
-	EDMR_SRST	= 0x03,
-	EMDR_DESC_R	= 0x30, /* Descriptor reserve size */
-	EDMR_EL		= 0x40, /* Litte endian */
+	EDMR_SRST = 0x03,
 #else /* CONFIG_CPU_SUBTYPE_SH7763 */
 	EDMR_SRST = 0x01,
 #endif
@@ -307,47 +382,43 @@
 
 /* EESR */
 enum EESR_BIT {
-#ifndef CONFIG_CPU_SUBTYPE_SH7763
-	EESR_TWB  = 0x40000000,
-#else
-	EESR_TWB  = 0xC0000000,
-	EESR_TC1  = 0x20000000,
-	EESR_TUC  = 0x10000000,
-	EESR_ROC  = 0x80000000,
-#endif
-	EESR_TABT = 0x04000000,
-	EESR_RABT = 0x02000000, EESR_RFRMER = 0x01000000,
-#ifndef CONFIG_CPU_SUBTYPE_SH7763
-	EESR_ADE  = 0x00800000,
-#endif
-	EESR_ECI  = 0x00400000,
-	EESR_FTC  = 0x00200000, EESR_TDE  = 0x00100000,
-	EESR_TFE  = 0x00080000, EESR_FRC  = 0x00040000,
-	EESR_RDE  = 0x00020000, EESR_RFE  = 0x00010000,
-#ifndef CONFIG_CPU_SUBTYPE_SH7763
-	EESR_CND  = 0x00000800,
-#endif
-	EESR_DLC  = 0x00000400,
-	EESR_CD   = 0x00000200, EESR_RTO  = 0x00000100,
-	EESR_RMAF = 0x00000080, EESR_CEEF = 0x00000040,
-	EESR_CELF = 0x00000020, EESR_RRF  = 0x00000010,
-	EESR_RTLF = 0x00000008, EESR_RTSF = 0x00000004,
-	EESR_PRE  = 0x00000002, EESR_CERF = 0x00000001,
+	EESR_TWB1	= 0x80000000,
+	EESR_TWB	= 0x40000000,	/* same as TWB0 */
+	EESR_TC1	= 0x20000000,
+	EESR_TUC	= 0x10000000,
+	EESR_ROC	= 0x08000000,
+	EESR_TABT	= 0x04000000,
+	EESR_RABT	= 0x02000000,
+	EESR_RFRMER	= 0x01000000,	/* same as RFCOF */
+	EESR_ADE	= 0x00800000,
+	EESR_ECI	= 0x00400000,
+	EESR_FTC	= 0x00200000,	/* same as TC or TC0 */
+	EESR_TDE	= 0x00100000,
+	EESR_TFE	= 0x00080000,	/* same as TFUF */
+	EESR_FRC	= 0x00040000,	/* same as FR */
+	EESR_RDE	= 0x00020000,
+	EESR_RFE	= 0x00010000,
+	EESR_CND	= 0x00000800,
+	EESR_DLC	= 0x00000400,
+	EESR_CD		= 0x00000200,
+	EESR_RTO	= 0x00000100,
+	EESR_RMAF	= 0x00000080,
+	EESR_CEEF	= 0x00000040,
+	EESR_CELF	= 0x00000020,
+	EESR_RRF	= 0x00000010,
+	EESR_RTLF	= 0x00000008,
+	EESR_RTSF	= 0x00000004,
+	EESR_PRE	= 0x00000002,
+	EESR_CERF	= 0x00000001,
 };
 
-
-#ifdef CONFIG_CPU_SUBTYPE_SH7763
-# define TX_CHECK (EESR_TC1 | EESR_FTC)
-# define EESR_ERR_CHECK	(EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE \
-		| EESR_RFRMER | EESR_TFE | EESR_TDE | EESR_ECI)
-# define TX_ERROR_CEHCK (EESR_TWB | EESR_TABT | EESR_TDE | EESR_TFE)
-
-#else
-# define TX_CHECK (EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_RTO)
-# define EESR_ERR_CHECK	(EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE \
-		| EESR_RFRMER | EESR_ADE | EESR_TFE | EESR_TDE | EESR_ECI)
-# define TX_ERROR_CEHCK (EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE)
-#endif
+#define DEFAULT_TX_CHECK	(EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | \
+				 EESR_RTO)
+#define DEFAULT_EESR_ERR_CHECK	(EESR_TWB | EESR_TABT | EESR_RABT | \
+				 EESR_RDE | EESR_RFRMER | EESR_ADE | \
+				 EESR_TFE | EESR_TDE | EESR_ECI)
+#define DEFAULT_TX_ERROR_CHECK	(EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | \
+				 EESR_TFE)
 
 /* EESIPR */
 enum DMAC_IM_BIT {
@@ -386,12 +457,8 @@
 	FCFTR_RFF0 = 0x00010000, FCFTR_RFD2 = 0x00000004,
 	FCFTR_RFD1 = 0x00000002, FCFTR_RFD0 = 0x00000001,
 };
-#define FIFO_F_D_RFF	(FCFTR_RFF2|FCFTR_RFF1|FCFTR_RFF0)
-#ifndef CONFIG_CPU_SUBTYPE_SH7619
-#define FIFO_F_D_RFD	(FCFTR_RFD2|FCFTR_RFD1|FCFTR_RFD0)
-#else
-#define FIFO_F_D_RFD	(FCFTR_RFD0)
-#endif
+#define DEFAULT_FIFO_F_D_RFF	(FCFTR_RFF2 | FCFTR_RFF1 | FCFTR_RFF0)
+#define DEFAULT_FIFO_F_D_RFD	(FCFTR_RFD2 | FCFTR_RFD1 | FCFTR_RFD0)
 
 /* Transfer descriptor bit */
 enum TD_STS_BIT {
@@ -404,60 +471,38 @@
 #define TD_TFP	(TD_TFP1|TD_TFP0)
 
 /* RMCR */
-enum RECV_RST_BIT { RMCR_RST = 0x01, };
+#define DEFAULT_RMCR_VALUE	0x00000000
+
 /* ECMR */
 enum FELIC_MODE_BIT {
-#ifdef CONFIG_CPU_SUBTYPE_SH7763
 	ECMR_TRCCM = 0x04000000, ECMR_RCSC = 0x00800000,
 	ECMR_DPAD = 0x00200000, ECMR_RZPF = 0x00100000,
-#endif
 	ECMR_ZPF = 0x00080000, ECMR_PFR = 0x00040000, ECMR_RXF = 0x00020000,
 	ECMR_TXF = 0x00010000, ECMR_MCT = 0x00002000, ECMR_PRCEF = 0x00001000,
 	ECMR_PMDE = 0x00000200, ECMR_RE = 0x00000040, ECMR_TE = 0x00000020,
-	ECMR_ILB = 0x00000008, ECMR_ELB = 0x00000004, ECMR_DM = 0x00000002,
-	ECMR_PRM = 0x00000001,
+	ECMR_RTM = 0x00000010, ECMR_ILB = 0x00000008, ECMR_ELB = 0x00000004,
+	ECMR_DM = 0x00000002, ECMR_PRM = 0x00000001,
 };
 
-#ifdef CONFIG_CPU_SUBTYPE_SH7763
-#define ECMR_CHG_DM	(ECMR_TRCCM | ECMR_RZPF | ECMR_ZPF |\
-			ECMR_PFR | ECMR_RXF | ECMR_TXF | ECMR_MCT)
-#elif CONFIG_CPU_SUBTYPE_SH7619
-#define ECMR_CHG_DM	(ECMR_ZPF | ECMR_PFR | ECMR_RXF | ECMR_TXF)
-#else
-#define ECMR_CHG_DM	(ECMR_ZPF | ECMR_PFR | ECMR_RXF | ECMR_TXF | ECMR_MCT)
-#endif
-
 /* ECSR */
 enum ECSR_STATUS_BIT {
-#ifndef CONFIG_CPU_SUBTYPE_SH7763
 	ECSR_BRCRX = 0x20, ECSR_PSRTO = 0x10,
-#endif
 	ECSR_LCHNG = 0x04,
 	ECSR_MPD = 0x02, ECSR_ICD = 0x01,
 };
 
-#ifdef CONFIG_CPU_SUBTYPE_SH7763
-# define ECSR_INIT (ECSR_ICD | ECSIPR_MPDIP)
-#else
-# define ECSR_INIT (ECSR_BRCRX | ECSR_PSRTO | \
-			ECSR_LCHNG | ECSR_ICD | ECSIPR_MPDIP)
-#endif
+#define DEFAULT_ECSR_INIT	(ECSR_BRCRX | ECSR_PSRTO | ECSR_LCHNG | \
+				 ECSR_ICD | ECSIPR_MPDIP)
 
 /* ECSIPR */
 enum ECSIPR_STATUS_MASK_BIT {
-#ifndef CONFIG_CPU_SUBTYPE_SH7763
 	ECSIPR_BRCRXIP = 0x20, ECSIPR_PSRTOIP = 0x10,
-#endif
 	ECSIPR_LCHNGIP = 0x04,
 	ECSIPR_MPDIP = 0x02, ECSIPR_ICDIP = 0x01,
 };
 
-#ifdef CONFIG_CPU_SUBTYPE_SH7763
-# define ECSIPR_INIT (ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP)
-#else
-# define ECSIPR_INIT (ECSIPR_BRCRXIP | ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | \
-				ECSIPR_ICDIP | ECSIPR_MPDIP)
-#endif
+#define DEFAULT_ECSIPR_INIT	(ECSIPR_BRCRXIP | ECSIPR_PSRTOIP | \
+				 ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP)
 
 /* APR */
 enum APR_BIT {
@@ -483,23 +528,12 @@
 	RPADIR_PADR = 0x0003f,
 };
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7763)
-# define RPADIR_INIT (0x00)
-#else
-# define RPADIR_INIT (RPADIR_PADS1)
-#endif
-
 /* RFLR */
 #define RFLR_VALUE 0x1000
 
 /* FDR */
-enum FIFO_SIZE_BIT {
-#ifndef CONFIG_CPU_SUBTYPE_SH7619
-	FIFO_SIZE_T = 0x00000700, FIFO_SIZE_R = 0x00000007,
-#else
-	FIFO_SIZE_T = 0x00000100, FIFO_SIZE_R = 0x00000001,
-#endif
-};
+#define DEFAULT_FDR_INIT	0x00000707
+
 enum phy_offsets {
 	PHY_CTRL = 0, PHY_STAT = 1, PHY_IDT1 = 2, PHY_IDT2 = 3,
 	PHY_ANA = 4, PHY_ANL = 5, PHY_ANE = 6,
@@ -633,7 +667,43 @@
 	u32 pad0;		/* padding data */
 } __attribute__((aligned(2), packed));
 
+/* This structure is used by each CPU dependency handling. */
+struct sh_eth_cpu_data {
+	/* optional functions */
+	void (*chip_reset)(struct net_device *ndev);
+	void (*set_duplex)(struct net_device *ndev);
+	void (*set_rate)(struct net_device *ndev);
+
+	/* mandatory initialize value */
+	unsigned long eesipr_value;
+
+	/* optional initialize value */
+	unsigned long ecsr_value;
+	unsigned long ecsipr_value;
+	unsigned long fdr_value;
+	unsigned long fcftr_value;
+	unsigned long rpadir_value;
+	unsigned long rmcr_value;
+
+	/* interrupt checking mask */
+	unsigned long tx_check;
+	unsigned long eesr_err_check;
+	unsigned long tx_error_check;
+
+	/* hardware features */
+	unsigned no_psr:1;		/* EtherC DO NOT have PSR */
+	unsigned apr:1;			/* EtherC have APR */
+	unsigned mpr:1;			/* EtherC have MPR */
+	unsigned tpauser:1;		/* EtherC have TPAUSER */
+	unsigned bculr:1;		/* EtherC have BCULR */
+	unsigned hw_swap:1;		/* E-DMAC have DE bit in EDMR */
+	unsigned rpadir:1;		/* E-DMAC have RPADIR */
+	unsigned no_trimd:1;		/* E-DMAC DO NOT have TRIMD */
+	unsigned no_ade:1;	/* E-DMAC DO NOT have ADE bit in EESR */
+};
+
 struct sh_eth_private {
+	struct sh_eth_cpu_data *cd;
 	dma_addr_t rx_desc_dma;
 	dma_addr_t tx_desc_dma;
 	struct sh_eth_rxdesc *rx_ring;
@@ -661,11 +731,7 @@
 	struct net_device_stats tsu_stats;	/* TSU forward status */
 };
 
-#ifdef CONFIG_CPU_SUBTYPE_SH7763
-/* SH7763 has endian control register */
-#define swaps(x, y)
-#else
-static void swaps(char *src, int len)
+static inline void sh_eth_soft_swap(char *src, int len)
 {
 #ifdef __LITTLE_ENDIAN__
 	u32 *p = (u32 *)src;
@@ -676,5 +742,5 @@
 		*p = swab32(*p);
 #endif
 }
-#endif /* CONFIG_CPU_SUBTYPE_SH7763 */
-#endif
+
+#endif	/* #ifndef __SH_ETH_H__ */
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index c399b19..545f81b 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -369,7 +369,6 @@
 	struct sk_buff* tx_skbuff[TX_RING_SIZE];
         dma_addr_t tx_ring_dma;
         dma_addr_t rx_ring_dma;
-	struct net_device_stats stats;
 	struct timer_list timer;		/* Media monitoring timer. */
 	/* Frequently used values: keep some adjacent for cache effect. */
 	spinlock_t lock;
@@ -975,7 +974,7 @@
 	dev->if_port = 0;
 
 	dev->trans_start = jiffies;
-	np->stats.tx_errors++;
+	dev->stats.tx_errors++;
 	if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
 		netif_wake_queue(dev);
 	}
@@ -1123,7 +1122,7 @@
 			else
 				dev_kfree_skb (skb);
 			np->tx_skbuff[i] = NULL;
-			np->stats.tx_dropped++;
+			dev->stats.tx_dropped++;
 		}
 	}
 	np->cur_tx = np->dirty_tx = 0;
@@ -1181,15 +1180,15 @@
 					if (netif_msg_tx_err(np))
 						printk("%s: Transmit error status %4.4x.\n",
 							   dev->name, tx_status);
-					np->stats.tx_errors++;
+					dev->stats.tx_errors++;
 					if (tx_status & 0x10)
-						np->stats.tx_fifo_errors++;
+						dev->stats.tx_fifo_errors++;
 					if (tx_status & 0x08)
-						np->stats.collisions++;
+						dev->stats.collisions++;
 					if (tx_status & 0x04)
-						np->stats.tx_fifo_errors++;
+						dev->stats.tx_fifo_errors++;
 					if (tx_status & 0x02)
-						np->stats.tx_window_errors++;
+						dev->stats.tx_window_errors++;
 
 					/*
 					** This reset has been verified on
@@ -1313,11 +1312,15 @@
 			if (netif_msg_rx_err(np))
 				printk(KERN_DEBUG "  netdev_rx() Rx error was %8.8x.\n",
 					   frame_status);
-			np->stats.rx_errors++;
-			if (frame_status & 0x00100000) np->stats.rx_length_errors++;
-			if (frame_status & 0x00010000) np->stats.rx_fifo_errors++;
-			if (frame_status & 0x00060000) np->stats.rx_frame_errors++;
-			if (frame_status & 0x00080000) np->stats.rx_crc_errors++;
+			dev->stats.rx_errors++;
+			if (frame_status & 0x00100000)
+				dev->stats.rx_length_errors++;
+			if (frame_status & 0x00010000)
+				dev->stats.rx_fifo_errors++;
+			if (frame_status & 0x00060000)
+				dev->stats.rx_frame_errors++;
+			if (frame_status & 0x00080000)
+				dev->stats.rx_crc_errors++;
 			if (frame_status & 0x00100000) {
 				printk(KERN_WARNING "%s: Oversized Ethernet frame,"
 					   " status %8.8x.\n",
@@ -1485,22 +1488,22 @@
 	   the vulnerability window is very small and statistics are
 	   non-critical. */
 	/* The chip only need report frame silently dropped. */
-	np->stats.rx_missed_errors	+= ioread8(ioaddr + RxMissed);
-	np->stats.tx_packets += ioread16(ioaddr + TxFramesOK);
-	np->stats.rx_packets += ioread16(ioaddr + RxFramesOK);
-	np->stats.collisions += ioread8(ioaddr + StatsLateColl);
-	np->stats.collisions += ioread8(ioaddr + StatsMultiColl);
-	np->stats.collisions += ioread8(ioaddr + StatsOneColl);
-	np->stats.tx_carrier_errors += ioread8(ioaddr + StatsCarrierError);
+	dev->stats.rx_missed_errors	+= ioread8(ioaddr + RxMissed);
+	dev->stats.tx_packets += ioread16(ioaddr + TxFramesOK);
+	dev->stats.rx_packets += ioread16(ioaddr + RxFramesOK);
+	dev->stats.collisions += ioread8(ioaddr + StatsLateColl);
+	dev->stats.collisions += ioread8(ioaddr + StatsMultiColl);
+	dev->stats.collisions += ioread8(ioaddr + StatsOneColl);
+	dev->stats.tx_carrier_errors += ioread8(ioaddr + StatsCarrierError);
 	ioread8(ioaddr + StatsTxDefer);
 	for (i = StatsTxDefer; i <= StatsMcastRx; i++)
 		ioread8(ioaddr + i);
-	np->stats.tx_bytes += ioread16(ioaddr + TxOctetsLow);
-	np->stats.tx_bytes += ioread16(ioaddr + TxOctetsHigh) << 16;
-	np->stats.rx_bytes += ioread16(ioaddr + RxOctetsLow);
-	np->stats.rx_bytes += ioread16(ioaddr + RxOctetsHigh) << 16;
+	dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsLow);
+	dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsHigh) << 16;
+	dev->stats.rx_bytes += ioread16(ioaddr + RxOctetsLow);
+	dev->stats.rx_bytes += ioread16(ioaddr + RxOctetsHigh) << 16;
 
-	return &np->stats;
+	return &dev->stats;
 }
 
 static void set_rx_mode(struct net_device *dev)
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index f18017d..0cf22c4 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -3325,6 +3325,37 @@
 }
 #endif /* CONFIG_NET_POLL_CONTROLLER */
 
+static int ucc_geth_set_mac_addr(struct net_device *dev, void *p)
+{
+	struct ucc_geth_private *ugeth = netdev_priv(dev);
+	struct sockaddr *addr = p;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+	/*
+	 * If device is not running, we will set mac addr register
+	 * when opening the device.
+	 */
+	if (!netif_running(dev))
+		return 0;
+
+	spin_lock_irq(&ugeth->lock);
+	init_mac_station_addr_regs(dev->dev_addr[0],
+				   dev->dev_addr[1],
+				   dev->dev_addr[2],
+				   dev->dev_addr[3],
+				   dev->dev_addr[4],
+				   dev->dev_addr[5],
+				   &ugeth->ug_regs->macstnaddr1,
+				   &ugeth->ug_regs->macstnaddr2);
+	spin_unlock_irq(&ugeth->lock);
+
+	return 0;
+}
+
 /* Called when something needs to use the ethernet device */
 /* Returns 0 for success. */
 static int ucc_geth_open(struct net_device *dev)
@@ -3501,7 +3532,7 @@
 	.ndo_stop		= ucc_geth_close,
 	.ndo_start_xmit		= ucc_geth_start_xmit,
 	.ndo_validate_addr	= eth_validate_addr,
-	.ndo_set_mac_address	= eth_mac_addr,
+	.ndo_set_mac_address	= ucc_geth_set_mac_addr,
 	.ndo_change_mtu		= eth_change_mtu,
 	.ndo_set_multicast_list	= ucc_geth_set_multi,
 	.ndo_tx_timeout		= ucc_geth_timeout,
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 45daba7..d3489a3 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -388,7 +388,6 @@
 	long pioaddr;
 	struct net_device *dev;
 	struct napi_struct napi;
-	struct net_device_stats stats;
 	spinlock_t lock;
 
 	/* Frequently used values: keep some adjacent for cache effect. */
@@ -1209,7 +1208,7 @@
 	enable_irq(rp->pdev->irq);
 
 	dev->trans_start = jiffies;
-	rp->stats.tx_errors++;
+	dev->stats.tx_errors++;
 	netif_wake_queue(dev);
 }
 
@@ -1237,7 +1236,7 @@
 			/* packet too long, drop it */
 			dev_kfree_skb(skb);
 			rp->tx_skbuff[entry] = NULL;
-			rp->stats.tx_dropped++;
+			dev->stats.tx_dropped++;
 			return 0;
 		}
 
@@ -1378,29 +1377,33 @@
 				printk(KERN_DEBUG "%s: Transmit error, "
 				       "Tx status %8.8x.\n",
 				       dev->name, txstatus);
-			rp->stats.tx_errors++;
-			if (txstatus & 0x0400) rp->stats.tx_carrier_errors++;
-			if (txstatus & 0x0200) rp->stats.tx_window_errors++;
-			if (txstatus & 0x0100) rp->stats.tx_aborted_errors++;
-			if (txstatus & 0x0080) rp->stats.tx_heartbeat_errors++;
+			dev->stats.tx_errors++;
+			if (txstatus & 0x0400)
+				dev->stats.tx_carrier_errors++;
+			if (txstatus & 0x0200)
+				dev->stats.tx_window_errors++;
+			if (txstatus & 0x0100)
+				dev->stats.tx_aborted_errors++;
+			if (txstatus & 0x0080)
+				dev->stats.tx_heartbeat_errors++;
 			if (((rp->quirks & rqRhineI) && txstatus & 0x0002) ||
 			    (txstatus & 0x0800) || (txstatus & 0x1000)) {
-				rp->stats.tx_fifo_errors++;
+				dev->stats.tx_fifo_errors++;
 				rp->tx_ring[entry].tx_status = cpu_to_le32(DescOwn);
 				break; /* Keep the skb - we try again */
 			}
 			/* Transmitter restarted in 'abnormal' handler. */
 		} else {
 			if (rp->quirks & rqRhineI)
-				rp->stats.collisions += (txstatus >> 3) & 0x0F;
+				dev->stats.collisions += (txstatus >> 3) & 0x0F;
 			else
-				rp->stats.collisions += txstatus & 0x0F;
+				dev->stats.collisions += txstatus & 0x0F;
 			if (debug > 6)
 				printk(KERN_DEBUG "collisions: %1.1x:%1.1x\n",
 				       (txstatus >> 3) & 0xF,
 				       txstatus & 0xF);
-			rp->stats.tx_bytes += rp->tx_skbuff[entry]->len;
-			rp->stats.tx_packets++;
+			dev->stats.tx_bytes += rp->tx_skbuff[entry]->len;
+			dev->stats.tx_packets++;
 		}
 		/* Free the original skb. */
 		if (rp->tx_skbuff_dma[entry]) {
@@ -1455,21 +1458,24 @@
 				printk(KERN_WARNING "%s: Oversized Ethernet "
 				       "frame %p vs %p.\n", dev->name,
 				       rp->rx_head_desc, &rp->rx_ring[entry]);
-				rp->stats.rx_length_errors++;
+				dev->stats.rx_length_errors++;
 			} else if (desc_status & RxErr) {
 				/* There was a error. */
 				if (debug > 2)
 					printk(KERN_DEBUG "rhine_rx() Rx "
 					       "error was %8.8x.\n",
 					       desc_status);
-				rp->stats.rx_errors++;
-				if (desc_status & 0x0030) rp->stats.rx_length_errors++;
-				if (desc_status & 0x0048) rp->stats.rx_fifo_errors++;
-				if (desc_status & 0x0004) rp->stats.rx_frame_errors++;
+				dev->stats.rx_errors++;
+				if (desc_status & 0x0030)
+					dev->stats.rx_length_errors++;
+				if (desc_status & 0x0048)
+					dev->stats.rx_fifo_errors++;
+				if (desc_status & 0x0004)
+					dev->stats.rx_frame_errors++;
 				if (desc_status & 0x0002) {
 					/* this can also be updated outside the interrupt handler */
 					spin_lock(&rp->lock);
-					rp->stats.rx_crc_errors++;
+					dev->stats.rx_crc_errors++;
 					spin_unlock(&rp->lock);
 				}
 			}
@@ -1513,8 +1519,8 @@
 			}
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_receive_skb(skb);
-			rp->stats.rx_bytes += pkt_len;
-			rp->stats.rx_packets++;
+			dev->stats.rx_bytes += pkt_len;
+			dev->stats.rx_packets++;
 		}
 		entry = (++rp->cur_rx) % RX_RING_SIZE;
 		rp->rx_head_desc = &rp->rx_ring[entry];
@@ -1599,8 +1605,8 @@
 	if (intr_status & IntrLinkChange)
 		rhine_check_media(dev, 0);
 	if (intr_status & IntrStatsMax) {
-		rp->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs);
-		rp->stats.rx_missed_errors += ioread16(ioaddr + RxMissed);
+		dev->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs);
+		dev->stats.rx_missed_errors += ioread16(ioaddr + RxMissed);
 		clear_tally_counters(ioaddr);
 	}
 	if (intr_status & IntrTxAborted) {
@@ -1654,12 +1660,12 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&rp->lock, flags);
-	rp->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs);
-	rp->stats.rx_missed_errors += ioread16(ioaddr + RxMissed);
+	dev->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs);
+	dev->stats.rx_missed_errors += ioread16(ioaddr + RxMissed);
 	clear_tally_counters(ioaddr);
 	spin_unlock_irqrestore(&rp->lock, flags);
 
-	return &rp->stats;
+	return &dev->stats;
 }
 
 static void rhine_set_rx_mode(struct net_device *dev)
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 754a4b1..e2a7725 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -1385,7 +1385,7 @@
 
 static int velocity_rx_srv(struct velocity_info *vptr, int status)
 {
-	struct net_device_stats *stats = &vptr->stats;
+	struct net_device_stats *stats = &vptr->dev->stats;
 	int rd_curr = vptr->rx.curr;
 	int works = 0;
 
@@ -1519,7 +1519,7 @@
 static int velocity_receive_frame(struct velocity_info *vptr, int idx)
 {
 	void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int);
-	struct net_device_stats *stats = &vptr->stats;
+	struct net_device_stats *stats = &vptr->dev->stats;
 	struct velocity_rd_info *rd_info = &(vptr->rx.info[idx]);
 	struct rx_desc *rd = &(vptr->rx.ring[idx]);
 	int pkt_len = le16_to_cpu(rd->rdesc0.len) & 0x3fff;
@@ -1532,7 +1532,7 @@
 	}
 
 	if (rd->rdesc0.RSR & RSR_MAR)
-		vptr->stats.multicast++;
+		stats->multicast++;
 
 	skb = rd_info->skb;
 
@@ -1634,7 +1634,7 @@
 	int idx;
 	int works = 0;
 	struct velocity_td_info *tdinfo;
-	struct net_device_stats *stats = &vptr->stats;
+	struct net_device_stats *stats = &vptr->dev->stats;
 
 	for (qnum = 0; qnum < vptr->tx.numq; qnum++) {
 		for (idx = vptr->tx.tail[qnum]; vptr->tx.used[qnum] > 0;
@@ -2324,22 +2324,22 @@
 
 	/* If the hardware is down, don't touch MII */
 	if(!netif_running(dev))
-		return &vptr->stats;
+		return &dev->stats;
 
 	spin_lock_irq(&vptr->lock);
 	velocity_update_hw_mibs(vptr);
 	spin_unlock_irq(&vptr->lock);
 
-	vptr->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts];
-	vptr->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts];
-	vptr->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors];
+	dev->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts];
+	dev->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts];
+	dev->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors];
 
 //  unsigned long   rx_dropped;     /* no space in linux buffers    */
-	vptr->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions];
+	dev->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions];
 	/* detailed rx_errors: */
 //  unsigned long   rx_length_errors;
 //  unsigned long   rx_over_errors;     /* receiver ring buff overflow  */
-	vptr->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE];
+	dev->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE];
 //  unsigned long   rx_frame_errors;    /* recv'd frame alignment error */
 //  unsigned long   rx_fifo_errors;     /* recv'r fifo overrun      */
 //  unsigned long   rx_missed_errors;   /* receiver missed packet   */
@@ -2347,7 +2347,7 @@
 	/* detailed tx_errors */
 //  unsigned long   tx_fifo_errors;
 
-	return &vptr->stats;
+	return &dev->stats;
 }
 
 
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index ea43e18..4cd3f6c 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -1503,7 +1503,6 @@
 
 	struct pci_dev *pdev;
 	struct net_device *dev;
-	struct net_device_stats stats;
 
 	struct vlan_group    *vlgrp;
 	u8 ip_addr[4];
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 91be3e7..a67d292 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -501,5 +501,6 @@
 source "drivers/net/wireless/rt2x00/Kconfig"
 source "drivers/net/wireless/orinoco/Kconfig"
 source "drivers/net/wireless/wl12xx/Kconfig"
+source "drivers/net/wireless/iwmc3200wifi/Kconfig"
 
 endmenu
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index f2b1861..7a4647e 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -60,3 +60,5 @@
 obj-$(CONFIG_MAC80211_HWSIM)	+= mac80211_hwsim.o
 
 obj-$(CONFIG_WL12XX)	+= wl12xx/
+
+obj-$(CONFIG_IWM)	+= iwmc3200wifi/
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index d734757..9eabf4d 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -6467,6 +6467,7 @@
 {
 	struct airo_info *local = dev->ml_priv;
 	int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+	int wep_key_len;
 	u8 buf[16];
 
 	if (!local->wep_capable)
@@ -6500,11 +6501,13 @@
 	dwrq->flags |= index + 1;
 
 	/* Copy the key to the user buffer */
-	dwrq->length = get_wep_key(local, index, &buf[0], sizeof(buf));
-	if (dwrq->length != -1)
-		memcpy(extra, buf, dwrq->length);
-	else
+	wep_key_len = get_wep_key(local, index, &buf[0], sizeof(buf));
+	if (wep_key_len < 0) {
 		dwrq->length = 0;
+	} else {
+		dwrq->length = wep_key_len;
+		memcpy(extra, buf, dwrq->length);
+	}
 
 	return 0;
 }
@@ -6617,7 +6620,7 @@
 	struct airo_info *local = dev->ml_priv;
 	struct iw_point *encoding = &wrqu->encoding;
 	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
-	int idx, max_key_len;
+	int idx, max_key_len, wep_key_len;
 	u8 buf[16];
 
 	if (!local->wep_capable)
@@ -6661,11 +6664,13 @@
 	memset(extra, 0, 16);
 	
 	/* Copy the key to the user buffer */
-	ext->key_len = get_wep_key(local, idx, &buf[0], sizeof(buf));
-	if (ext->key_len != -1)
-		memcpy(extra, buf, ext->key_len);
-	else
+	wep_key_len = get_wep_key(local, idx, &buf[0], sizeof(buf));
+	if (wep_key_len < 0) {
 		ext->key_len = 0;
+	} else {
+		ext->key_len = wep_key_len;
+		memcpy(extra, buf, ext->key_len);
+	}
 
 	return 0;
 }
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index 4ef1d2f..99df9dd 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -1555,7 +1555,7 @@
 
 	switch (key->alg) {
 	case ALG_WEP:
-		if (key->keylen == LEN_WEP40)
+		if (key->keylen == WLAN_KEY_LEN_WEP40)
 			ktype = AR9170_ENC_ALG_WEP64;
 		else
 			ktype = AR9170_ENC_ALG_WEP128;
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index dbfe9f4..fb51937 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -242,8 +242,8 @@
 static u64 ath5k_get_tsf(struct ieee80211_hw *hw);
 static void ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf);
 static void ath5k_reset_tsf(struct ieee80211_hw *hw);
-static int ath5k_beacon_update(struct ath5k_softc *sc,
-		struct sk_buff *skb);
+static int ath5k_beacon_update(struct ieee80211_hw *hw,
+		struct ieee80211_vif *vif);
 static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
 		struct ieee80211_vif *vif,
 		struct ieee80211_bss_conf *bss_conf,
@@ -2127,8 +2127,10 @@
 		/* NB: hw still stops DMA, so proceed */
 	}
 
-	/* Note: Beacon buffer is updated on beacon_update when mac80211
-	 * calls config_interface */
+	/* refresh the beacon for AP mode */
+	if (sc->opmode == NL80211_IFTYPE_AP)
+		ath5k_beacon_update(sc->hw, sc->vif);
+
 	ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr);
 	ath5k_hw_start_tx_dma(ah, sc->bhalq);
 	ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n",
@@ -3047,28 +3049,55 @@
 		ath5k_hw_reset_tsf(sc->ah);
 }
 
+/*
+ * Updates the beacon that is sent by ath5k_beacon_send.  For adhoc,
+ * this is called only once at config_bss time, for AP we do it every
+ * SWBA interrupt so that the TIM will reflect buffered frames.
+ *
+ * Called with the beacon lock.
+ */
 static int
-ath5k_beacon_update(struct ath5k_softc *sc, struct sk_buff *skb)
+ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
-	unsigned long flags;
 	int ret;
+	struct ath5k_softc *sc = hw->priv;
+	struct sk_buff *skb = ieee80211_beacon_get(hw, vif);
+
+	if (!skb) {
+		ret = -ENOMEM;
+		goto out;
+	}
 
 	ath5k_debug_dump_skb(sc, skb, "BC  ", 1);
 
-	spin_lock_irqsave(&sc->block, flags);
 	ath5k_txbuf_free(sc, sc->bbuf);
 	sc->bbuf->skb = skb;
 	ret = ath5k_beacon_setup(sc, sc->bbuf);
 	if (ret)
 		sc->bbuf->skb = NULL;
+out:
+	return ret;
+}
+
+/*
+ *  Update the beacon and reconfigure the beacon queues.
+ */
+static void
+ath5k_beacon_reconfig(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+	int ret;
+	unsigned long flags;
+	struct ath5k_softc *sc = hw->priv;
+
+	spin_lock_irqsave(&sc->block, flags);
+	ret = ath5k_beacon_update(hw, vif);
 	spin_unlock_irqrestore(&sc->block, flags);
-	if (!ret) {
+	if (ret == 0) {
 		ath5k_beacon_config(sc);
 		mmiowb();
 	}
-
-	return ret;
 }
+
 static void
 set_beacon_filter(struct ieee80211_hw *hw, bool enable)
 {
@@ -3118,10 +3147,7 @@
 	    (vif->type == NL80211_IFTYPE_ADHOC ||
 	     vif->type == NL80211_IFTYPE_MESH_POINT ||
 	     vif->type == NL80211_IFTYPE_AP)) {
-		struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
-
-		if (beacon)
-			ath5k_beacon_update(sc, beacon);
+		ath5k_beacon_reconfig(hw, vif);
 	}
 
  unlock:
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c
index 579aa0a..ec35503 100644
--- a/drivers/net/wireless/ath/ath5k/pcu.c
+++ b/drivers/net/wireless/ath/ath5k/pcu.c
@@ -1038,9 +1038,9 @@
 	case ALG_CCMP:
 		return AR5K_KEYTABLE_TYPE_CCM;
 	case ALG_WEP:
-		if (key->keylen == LEN_WEP40)
+		if (key->keylen == WLAN_KEY_LEN_WEP40)
 			return AR5K_KEYTABLE_TYPE_40;
-		else if (key->keylen == LEN_WEP104)
+		else if (key->keylen == WLAN_KEY_LEN_WEP104)
 			return AR5K_KEYTABLE_TYPE_104;
 		return -EINVAL;
 	default:
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index d0d1c35..a876ca8 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -1897,6 +1897,9 @@
 	s16 min_pwrL, min_pwrR;
 	s16 pwr_i;
 
+	if (WARN_ON(stepL[0] == stepL[1] || stepR[0] == stepR[1]))
+		return 0;
+
 	if (pwrL[0] == pwrL[1])
 		min_pwrL = pwrL[0];
 	else {
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index c1862f8..6606773 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -26,7 +26,7 @@
 \*****************************/
 
 #include <linux/pci.h> 		/* To determine if a card is pci-e */
-#include <linux/bitops.h>	/* For get_bitmask_order */
+#include <linux/log2.h>
 #include "ath5k.h"
 #include "reg.h"
 #include "base.h"
@@ -68,10 +68,10 @@
 
 	/* Get exponent
 	 * ALGO: coef_exp = 14 - highest set bit position */
-	coef_exp = get_bitmask_order(coef_scaled);
+	coef_exp = ilog2(coef_scaled);
 
 	/* Doesn't make sense if it's zero*/
-	if (!coef_exp)
+	if (!coef_scaled || !coef_exp)
 		return -EINVAL;
 
 	/* Note: we've shifted coef_scaled by 24 */
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 10ffc94..796a3ad 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -515,6 +515,10 @@
 #define SC_OP_LED_ON            BIT(13)
 #define SC_OP_SCANNING          BIT(14)
 #define SC_OP_TSF_RESET         BIT(15)
+#define SC_OP_WAIT_FOR_CAB      BIT(16)
+#define SC_OP_WAIT_FOR_PSPOLL_DATA BIT(17)
+#define SC_OP_WAIT_FOR_TX_ACK   BIT(18)
+#define SC_OP_BEACON_SYNC       BIT(19)
 
 struct ath_bus_ops {
 	void		(*read_cachesize)(struct ath_softc *sc, int *csz);
@@ -599,6 +603,7 @@
 	struct ath9k_debug debug;
 #endif
 	struct ath_bus_ops *bus_ops;
+	struct ath_beacon_config cur_beacon_conf;
 };
 
 struct ath_wiphy {
@@ -676,7 +681,9 @@
 {
 	if (atomic_dec_and_test(&sc->ps_usecount))
 		if ((sc->hw->conf.flags & IEEE80211_CONF_PS) &&
-		    !(sc->sc_flags & SC_OP_WAIT_FOR_BEACON))
+		    !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
+				      SC_OP_WAIT_FOR_PSPOLL_DATA |
+				      SC_OP_WAIT_FOR_TX_ACK)))
 			ath9k_hw_setpower(sc->sc_ah,
 					  sc->sc_ah->restore_mode);
 }
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 3a7154b..a21b213 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -507,8 +507,7 @@
  * slot. Slots that are not occupied will generate nothing.
  */
 static void ath_beacon_config_ap(struct ath_softc *sc,
-				 struct ath_beacon_config *conf,
-				 struct ath_vif *avp)
+				 struct ath_beacon_config *conf)
 {
 	u32 nexttbtt, intval;
 
@@ -553,14 +552,14 @@
  * we've associated with.
  */
 static void ath_beacon_config_sta(struct ath_softc *sc,
-				  struct ath_beacon_config *conf,
-				  struct ath_vif *avp)
+				  struct ath_beacon_config *conf)
 {
 	struct ath9k_beacon_state bs;
 	int dtimperiod, dtimcount, sleepduration;
 	int cfpperiod, cfpcount;
 	u32 nexttbtt = 0, intval, tsftu;
 	u64 tsf;
+	int num_beacons, offset, dtim_dec_count, cfp_dec_count;
 
 	memset(&bs, 0, sizeof(bs));
 	intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
@@ -588,14 +587,27 @@
 	 */
 	tsf = ath9k_hw_gettsf64(sc->sc_ah);
 	tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
-	do {
+
+	num_beacons = tsftu / intval + 1;
+	offset = tsftu % intval;
+	nexttbtt = tsftu - offset;
+	if (offset)
 		nexttbtt += intval;
-		if (--dtimcount < 0) {
-			dtimcount = dtimperiod - 1;
-			if (--cfpcount < 0)
-				cfpcount = cfpperiod - 1;
-		}
-	} while (nexttbtt < tsftu);
+
+	/* DTIM Beacon every dtimperiod Beacon */
+	dtim_dec_count = num_beacons % dtimperiod;
+	/* CFP every cfpperiod DTIM Beacon */
+	cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod;
+	if (dtim_dec_count)
+		cfp_dec_count++;
+
+	dtimcount -= dtim_dec_count;
+	if (dtimcount < 0)
+		dtimcount += dtimperiod;
+
+	cfpcount -= cfp_dec_count;
+	if (cfpcount < 0)
+		cfpcount += cfpperiod;
 
 	bs.bs_intval = intval;
 	bs.bs_nexttbtt = nexttbtt;
@@ -654,7 +666,6 @@
 
 static void ath_beacon_config_adhoc(struct ath_softc *sc,
 				    struct ath_beacon_config *conf,
-				    struct ath_vif *avp,
 				    struct ieee80211_vif *vif)
 {
 	u64 tsf;
@@ -698,43 +709,50 @@
 	sc->beacon.bmisscnt = 0;
 	ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
 
-	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)
+	/* FIXME: Handle properly when vif is NULL */
+	if (vif && sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)
 		ath_beacon_start_adhoc(sc, vif);
 }
 
 void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
 {
-	struct ath_beacon_config conf;
+	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
+	enum nl80211_iftype iftype;
 
 	/* Setup the beacon configuration parameters */
 
-	memset(&conf, 0, sizeof(struct ath_beacon_config));
-	conf.beacon_interval = sc->beacon_interval ? : ATH_DEFAULT_BINTVAL;
-	conf.listen_interval = 1;
-	conf.dtim_period = conf.beacon_interval;
-	conf.dtim_count = 1;
-	conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval;
-
 	if (vif) {
-		struct ath_vif *avp = (struct ath_vif *)vif->drv_priv;
+		struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
 
-		switch(avp->av_opmode) {
-		case NL80211_IFTYPE_AP:
-			ath_beacon_config_ap(sc, &conf, avp);
-			break;
-		case NL80211_IFTYPE_ADHOC:
-		case NL80211_IFTYPE_MESH_POINT:
-			ath_beacon_config_adhoc(sc, &conf, avp, vif);
-			break;
-		case NL80211_IFTYPE_STATION:
-			ath_beacon_config_sta(sc, &conf, avp);
-			break;
-		default:
-			DPRINTF(sc, ATH_DBG_CONFIG,
-				"Unsupported beaconing mode\n");
-			return;
-		}
+		iftype = vif->type;
 
-		sc->sc_flags |= SC_OP_BEACONS;
+		cur_conf->beacon_interval = bss_conf->beacon_int;
+		cur_conf->dtim_period = bss_conf->dtim_period;
+		cur_conf->listen_interval = 1;
+		cur_conf->dtim_count = 1;
+		cur_conf->bmiss_timeout =
+			ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
+	} else {
+		iftype = sc->sc_ah->opmode;
 	}
+
+
+	switch (iftype) {
+	case NL80211_IFTYPE_AP:
+		ath_beacon_config_ap(sc, cur_conf);
+		break;
+	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_MESH_POINT:
+		ath_beacon_config_adhoc(sc, cur_conf, vif);
+		break;
+	case NL80211_IFTYPE_STATION:
+		ath_beacon_config_sta(sc, cur_conf);
+		break;
+	default:
+		DPRINTF(sc, ATH_DBG_CONFIG,
+			"Unsupported beaconing mode\n");
+		return;
+	}
+
+	sc->sc_flags |= SC_OP_BEACONS;
 }
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 23298b9..db845cf 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -29,6 +29,7 @@
 	ATH_DBG_BEACON		= 0x00000100,
 	ATH_DBG_CONFIG		= 0x00000200,
 	ATH_DBG_FATAL		= 0x00000400,
+	ATH_DBG_PS		= 0x00000800,
 	ATH_DBG_ANY		= 0xffffffff
 };
 
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 4acfab5..1579c94 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -2472,14 +2472,14 @@
 		}
 		break;
 	case ATH9K_CIPHER_WEP:
-		if (k->kv_len < LEN_WEP40) {
+		if (k->kv_len < WLAN_KEY_LEN_WEP40) {
 			DPRINTF(ah->ah_sc, ATH_DBG_ANY,
 				"WEP key length %u too small\n", k->kv_len);
 			return false;
 		}
-		if (k->kv_len <= LEN_WEP40)
+		if (k->kv_len <= WLAN_KEY_LEN_WEP40)
 			keyType = AR_KEYTABLE_TYPE_40;
-		else if (k->kv_len <= LEN_WEP104)
+		else if (k->kv_len <= WLAN_KEY_LEN_WEP104)
 			keyType = AR_KEYTABLE_TYPE_104;
 		else
 			keyType = AR_KEYTABLE_TYPE_128;
@@ -2498,7 +2498,7 @@
 	key2 = get_unaligned_le32(k->kv_val + 6);
 	key3 = get_unaligned_le16(k->kv_val + 10);
 	key4 = get_unaligned_le32(k->kv_val + 12);
-	if (k->kv_len <= LEN_WEP104)
+	if (k->kv_len <= WLAN_KEY_LEN_WEP104)
 		key4 &= 0xff;
 
 	/*
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index bbbfdcd..61da08a 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -35,14 +35,14 @@
 #define CHAN2G(_freq, _idx)  { \
 	.center_freq = (_freq), \
 	.hw_value = (_idx), \
-	.max_power = 30, \
+	.max_power = 20, \
 }
 
 #define CHAN5G(_freq, _idx) { \
 	.band = IEEE80211_BAND_5GHZ, \
 	.center_freq = (_freq), \
 	.hw_value = (_idx), \
-	.max_power = 30, \
+	.max_power = 20, \
 }
 
 /* Some 2 GHz radios are actually tunable on 2312-2732
@@ -280,7 +280,7 @@
 	if (r) {
 		DPRINTF(sc, ATH_DBG_FATAL,
 			"Unable to reset channel (%u Mhz) "
-			"reset status %u\n",
+			"reset status %d\n",
 			channel->center_freq, r);
 		spin_unlock_bh(&sc->sc_resetlock);
 		return r;
@@ -329,6 +329,12 @@
 	if (sc->sc_flags & SC_OP_SCANNING)
 		goto set_timer;
 
+	/* Only calibrate if awake */
+	if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE)
+		goto set_timer;
+
+	ath9k_ps_wakeup(sc);
+
 	/* Long calibration runs independently of short calibration. */
 	if ((timestamp - sc->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
 		longcal = true;
@@ -380,6 +386,8 @@
 		}
 	}
 
+	ath9k_ps_restore(sc);
+
 set_timer:
 	/*
 	* Set timer interval based on previous results.
@@ -455,8 +463,11 @@
 	struct ath_softc *sc = (struct ath_softc *)data;
 	u32 status = sc->intrstatus;
 
+	ath9k_ps_wakeup(sc);
+
 	if (status & ATH9K_INT_FATAL) {
 		ath_reset(sc, false);
+		ath9k_ps_restore(sc);
 		return;
 	}
 
@@ -469,8 +480,19 @@
 	if (status & ATH9K_INT_TX)
 		ath_tx_tasklet(sc);
 
+	if ((status & ATH9K_INT_TSFOOR) &&
+	    (sc->hw->conf.flags & IEEE80211_CONF_PS)) {
+		/*
+		 * TSF sync does not look correct; remain awake to sync with
+		 * the next Beacon.
+		 */
+		DPRINTF(sc, ATH_DBG_PS, "TSFOOR - Sync with next Beacon\n");
+		sc->sc_flags |= SC_OP_WAIT_FOR_BEACON | SC_OP_BEACON_SYNC;
+	}
+
 	/* re-enable hardware interrupt */
 	ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
+	ath9k_ps_restore(sc);
 }
 
 irqreturn_t ath_isr(int irq, void *dev)
@@ -498,14 +520,11 @@
 	if (sc->sc_flags & SC_OP_INVALID)
 		return IRQ_NONE;
 
-	ath9k_ps_wakeup(sc);
 
 	/* shared irq, not for us */
 
-	if (!ath9k_hw_intrpend(ah)) {
-		ath9k_ps_restore(sc);
+	if (!ath9k_hw_intrpend(ah))
 		return IRQ_NONE;
-	}
 
 	/*
 	 * Figure out the reason(s) for the interrupt.  Note
@@ -520,10 +539,8 @@
 	 * If there are no status bits set, then this interrupt was not
 	 * for me (should have been caught above).
 	 */
-	if (!status) {
-		ath9k_ps_restore(sc);
+	if (!status)
 		return IRQ_NONE;
-	}
 
 	/* Cache the status */
 	sc->intrstatus = status;
@@ -560,20 +577,17 @@
 		ath9k_hw_set_interrupts(ah, sc->imask);
 	}
 
-	if (status & ATH9K_INT_TIM_TIMER) {
-		if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+	if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
+		if (status & ATH9K_INT_TIM_TIMER) {
 			/* Clear RxAbort bit so that we can
 			 * receive frames */
 			ath9k_hw_setpower(ah, ATH9K_PM_AWAKE);
-			ath9k_hw_setrxabort(ah, 0);
-			sched = true;
+			ath9k_hw_setrxabort(sc->sc_ah, 0);
 			sc->sc_flags |= SC_OP_WAIT_FOR_BEACON;
 		}
-	}
 
 chip_reset:
 
-	ath9k_ps_restore(sc);
 	ath_debug_stat_interrupt(sc, status);
 
 	if (sched) {
@@ -900,6 +914,13 @@
 		if (avp->av_opmode == NL80211_IFTYPE_STATION) {
 			sc->curaid = bss_conf->aid;
 			ath9k_hw_write_associd(sc);
+
+			/*
+			 * Request a re-configuration of Beacon related timers
+			 * on the receipt of the first Beacon frame (i.e.,
+			 * after time sync with the AP).
+			 */
+			sc->sc_flags |= SC_OP_BEACON_SYNC;
 		}
 
 		/* Configure the beacon */
@@ -1094,7 +1115,7 @@
 	if (r) {
 		DPRINTF(sc, ATH_DBG_FATAL,
 			"Unable to reset channel %u (%uMhz) ",
-			"reset status %u\n",
+			"reset status %d\n",
 			channel->center_freq, r);
 	}
 	spin_unlock_bh(&sc->sc_resetlock);
@@ -1146,7 +1167,7 @@
 	if (r) {
 		DPRINTF(sc, ATH_DBG_FATAL,
 			"Unable to reset channel %u (%uMhz) "
-			"reset status %u\n",
+			"reset status %d\n",
 			channel->center_freq, r);
 	}
 	spin_unlock_bh(&sc->sc_resetlock);
@@ -1416,8 +1437,6 @@
 	for (i = 0; i < sc->keymax; i++)
 		ath9k_hw_keyreset(ah, (u16) i);
 
-	error = ath_regd_init(&sc->sc_ah->regulatory, sc->hw->wiphy,
-			      ath9k_reg_notifier);
 	if (error)
 		goto bad;
 
@@ -1630,14 +1649,19 @@
 	if (error != 0)
 		return error;
 
-	reg = &sc->sc_ah->regulatory;
-
 	/* get mac address from hardware and set in mac80211 */
 
 	SET_IEEE80211_PERM_ADDR(hw, sc->sc_ah->macaddr);
 
 	ath_set_hw_capab(sc, hw);
 
+	error = ath_regd_init(&sc->sc_ah->regulatory, sc->hw->wiphy,
+			      ath9k_reg_notifier);
+	if (error)
+		return error;
+
+	reg = &sc->sc_ah->regulatory;
+
 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
 		setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
 		if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes))
@@ -1709,7 +1733,7 @@
 	r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false);
 	if (r)
 		DPRINTF(sc, ATH_DBG_FATAL,
-			"Unable to reset hardware; reset status %u\n", r);
+			"Unable to reset hardware; reset status %d\n", r);
 	spin_unlock_bh(&sc->sc_resetlock);
 
 	if (ath_startrecv(sc) != 0)
@@ -2001,7 +2025,7 @@
 	r = ath9k_hw_reset(sc->sc_ah, init_channel, false);
 	if (r) {
 		DPRINTF(sc, ATH_DBG_FATAL,
-			"Unable to reset hardware; reset status %u "
+			"Unable to reset hardware; reset status %d "
 			"(freq %u MHz)\n", r,
 			curchan->center_freq);
 		spin_unlock_bh(&sc->sc_resetlock);
@@ -2074,6 +2098,46 @@
 		goto exit;
 	}
 
+	if (sc->hw->conf.flags & IEEE80211_CONF_PS) {
+		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+		/*
+		 * mac80211 does not set PM field for normal data frames, so we
+		 * need to update that based on the current PS mode.
+		 */
+		if (ieee80211_is_data(hdr->frame_control) &&
+		    !ieee80211_is_nullfunc(hdr->frame_control) &&
+		    !ieee80211_has_pm(hdr->frame_control)) {
+			DPRINTF(sc, ATH_DBG_PS, "Add PM=1 for a TX frame "
+				"while in PS mode\n");
+			hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
+		}
+	}
+
+	if (unlikely(sc->sc_ah->power_mode != ATH9K_PM_AWAKE)) {
+		/*
+		 * We are using PS-Poll and mac80211 can request TX while in
+		 * power save mode. Need to wake up hardware for the TX to be
+		 * completed and if needed, also for RX of buffered frames.
+		 */
+		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+		ath9k_ps_wakeup(sc);
+		ath9k_hw_setrxabort(sc->sc_ah, 0);
+		if (ieee80211_is_pspoll(hdr->frame_control)) {
+			DPRINTF(sc, ATH_DBG_PS, "Sending PS-Poll to pick a "
+				"buffered frame\n");
+			sc->sc_flags |= SC_OP_WAIT_FOR_PSPOLL_DATA;
+		} else {
+			DPRINTF(sc, ATH_DBG_PS, "Wake up to complete TX\n");
+			sc->sc_flags |= SC_OP_WAIT_FOR_TX_ACK;
+		}
+		/*
+		 * The actual restore operation will happen only after
+		 * the sc_flags bit is cleared. We are just dropping
+		 * the ps_usecount here.
+		 */
+		ath9k_ps_restore(sc);
+	}
+
 	memset(&txctl, 0, sizeof(struct ath_tx_control));
 
 	/*
@@ -2311,7 +2375,10 @@
 			if (!(ah->caps.hw_caps &
 			      ATH9K_HW_CAP_AUTOSLEEP)) {
 				ath9k_hw_setrxabort(sc->sc_ah, 0);
-				sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON;
+				sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON |
+						  SC_OP_WAIT_FOR_CAB |
+						  SC_OP_WAIT_FOR_PSPOLL_DATA |
+						  SC_OP_WAIT_FOR_TX_ACK);
 				if (sc->imask & ATH9K_INT_TIM_TIMER) {
 					sc->imask &= ~ATH9K_INT_TIM_TIMER;
 					ath9k_hw_set_interrupts(sc->sc_ah,
@@ -2386,8 +2453,10 @@
 	*total_flags &= SUPPORTED_FILTERS;
 
 	sc->rx.rxfilter = *total_flags;
+	ath9k_ps_wakeup(sc);
 	rfilt = ath_calcrxfilter(sc);
 	ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
+	ath9k_ps_restore(sc);
 
 	DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter);
 }
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index b46badd..5014a19 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -473,6 +473,159 @@
 	spin_unlock_bh(&sc->rx.rxflushlock);
 }
 
+static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
+{
+	/* Check whether the Beacon frame has DTIM indicating buffered bc/mc */
+	struct ieee80211_mgmt *mgmt;
+	u8 *pos, *end, id, elen;
+	struct ieee80211_tim_ie *tim;
+
+	mgmt = (struct ieee80211_mgmt *)skb->data;
+	pos = mgmt->u.beacon.variable;
+	end = skb->data + skb->len;
+
+	while (pos + 2 < end) {
+		id = *pos++;
+		elen = *pos++;
+		if (pos + elen > end)
+			break;
+
+		if (id == WLAN_EID_TIM) {
+			if (elen < sizeof(*tim))
+				break;
+			tim = (struct ieee80211_tim_ie *) pos;
+			if (tim->dtim_count != 0)
+				break;
+			return tim->bitmap_ctrl & 0x01;
+		}
+
+		pos += elen;
+	}
+
+	return false;
+}
+
+static void ath_rx_ps_back_to_sleep(struct ath_softc *sc)
+{
+	sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB);
+}
+
+static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
+{
+	struct ieee80211_mgmt *mgmt;
+
+	if (skb->len < 24 + 8 + 2 + 2)
+		return;
+
+	mgmt = (struct ieee80211_mgmt *)skb->data;
+	if (memcmp(sc->curbssid, mgmt->bssid, ETH_ALEN) != 0)
+		return; /* not from our current AP */
+
+	if (sc->sc_flags & SC_OP_BEACON_SYNC) {
+		sc->sc_flags &= ~SC_OP_BEACON_SYNC;
+		DPRINTF(sc, ATH_DBG_PS, "Reconfigure Beacon timers based on "
+			"timestamp from the AP\n");
+		ath_beacon_config(sc, NULL);
+	}
+
+	if (!(sc->hw->conf.flags & IEEE80211_CONF_PS)) {
+		/* We are not in PS mode anymore; remain awake */
+		DPRINTF(sc, ATH_DBG_PS, "Not in PS mode anymore, remain "
+			"awake\n");
+		sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB);
+		return;
+	}
+
+	if (ath_beacon_dtim_pending_cab(skb)) {
+		/*
+		 * Remain awake waiting for buffered broadcast/multicast
+		 * frames.
+		 */
+		DPRINTF(sc, ATH_DBG_PS, "Received DTIM beacon indicating "
+			"buffered broadcast/multicast frame(s)\n");
+		sc->sc_flags |= SC_OP_WAIT_FOR_CAB;
+		return;
+	}
+
+	if (sc->sc_flags & SC_OP_WAIT_FOR_CAB) {
+		/*
+		 * This can happen if a broadcast frame is dropped or the AP
+		 * fails to send a frame indicating that all CAB frames have
+		 * been delivered.
+		 */
+		DPRINTF(sc, ATH_DBG_PS, "PS wait for CAB frames timed out\n");
+	}
+
+	/* No more broadcast/multicast frames to be received at this point. */
+	ath_rx_ps_back_to_sleep(sc);
+}
+
+static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr;
+
+	hdr = (struct ieee80211_hdr *)skb->data;
+
+	/* Process Beacon and CAB receive in PS state */
+	if ((sc->sc_flags & SC_OP_WAIT_FOR_BEACON) &&
+	    ieee80211_is_beacon(hdr->frame_control))
+		ath_rx_ps_beacon(sc, skb);
+	else if ((sc->sc_flags & SC_OP_WAIT_FOR_CAB) &&
+		 (ieee80211_is_data(hdr->frame_control) ||
+		  ieee80211_is_action(hdr->frame_control)) &&
+		 is_multicast_ether_addr(hdr->addr1) &&
+		 !ieee80211_has_moredata(hdr->frame_control)) {
+		DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to "
+			"sleep\n");
+		/*
+		 * No more broadcast/multicast frames to be received at this
+		 * point.
+		 */
+		ath_rx_ps_back_to_sleep(sc);
+	} else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) &&
+		   !is_multicast_ether_addr(hdr->addr1) &&
+		   !ieee80211_has_morefrags(hdr->frame_control)) {
+		sc->sc_flags &= ~SC_OP_WAIT_FOR_PSPOLL_DATA;
+		DPRINTF(sc, ATH_DBG_PS, "Going back to sleep after having "
+			"received PS-Poll data (0x%x)\n",
+			sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
+					SC_OP_WAIT_FOR_CAB |
+					SC_OP_WAIT_FOR_PSPOLL_DATA |
+					SC_OP_WAIT_FOR_TX_ACK));
+	}
+}
+
+static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb,
+				    struct ieee80211_rx_status *rx_status)
+{
+	struct ieee80211_hdr *hdr;
+
+	hdr = (struct ieee80211_hdr *)skb->data;
+
+	/* Send the frame to mac80211 */
+	if (is_multicast_ether_addr(hdr->addr1)) {
+		int i;
+		/*
+		 * Deliver broadcast/multicast frames to all suitable
+		 * virtual wiphys.
+		 */
+		/* TODO: filter based on channel configuration */
+		for (i = 0; i < sc->num_sec_wiphy; i++) {
+			struct ath_wiphy *aphy = sc->sec_wiphy[i];
+			struct sk_buff *nskb;
+			if (aphy == NULL)
+				continue;
+			nskb = skb_copy(skb, GFP_ATOMIC);
+			if (nskb)
+				__ieee80211_rx(aphy->hw, nskb, rx_status);
+		}
+		__ieee80211_rx(sc->hw, skb, rx_status);
+	} else {
+		/* Deliver unicast frames based on receiver address */
+		__ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, rx_status);
+	}
+}
+
 int ath_rx_tasklet(struct ath_softc *sc, int flush)
 {
 #define PA2DESC(_sc, _pa)                                               \
@@ -622,7 +775,7 @@
 
 		if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) {
 			rx_status.flag |= RX_FLAG_DECRYPTED;
-		} else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED)
+		} else if (ieee80211_has_protected(fc)
 			   && !decrypt_error && skb->len >= hdrlen + 4) {
 			keyix = skb->data[hdrlen + 3] >> 6;
 
@@ -631,36 +784,11 @@
 		}
 		if (ah->sw_mgmt_crypto &&
 		    (rx_status.flag & RX_FLAG_DECRYPTED) &&
-		    ieee80211_is_mgmt(hdr->frame_control)) {
+		    ieee80211_is_mgmt(fc)) {
 			/* Use software decrypt for management frames. */
 			rx_status.flag &= ~RX_FLAG_DECRYPTED;
 		}
 
-		/* Send the frame to mac80211 */
-		if (hdr->addr1[5] & 0x01) {
-			int i;
-			/*
-			 * Deliver broadcast/multicast frames to all suitable
-			 * virtual wiphys.
-			 */
-			/* TODO: filter based on channel configuration */
-			for (i = 0; i < sc->num_sec_wiphy; i++) {
-				struct ath_wiphy *aphy = sc->sec_wiphy[i];
-				struct sk_buff *nskb;
-				if (aphy == NULL)
-					continue;
-				nskb = skb_copy(skb, GFP_ATOMIC);
-				if (nskb)
-					__ieee80211_rx(aphy->hw, nskb,
-						       &rx_status);
-			}
-			__ieee80211_rx(sc->hw, skb, &rx_status);
-		} else {
-			/* Deliver unicast frames based on receiver address */
-			__ieee80211_rx(ath_get_virt_hw(sc, hdr), skb,
-				       &rx_status);
-		}
-
 		/* We will now give hardware our shiny new allocated skb */
 		bf->bf_mpdu = requeue_skb;
 		bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data,
@@ -672,6 +800,7 @@
 			bf->bf_mpdu = NULL;
 			DPRINTF(sc, ATH_DBG_FATAL,
 				"dma_mapping_error() on RX\n");
+			ath_rx_send_to_mac80211(sc, skb, &rx_status);
 			break;
 		}
 		bf->bf_dmacontext = bf->bf_buf_addr;
@@ -687,11 +816,12 @@
 			sc->rx.rxotherant = 0;
 		}
 
-		if (ieee80211_is_beacon(fc) &&
-				(sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) {
-			sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON;
-			ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
-		}
+		if (unlikely(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
+					     SC_OP_WAIT_FOR_PSPOLL_DATA)))
+			ath_rx_ps(sc, skb);
+
+		ath_rx_send_to_mac80211(sc, skb, &rx_status);
+
 requeue:
 		list_move_tail(&bf->list, &sc->rx.rxbuf);
 		ath_rx_buf_link(sc, bf);
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 41c4282..a8def4f 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1070,7 +1070,7 @@
 		r = ath9k_hw_reset(ah, sc->sc_ah->curchan, true);
 		if (r)
 			DPRINTF(sc, ATH_DBG_FATAL,
-				"Unable to reset hardware; reset status %u\n",
+				"Unable to reset hardware; reset status %d\n",
 				r);
 		spin_unlock_bh(&sc->sc_resetlock);
 	}
@@ -1790,6 +1790,16 @@
 		skb_pull(skb, padsize);
 	}
 
+	if (sc->sc_flags & SC_OP_WAIT_FOR_TX_ACK) {
+		sc->sc_flags &= ~SC_OP_WAIT_FOR_TX_ACK;
+		DPRINTF(sc, ATH_DBG_PS, "Going back to sleep after having "
+			"received TX status (0x%x)\n",
+			sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
+					SC_OP_WAIT_FOR_CAB |
+					SC_OP_WAIT_FOR_PSPOLL_DATA |
+					SC_OP_WAIT_FOR_TX_ACK));
+	}
+
 	if (frame_type == ATH9K_NOT_INTERNAL)
 		ieee80211_tx_status(hw, skb);
 	else
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index fdf07c8..7a89f9f 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -200,8 +200,10 @@
 				continue;
 
 			if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-				r = freq_reg_info(wiphy, ch->center_freq,
-					&bandwidth, &reg_rule);
+				r = freq_reg_info(wiphy,
+						  ch->center_freq,
+						  bandwidth,
+						  &reg_rule);
 				if (r)
 					continue;
 				/*
@@ -265,7 +267,7 @@
 	 */
 
 	ch = &sband->channels[11]; /* CH 12 */
-	r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, &reg_rule);
+	r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
 	if (!r) {
 		if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
 			if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
@@ -273,7 +275,7 @@
 	}
 
 	ch = &sband->channels[12]; /* CH 13 */
-	r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, &reg_rule);
+	r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
 	if (!r) {
 		if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
 			if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 2615aaf..cb4a871 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -3553,28 +3553,26 @@
 
 	B43_WARN_ON(wl->vif != vif);
 
+	spin_lock_irqsave(&wl->irq_lock, flags);
 	if (changed & BSS_CHANGED_BSSID) {
-		spin_lock_irqsave(&wl->irq_lock, flags);
 		if (conf->bssid)
 			memcpy(wl->bssid, conf->bssid, ETH_ALEN);
 		else
 			memset(wl->bssid, 0, ETH_ALEN);
-
-		if (b43_status(dev) >= B43_STAT_INITIALIZED) {
-			if (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
-			    b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) {
-				B43_WARN_ON(vif->type != wl->if_type);
-				if (changed & BSS_CHANGED_BEACON)
-					b43_update_templates(wl);
-			} else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) {
-				if (changed & BSS_CHANGED_BEACON)
-					b43_update_templates(wl);
-			}
-			b43_write_mac_bssid_templates(dev);
-		}
-		spin_unlock_irqrestore(&wl->irq_lock, flags);
 	}
 
+	if (b43_status(dev) >= B43_STAT_INITIALIZED) {
+		if (changed & BSS_CHANGED_BEACON &&
+		    (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
+		     b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) ||
+		     b43_is_mode(wl, NL80211_IFTYPE_ADHOC)))
+			b43_update_templates(wl);
+
+		if (changed & BSS_CHANGED_BSSID)
+			b43_write_mac_bssid_templates(dev);
+	}
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+
 	b43_mac_suspend(dev);
 
 	/* Update templates for AP/mesh mode. */
@@ -3639,7 +3637,7 @@
 	err = -EINVAL;
 	switch (key->alg) {
 	case ALG_WEP:
-		if (key->keylen == LEN_WEP40)
+		if (key->keylen == WLAN_KEY_LEN_WEP40)
 			algorithm = B43_SEC_ALGO_WEP40;
 		else
 			algorithm = B43_SEC_ALGO_WEP104;
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
index da59ef0..19a4b0b 100644
--- a/drivers/net/wireless/b43legacy/b43legacy.h
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -694,8 +694,8 @@
 	/* Reason code of the last interrupt. */
 	u32 irq_reason;
 	u32 dma_reason[6];
-	/* saved irq enable/disable state bitfield. */
-	u32 irq_savedstate;
+	/* The currently active generic-interrupt mask. */
+	u32 irq_mask;
 	/* Link Quality calculation context. */
 	struct b43legacy_noise_calculation noisecalc;
 	/* if > 0 MAC is suspended. if == 0 MAC is enabled. */
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 07c7898..f6f3fbf 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -583,35 +583,6 @@
 	b43legacy_set_slot_time(dev, 20);
 }
 
-/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
- * Returns the _previously_ enabled IRQ mask.
- */
-static inline u32 b43legacy_interrupt_enable(struct b43legacy_wldev *dev,
-					     u32 mask)
-{
-	u32 old_mask;
-
-	old_mask = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
-	b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, old_mask |
-			  mask);
-
-	return old_mask;
-}
-
-/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable.
- * Returns the _previously_ enabled IRQ mask.
- */
-static inline u32 b43legacy_interrupt_disable(struct b43legacy_wldev *dev,
-					      u32 mask)
-{
-	u32 old_mask;
-
-	old_mask = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
-	b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, old_mask & ~mask);
-
-	return old_mask;
-}
-
 /* Synchronize IRQ top- and bottom-half.
  * IRQs must be masked before calling this.
  * This must not be called with the irq_lock held.
@@ -1200,7 +1171,7 @@
 	/* This is the bottom half of the asynchronous beacon update. */
 
 	/* Ignore interrupt in the future. */
-	dev->irq_savedstate &= ~B43legacy_IRQ_BEACON;
+	dev->irq_mask &= ~B43legacy_IRQ_BEACON;
 
 	cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
 	beacon0_valid = (cmd & B43legacy_MACCMD_BEACON0_VALID);
@@ -1209,7 +1180,7 @@
 	/* Schedule interrupt manually, if busy. */
 	if (beacon0_valid && beacon1_valid) {
 		b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, B43legacy_IRQ_BEACON);
-		dev->irq_savedstate |= B43legacy_IRQ_BEACON;
+		dev->irq_mask |= B43legacy_IRQ_BEACON;
 		return;
 	}
 
@@ -1247,12 +1218,11 @@
 	dev = wl->current_dev;
 	if (likely(dev && (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED))) {
 		spin_lock_irq(&wl->irq_lock);
-		/* update beacon right away or defer to irq */
-		dev->irq_savedstate = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
+		/* Update beacon right away or defer to IRQ. */
 		handle_irq_beacon(dev);
 		/* The handler might have updated the IRQ mask. */
 		b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK,
-			    dev->irq_savedstate);
+				  dev->irq_mask);
 		mmiowb();
 		spin_unlock_irq(&wl->irq_lock);
 	}
@@ -1398,7 +1368,7 @@
 	if (reason & B43legacy_IRQ_TX_OK)
 		handle_irq_transmit_status(dev);
 
-	b43legacy_interrupt_enable(dev, dev->irq_savedstate);
+	b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, dev->irq_mask);
 	mmiowb();
 	spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
 }
@@ -1450,18 +1420,18 @@
 	struct b43legacy_wldev *dev = dev_id;
 	u32 reason;
 
-	if (!dev)
-		return IRQ_NONE;
+	B43legacy_WARN_ON(!dev);
 
 	spin_lock(&dev->wl->irq_lock);
 
-	if (b43legacy_status(dev) < B43legacy_STAT_STARTED)
+	if (unlikely(b43legacy_status(dev) < B43legacy_STAT_STARTED))
+		/* This can only happen on shared IRQ lines. */
 		goto out;
 	reason = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
 	if (reason == 0xffffffff) /* shared IRQ */
 		goto out;
 	ret = IRQ_HANDLED;
-	reason &= b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
+	reason &= dev->irq_mask;
 	if (!reason)
 		goto out;
 
@@ -1485,10 +1455,9 @@
 					      & 0x0000DC00;
 
 	b43legacy_interrupt_ack(dev, reason);
-	/* disable all IRQs. They are enabled again in the bottom half. */
-	dev->irq_savedstate = b43legacy_interrupt_disable(dev,
-							  B43legacy_IRQ_ALL);
-	/* save the reason code and call our bottom half. */
+	/* Disable all IRQs. They are enabled again in the bottom half. */
+	b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0);
+	/* Save the reason code and call our bottom half. */
 	dev->irq_reason = reason;
 	tasklet_schedule(&dev->isr_tasklet);
 out:
@@ -1948,7 +1917,8 @@
 
 		/* Re-enable IRQs. */
 		spin_lock_irq(&dev->wl->irq_lock);
-		b43legacy_interrupt_enable(dev, dev->irq_savedstate);
+		b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK,
+				  dev->irq_mask);
 		spin_unlock_irq(&dev->wl->irq_lock);
 	}
 }
@@ -1967,10 +1937,9 @@
 		/* Mask IRQs before suspending MAC. Otherwise
 		 * the MAC stays busy and won't suspend. */
 		spin_lock_irq(&dev->wl->irq_lock);
-		tmp = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL);
+		b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0);
 		spin_unlock_irq(&dev->wl->irq_lock);
 		b43legacy_synchronize_irq(dev);
-		dev->irq_savedstate = tmp;
 
 		b43legacy_power_saving_ctl_bits(dev, -1, 1);
 		b43legacy_write32(dev, B43legacy_MMIO_MACCTL,
@@ -2659,7 +2628,6 @@
 	int antenna_tx;
 	int antenna_rx;
 	int err = 0;
-	u32 savedirqs;
 
 	antenna_tx = B43legacy_ANTENNA_DEFAULT;
 	antenna_rx = B43legacy_ANTENNA_DEFAULT;
@@ -2699,7 +2667,7 @@
 		spin_unlock_irqrestore(&wl->irq_lock, flags);
 		goto out_unlock_mutex;
 	}
-	savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL);
+	b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0);
 	spin_unlock_irqrestore(&wl->irq_lock, flags);
 	b43legacy_synchronize_irq(dev);
 
@@ -2738,7 +2706,7 @@
 	}
 
 	spin_lock_irqsave(&wl->irq_lock, flags);
-	b43legacy_interrupt_enable(dev, savedirqs);
+	b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, dev->irq_mask);
 	mmiowb();
 	spin_unlock_irqrestore(&wl->irq_lock, flags);
 out_unlock_mutex:
@@ -2801,7 +2769,6 @@
 	struct b43legacy_wldev *dev;
 	struct b43legacy_phy *phy;
 	unsigned long flags;
-	u32 savedirqs;
 
 	mutex_lock(&wl->mutex);
 	B43legacy_WARN_ON(wl->vif != vif);
@@ -2817,31 +2784,28 @@
 		spin_unlock_irqrestore(&wl->irq_lock, flags);
 		goto out_unlock_mutex;
 	}
-	savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL);
+	b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0);
 
 	if (changed & BSS_CHANGED_BSSID) {
-		spin_unlock_irqrestore(&wl->irq_lock, flags);
 		b43legacy_synchronize_irq(dev);
 
 		if (conf->bssid)
 			memcpy(wl->bssid, conf->bssid, ETH_ALEN);
 		else
 			memset(wl->bssid, 0, ETH_ALEN);
-
-		if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
-			if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) {
-				B43legacy_WARN_ON(vif->type != NL80211_IFTYPE_AP);
-				if (changed & BSS_CHANGED_BEACON)
-					b43legacy_update_templates(wl);
-			} else if (b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC)) {
-				if (changed & BSS_CHANGED_BEACON)
-					b43legacy_update_templates(wl);
-			}
-			b43legacy_write_mac_bssid_templates(dev);
-		}
-		spin_unlock_irqrestore(&wl->irq_lock, flags);
 	}
 
+	if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
+		if (changed & BSS_CHANGED_BEACON &&
+		    (b43legacy_is_mode(wl, NL80211_IFTYPE_AP) ||
+		     b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC)))
+			b43legacy_update_templates(wl);
+
+		if (changed & BSS_CHANGED_BSSID)
+			b43legacy_write_mac_bssid_templates(dev);
+	}
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+
 	b43legacy_mac_suspend(dev);
 
 	if (changed & BSS_CHANGED_BEACON_INT &&
@@ -2862,7 +2826,7 @@
 	b43legacy_mac_enable(dev);
 
 	spin_lock_irqsave(&wl->irq_lock, flags);
-	b43legacy_interrupt_enable(dev, savedirqs);
+	b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, dev->irq_mask);
 	/* XXX: why? */
 	mmiowb();
 	spin_unlock_irqrestore(&wl->irq_lock, flags);
@@ -2922,8 +2886,7 @@
 	 * setting the status to INITIALIZED, as the interrupt handler
 	 * won't care about IRQs then. */
 	spin_lock_irqsave(&wl->irq_lock, flags);
-	dev->irq_savedstate = b43legacy_interrupt_disable(dev,
-							  B43legacy_IRQ_ALL);
+	b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0);
 	b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); /* flush */
 	spin_unlock_irqrestore(&wl->irq_lock, flags);
 	b43legacy_synchronize_irq(dev);
@@ -2963,7 +2926,7 @@
 
 	/* Start data flow (TX/RX) */
 	b43legacy_mac_enable(dev);
-	b43legacy_interrupt_enable(dev, dev->irq_savedstate);
+	b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, dev->irq_mask);
 
 	/* Start maintenance work */
 	b43legacy_periodic_tasks_setup(dev);
@@ -3126,7 +3089,7 @@
 	/* IRQ related flags */
 	dev->irq_reason = 0;
 	memset(dev->dma_reason, 0, sizeof(dev->dma_reason));
-	dev->irq_savedstate = B43legacy_IRQ_MASKTEMPLATE;
+	dev->irq_mask = B43legacy_IRQ_MASKTEMPLATE;
 
 	dev->mac_suspended = 1;
 
diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c
index 746d536..51866c9 100644
--- a/drivers/net/wireless/b43legacy/pio.c
+++ b/drivers/net/wireless/b43legacy/pio.c
@@ -443,7 +443,7 @@
 	pio->queue3 = queue;
 
 	if (dev->dev->id.revision < 3)
-		dev->irq_savedstate |= B43legacy_IRQ_PIO_WORKAROUND;
+		dev->irq_mask |= B43legacy_IRQ_PIO_WORKAROUND;
 
 	b43legacydbg(dev->wl, "PIO initialized\n");
 	err = 0;
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
index ac22f59..bd7e520 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
@@ -44,6 +44,15 @@
 #include "iwl-core.h"
 #include "iwl-dev.h"
 
+#ifdef CONFIG_IWLWIFI_DEBUG
+static const char *led_type_str[] = {
+	__stringify(IWL_LED_TRG_TX),
+	__stringify(IWL_LED_TRG_RX),
+	__stringify(IWL_LED_TRG_ASSOC),
+	__stringify(IWL_LED_TRG_RADIO),
+	NULL
+};
+#endif /* CONFIG_IWLWIFI_DEBUG */
 
 static const struct {
 	u16 brightness;
@@ -61,7 +70,7 @@
 	{10, 110, 110},
 	{5, 130, 130},
 	{0, 167, 167},
-	/*SOLID_ON*/
+	/* SOLID_ON */
 	{-1, IWL_LED_SOLID, 0}
 };
 
@@ -143,6 +152,30 @@
 }
 
 /*
+ *  Set led on in case of association
+ *  */
+static int iwl3945_led_associate(struct iwl_priv *priv, int led_id)
+{
+	IWL_DEBUG_LED(priv, "Associated\n");
+
+	priv->allow_blinking = 1;
+	return iwl3945_led_on(priv, led_id);
+}
+/* Set Led off in case of disassociation */
+static int iwl3945_led_disassociate(struct iwl_priv *priv, int led_id)
+{
+	IWL_DEBUG_LED(priv, "Disassociated\n");
+
+	priv->allow_blinking = 0;
+	if (iwl_is_rfkill(priv))
+		iwl3945_led_off(priv, led_id);
+	else
+		iwl3945_led_on(priv, led_id);
+
+	return 0;
+}
+
+/*
  * brightness call back function for Tx/Rx LED
  */
 static int iwl3945_led_associated(struct iwl_priv *priv, int led_id)
@@ -165,26 +198,21 @@
 				enum led_brightness brightness)
 {
 	struct iwl_led *led = container_of(led_cdev,
-					       struct iwl_led, led_dev);
+					   struct iwl_led, led_dev);
 	struct iwl_priv *priv = led->priv;
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
+	IWL_DEBUG_LED(priv, "Led type = %s brightness = %d\n",
+			led_type_str[led->type], brightness);
+
 	switch (brightness) {
 	case LED_FULL:
-		if (led->type == IWL_LED_TRG_ASSOC) {
-			priv->allow_blinking = 1;
-			IWL_DEBUG_LED(priv, "MAC is  associated\n");
-		}
 		if (led->led_on)
 			led->led_on(priv, IWL_LED_LINK);
 		break;
 	case LED_OFF:
-		if (led->type == IWL_LED_TRG_ASSOC) {
-			priv->allow_blinking = 0;
-			IWL_DEBUG_LED(priv, "MAC is disassociated\n");
-		}
 		if (led->led_off)
 			led->led_off(priv, IWL_LED_LINK);
 		break;
@@ -197,8 +225,6 @@
 	}
 }
 
-
-
 /*
  * Register led class with the system
  */
@@ -237,12 +263,12 @@
 static inline u8 get_blink_rate(struct iwl_priv *priv)
 {
 	int index;
-	u64 current_tpt = priv->rxtxpackets;
-	s64 tpt = current_tpt - priv->led_tpt;
+	s64 tpt = priv->rxtxpackets;
 
 	if (tpt < 0)
 		tpt = -tpt;
-	priv->led_tpt = current_tpt;
+
+	IWL_DEBUG_LED(priv, "tpt %lld \n", (long long)tpt);
 
 	if (!priv->allow_blinking)
 		index = IWL_MAX_BLINK_TBL;
@@ -250,13 +276,9 @@
 		for (index = 0; index < IWL_MAX_BLINK_TBL; index++)
 			if (tpt > (blink_tbl[index].brightness * IWL_1MB_RATE))
 				break;
-	return index;
-}
 
-static inline int is_rf_kill(struct iwl_priv *priv)
-{
-	return test_bit(STATUS_RF_KILL_HW, &priv->status) ||
-		test_bit(STATUS_RF_KILL_SW, &priv->status);
+	IWL_DEBUG_LED(priv, "LED BLINK IDX=%d\n", index);
+	return index;
 }
 
 /*
@@ -272,7 +294,7 @@
 		priv->last_blink_time = 0;
 		return;
 	}
-	if (is_rf_kill(priv)) {
+	if (iwl_is_rfkill(priv)) {
 		priv->last_blink_time = 0;
 		return;
 	}
@@ -341,8 +363,8 @@
 				   IWL_LED_TRG_ASSOC, 0, trigger);
 
 	/* for assoc always turn led on */
-	priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_on;
-	priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_on;
+	priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_associate;
+	priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_disassociate;
 	priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL;
 
 	if (ret)
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 5b0c6e5..fd65e1c3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -98,7 +98,6 @@
  *   ... and set IWL_EVT_DISABLE to 1. */
 void iwl3945_disable_events(struct iwl_priv *priv)
 {
-	int ret;
 	int i;
 	u32 base;		/* SRAM address of event log header */
 	u32 disable_ptr;	/* SRAM address of event-disable bitmap array */
@@ -159,26 +158,17 @@
 		return;
 	}
 
-	ret = iwl_grab_nic_access(priv);
-	if (ret) {
-		IWL_WARN(priv, "Can not read from adapter at this time.\n");
-		return;
-	}
-
 	disable_ptr = iwl_read_targ_mem(priv, base + (4 * sizeof(u32)));
 	array_size = iwl_read_targ_mem(priv, base + (5 * sizeof(u32)));
-	iwl_release_nic_access(priv);
 
 	if (IWL_EVT_DISABLE && (array_size == IWL_EVT_DISABLE_SIZE)) {
 		IWL_DEBUG_INFO(priv, "Disabling selected uCode log events at 0x%x\n",
 			       disable_ptr);
-		ret = iwl_grab_nic_access(priv);
 		for (i = 0; i < IWL_EVT_DISABLE_SIZE; i++)
 			iwl_write_targ_mem(priv,
 					   disable_ptr + (i * sizeof(u32)),
 					   evt_disable[i]);
 
-		iwl_release_nic_access(priv);
 	} else {
 		IWL_DEBUG_INFO(priv, "Selected uCode log events may be disabled\n");
 		IWL_DEBUG_INFO(priv, "  by writing \"1\"s into disable bitmap\n");
@@ -908,55 +898,30 @@
 
 static int iwl3945_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
 {
-	int ret;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	ret = iwl_grab_nic_access(priv);
-	if (ret) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return ret;
-	}
-
 	if (src == IWL_PWR_SRC_VAUX) {
 		if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) {
 			iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
 					APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
 					~APMG_PS_CTRL_MSK_PWR_SRC);
-			iwl_release_nic_access(priv);
 
 			iwl_poll_bit(priv, CSR_GPIO_IN,
 				     CSR_GPIO_IN_VAL_VAUX_PWR_SRC,
 				     CSR_GPIO_IN_BIT_AUX_POWER, 5000);
-		} else {
-			iwl_release_nic_access(priv);
 		}
 	} else {
 		iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
 				APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
 				~APMG_PS_CTRL_MSK_PWR_SRC);
 
-		iwl_release_nic_access(priv);
 		iwl_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC,
 			     CSR_GPIO_IN_BIT_AUX_POWER, 5000);	/* uS */
 	}
-	spin_unlock_irqrestore(&priv->lock, flags);
 
-	return ret;
+	return 0;
 }
 
 static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
 {
-	int rc;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_nic_access(priv);
-	if (rc) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return rc;
-	}
-
 	iwl_write_direct32(priv, FH39_RCSR_RBD_BASE(0), rxq->dma_addr);
 	iwl_write_direct32(priv, FH39_RCSR_RPTR_ADDR(0), rxq->rb_stts_dma);
 	iwl_write_direct32(priv, FH39_RCSR_WPTR(0), 0);
@@ -973,23 +938,11 @@
 	/* fake read to flush all prev I/O */
 	iwl_read_direct32(priv, FH39_RSSR_CTRL);
 
-	iwl_release_nic_access(priv);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
 	return 0;
 }
 
 static int iwl3945_tx_reset(struct iwl_priv *priv)
 {
-	int rc;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_nic_access(priv);
-	if (rc) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return rc;
-	}
 
 	/* bypass mode */
 	iwl_write_prph(priv, ALM_SCD_MODE_REG, 0x2);
@@ -1017,8 +970,6 @@
 		FH39_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH |
 		FH39_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH);
 
-	iwl_release_nic_access(priv);
-	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
 }
@@ -1061,7 +1012,7 @@
 
 static int iwl3945_apm_init(struct iwl_priv *priv)
 {
-	int ret = 0;
+	int ret;
 
 	iwl_power_initialize(priv);
 
@@ -1083,10 +1034,6 @@
 		goto out;
 	}
 
-	ret = iwl_grab_nic_access(priv);
-	if (ret)
-		goto out;
-
 	/* enable DMA */
 	iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT |
 						APMG_CLK_VAL_BSM_CLK_RQT);
@@ -1097,7 +1044,6 @@
 	iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
 			  APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
 
-	iwl_release_nic_access(priv);
 out:
 	return ret;
 }
@@ -1196,22 +1142,13 @@
 
 	iwl3945_rx_init(priv, rxq);
 
-	spin_lock_irqsave(&priv->lock, flags);
 
 	/* Look at using this instead:
 	rxq->need_update = 1;
 	iwl_rx_queue_update_write_ptr(priv, rxq);
 	*/
 
-	rc = iwl_grab_nic_access(priv);
-	if (rc) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return rc;
-	}
 	iwl_write_direct32(priv, FH39_RCSR_WPTR(0), rxq->write & ~7);
-	iwl_release_nic_access(priv);
-
-	spin_unlock_irqrestore(&priv->lock, flags);
 
 	rc = iwl3945_txq_ctx_reset(priv);
 	if (rc)
@@ -1243,14 +1180,6 @@
 void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
 {
 	int txq_id;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	if (iwl_grab_nic_access(priv)) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		iwl3945_hw_txq_ctx_free(priv);
-		return;
-	}
 
 	/* stop SCD */
 	iwl_write_prph(priv, ALM_SCD_MODE_REG, 0);
@@ -1263,9 +1192,6 @@
 				1000);
 	}
 
-	iwl_release_nic_access(priv);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
 	iwl3945_hw_txq_ctx_free(priv);
 }
 
@@ -1310,12 +1236,8 @@
 
 static int iwl3945_apm_reset(struct iwl_priv *priv)
 {
-	int rc;
-	unsigned long flags;
-
 	iwl3945_apm_stop_master(priv);
 
-	spin_lock_irqsave(&priv->lock, flags);
 
 	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
 	udelay(10);
@@ -1325,36 +1247,31 @@
 	iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
 			 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
 
-	rc = iwl_grab_nic_access(priv);
-	if (!rc) {
-		iwl_write_prph(priv, APMG_CLK_CTRL_REG,
-					 APMG_CLK_VAL_BSM_CLK_RQT);
+	iwl_write_prph(priv, APMG_CLK_CTRL_REG,
+				APMG_CLK_VAL_BSM_CLK_RQT);
 
-		iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0);
-		iwl_write_prph(priv, APMG_RTC_INT_STT_REG,
+	iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0);
+	iwl_write_prph(priv, APMG_RTC_INT_STT_REG,
 					0xFFFFFFFF);
 
-		/* enable DMA */
-		iwl_write_prph(priv, APMG_CLK_EN_REG,
-					 APMG_CLK_VAL_DMA_CLK_RQT |
-					 APMG_CLK_VAL_BSM_CLK_RQT);
-		udelay(10);
+	/* enable DMA */
+	iwl_write_prph(priv, APMG_CLK_EN_REG,
+				APMG_CLK_VAL_DMA_CLK_RQT |
+				APMG_CLK_VAL_BSM_CLK_RQT);
+	udelay(10);
 
-		iwl_set_bits_prph(priv, APMG_PS_CTRL_REG,
+	iwl_set_bits_prph(priv, APMG_PS_CTRL_REG,
 				APMG_PS_CTRL_VAL_RESET_REQ);
-		udelay(5);
-		iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG,
+	udelay(5);
+	iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG,
 				APMG_PS_CTRL_VAL_RESET_REQ);
-		iwl_release_nic_access(priv);
-	}
 
 	/* Clear the 'host command active' bit... */
 	clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
 
 	wake_up_interruptible(&priv->wait_command_queue);
-	spin_unlock_irqrestore(&priv->lock, flags);
 
-	return rc;
+	return 0;
 }
 
 /**
@@ -2500,14 +2417,6 @@
 int iwl3945_hw_rxq_stop(struct iwl_priv *priv)
 {
 	int rc;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_nic_access(priv);
-	if (rc) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return rc;
-	}
 
 	iwl_write_direct32(priv, FH39_RCSR_CONFIG(0), 0);
 	rc = iwl_poll_direct_bit(priv, FH39_RSSR_STATUS,
@@ -2515,28 +2424,17 @@
 	if (rc < 0)
 		IWL_ERR(priv, "Can't stop Rx DMA.\n");
 
-	iwl_release_nic_access(priv);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
 	return 0;
 }
 
 int iwl3945_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq)
 {
-	int rc;
-	unsigned long flags;
 	int txq_id = txq->q.id;
 
 	struct iwl3945_shared *shared_data = priv->shared_virt;
 
 	shared_data->tx_base_ptr[txq_id] = cpu_to_le32((u32)txq->q.dma_addr);
 
-	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_nic_access(priv);
-	if (rc) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return rc;
-	}
 	iwl_write_direct32(priv, FH39_CBCC_CTRL(txq_id), 0);
 	iwl_write_direct32(priv, FH39_CBCC_BASE(txq_id), 0);
 
@@ -2546,11 +2444,9 @@
 		FH39_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD |
 		FH39_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL |
 		FH39_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE);
-	iwl_release_nic_access(priv);
 
 	/* fake read to flush all prev. writes */
 	iwl_read32(priv, FH39_TSSR_CBB_BASE);
-	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
 }
@@ -2858,10 +2754,6 @@
 	inst_len = priv->ucode_init.len;
 	data_len = priv->ucode_init_data.len;
 
-	rc = iwl_grab_nic_access(priv);
-	if (rc)
-		return rc;
-
 	iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
 	iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
 	iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
@@ -2875,10 +2767,8 @@
 					  le32_to_cpu(*image));
 
 	rc = iwl3945_verify_bsm(priv);
-	if (rc) {
-		iwl_release_nic_access(priv);
+	if (rc)
 		return rc;
-	}
 
 	/* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
 	iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0);
@@ -2910,8 +2800,6 @@
 	iwl_write_prph(priv, BSM_WR_CTRL_REG,
 		BSM_WR_CTRL_REG_BIT_START_EN);
 
-	iwl_release_nic_access(priv);
-
 	return 0;
 }
 
@@ -2950,6 +2838,7 @@
 	.send_tx_power	= iwl3945_send_tx_power,
 	.is_valid_rtc_data_addr = iwl3945_hw_valid_rtc_data_addr,
 	.post_associate = iwl3945_post_associate,
+	.isr = iwl_isr_legacy,
 	.config_ap = iwl3945_config_ap,
 };
 
@@ -2983,7 +2872,8 @@
 	.eeprom_size = IWL3945_EEPROM_IMG_SIZE,
 	.eeprom_ver = EEPROM_3945_EEPROM_VERSION,
 	.ops = &iwl3945_ops,
-	.mod_params = &iwl3945_mod_params
+	.mod_params = &iwl3945_mod_params,
+	.use_isr_legacy = true
 };
 
 static struct iwl_cfg iwl3945_abg_cfg = {
@@ -2995,7 +2885,8 @@
 	.eeprom_size = IWL3945_EEPROM_IMG_SIZE,
 	.eeprom_ver = EEPROM_3945_EEPROM_VERSION,
 	.ops = &iwl3945_ops,
-	.mod_params = &iwl3945_mod_params
+	.mod_params = &iwl3945_mod_params,
+	.use_isr_legacy = true
 };
 
 struct pci_device_id iwl3945_hw_card_ids[] = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index a98ff4e..a0b2941 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -163,10 +163,6 @@
 	inst_len = priv->ucode_init.len;
 	data_len = priv->ucode_init_data.len;
 
-	ret = iwl_grab_nic_access(priv);
-	if (ret)
-		return ret;
-
 	iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
 	iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
 	iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
@@ -179,10 +175,8 @@
 		_iwl_write_prph(priv, reg_offset, le32_to_cpu(*image));
 
 	ret = iwl4965_verify_bsm(priv);
-	if (ret) {
-		iwl_release_nic_access(priv);
+	if (ret)
 		return ret;
-	}
 
 	/* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
 	iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0);
@@ -211,7 +205,6 @@
 	 *   (e.g. when powering back up after power-save shutdown) */
 	iwl_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START_EN);
 
-	iwl_release_nic_access(priv);
 
 	return 0;
 }
@@ -229,20 +222,12 @@
 {
 	dma_addr_t pinst;
 	dma_addr_t pdata;
-	unsigned long flags;
 	int ret = 0;
 
 	/* bits 35:4 for 4965 */
 	pinst = priv->ucode_code.p_addr >> 4;
 	pdata = priv->ucode_data_backup.p_addr >> 4;
 
-	spin_lock_irqsave(&priv->lock, flags);
-	ret = iwl_grab_nic_access(priv);
-	if (ret) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return ret;
-	}
-
 	/* Tell bootstrap uCode where to find image to load */
 	iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
 	iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
@@ -253,10 +238,6 @@
 	 *   that all new ptr/size info is in place */
 	iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG,
 				 priv->ucode_code.len | BSM_DRAM_INST_LOAD);
-	iwl_release_nic_access(priv);
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-
 	IWL_DEBUG_INFO(priv, "Runtime uCode pointers are set.\n");
 
 	return ret;
@@ -312,10 +293,12 @@
 	queue_work(priv->workqueue, &priv->restart);
 }
 
-static int is_fat_channel(__le32 rxon_flags)
+static bool is_fat_channel(__le32 rxon_flags)
 {
-	return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) ||
-		(rxon_flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK);
+	int chan_mod = le32_to_cpu(rxon_flags & RXON_FLG_CHANNEL_MODE_MSK)
+				    >> RXON_FLG_CHANNEL_MODE_POS;
+	return ((chan_mod == CHANNEL_MODE_PURE_40) ||
+		  (chan_mod == CHANNEL_MODE_MIXED));
 }
 
 /*
@@ -358,10 +341,6 @@
 		goto out;
 	}
 
-	ret = iwl_grab_nic_access(priv);
-	if (ret)
-		goto out;
-
 	/* enable DMA */
 	iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT |
 						APMG_CLK_VAL_BSM_CLK_RQT);
@@ -372,7 +351,6 @@
 	iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
 			  APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
 
-	iwl_release_nic_access(priv);
 out:
 	return ret;
 }
@@ -454,11 +432,9 @@
 static int iwl4965_apm_reset(struct iwl_priv *priv)
 {
 	int ret = 0;
-	unsigned long flags;
 
 	iwl4965_apm_stop_master(priv);
 
-	spin_lock_irqsave(&priv->lock, flags);
 
 	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
 
@@ -475,9 +451,6 @@
 
 	udelay(10);
 
-	ret = iwl_grab_nic_access(priv);
-	if (ret)
-		goto out;
 	/* Enable DMA and BSM Clock */
 	iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT |
 					      APMG_CLK_VAL_BSM_CLK_RQT);
@@ -488,14 +461,10 @@
 	iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
 			  APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
 
-	iwl_release_nic_access(priv);
-
 	clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
 	wake_up_interruptible(&priv->wait_command_queue);
 
 out:
-	spin_unlock_irqrestore(&priv->lock, flags);
-
 	return ret;
 }
 
@@ -681,18 +650,11 @@
 {
 	u32 a;
 	unsigned long flags;
-	int ret;
 	int i, chan;
 	u32 reg_val;
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	ret = iwl_grab_nic_access(priv);
-	if (ret) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return ret;
-	}
-
 	/* Clear 4965's internal Tx Scheduler data base */
 	priv->scd_base_addr = iwl_read_prph(priv, IWL49_SCD_SRAM_BASE_ADDR);
 	a = priv->scd_base_addr + IWL49_SCD_CONTEXT_DATA_OFFSET;
@@ -759,10 +721,9 @@
 		iwl4965_tx_queue_set_status(priv, &priv->txq[i], ac, 0);
 	}
 
-	iwl_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	return ret;
+	return 0;
 }
 
 static struct iwl_sensitivity_ranges iwl4965_sensitivity = {
@@ -788,6 +749,12 @@
 	.nrg_th_ofdm = 100,
 };
 
+static void iwl4965_set_ct_threshold(struct iwl_priv *priv)
+{
+	/* want Kelvin */
+	priv->hw_params.ct_kill_threshold = CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD);
+}
+
 /**
  * iwl4965_hw_set_hw_params
  *
@@ -822,7 +789,8 @@
 	priv->hw_params.rx_chains_num = 2;
 	priv->hw_params.valid_tx_ant = ANT_A | ANT_B;
 	priv->hw_params.valid_rx_ant = ANT_A | ANT_B;
-	priv->hw_params.ct_kill_threshold = CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD);
+	if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
+		priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
 
 	priv->hw_params.sens = &iwl4965_sensitivity;
 
@@ -1524,7 +1492,7 @@
 	struct iwl4965_txpowertable_cmd cmd = { 0 };
 	int ret;
 	u8 band = 0;
-	u8 is_fat = 0;
+	bool is_fat = false;
 	u8 ctrl_chan_high = 0;
 
 	if (test_bit(STATUS_SCANNING, &priv->status)) {
@@ -1602,7 +1570,7 @@
 {
 	int rc;
 	u8 band = 0;
-	u8 is_fat = 0;
+	bool is_fat = false;
 	u8 ctrl_chan_high = 0;
 	struct iwl4965_channel_switch_cmd cmd = { 0 };
 	const struct iwl_channel_info *ch_info;
@@ -1833,8 +1801,6 @@
 static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
 				   u16 ssn_idx, u8 tx_fifo)
 {
-	int ret = 0;
-
 	if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) ||
 	    (IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) {
 		IWL_WARN(priv,
@@ -1844,10 +1810,6 @@
 		return -EINVAL;
 	}
 
-	ret = iwl_grab_nic_access(priv);
-	if (ret)
-		return ret;
-
 	iwl4965_tx_queue_stop_scheduler(priv, txq_id);
 
 	iwl_clear_bits_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, (1 << txq_id));
@@ -1861,8 +1823,6 @@
 	iwl_txq_ctx_deactivate(priv, txq_id);
 	iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0);
 
-	iwl_release_nic_access(priv);
-
 	return 0;
 }
 
@@ -1904,7 +1864,6 @@
 				  int tx_fifo, int sta_id, int tid, u16 ssn_idx)
 {
 	unsigned long flags;
-	int ret;
 	u16 ra_tid;
 
 	if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) ||
@@ -1922,11 +1881,6 @@
 	iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
 
 	spin_lock_irqsave(&priv->lock, flags);
-	ret = iwl_grab_nic_access(priv);
-	if (ret) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return ret;
-	}
 
 	/* Stop this Tx queue before configuring it */
 	iwl4965_tx_queue_stop_scheduler(priv, txq_id);
@@ -1959,7 +1913,6 @@
 	/* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
 	iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
 
-	iwl_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
@@ -2331,9 +2284,13 @@
 	},
 	.send_tx_power	= iwl4965_send_tx_power,
 	.update_chain_flags = iwl_update_chain_flags,
-	.temperature = iwl4965_temperature_calib,
 	.post_associate = iwl_post_associate,
 	.config_ap = iwl_config_ap,
+	.isr = iwl_isr_legacy,
+	.temp_ops = {
+		.temperature = iwl4965_temperature_calib,
+		.set_ct_kill = iwl4965_set_ct_threshold,
+	},
 };
 
 static struct iwl_ops iwl4965_ops = {
@@ -2354,6 +2311,7 @@
 	.eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION,
 	.ops = &iwl4965_ops,
 	.mod_params = &iwl4965_mod_params,
+	.use_isr_legacy = true
 };
 
 /* Module firmware */
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
index 15cac70..4ef6804 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
@@ -87,6 +87,18 @@
 #define IWL50_NUM_AMPDU_QUEUES		  10
 #define IWL50_FIRST_AMPDU_QUEUE		  10
 
+/* 5150 only */
+#define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF	(-5)
+
+static inline s32 iwl_temp_calib_to_offset(struct iwl_priv *priv)
+{
+	u16 *temp_calib = (u16 *)iwl_eeprom_query_addr(priv,
+						       EEPROM_5000_TEMPERATURE);
+	/* offset =  temperature -  voltage / coef */
+	s32 offset = (s32)(temp_calib[0] - temp_calib[1] / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF);
+	return offset;
+}
+
 /* Fixed (non-configurable) rx data from phy */
 
 /**
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index d731a83..ab29aab 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -46,7 +46,7 @@
 #include "iwl-6000-hw.h"
 
 /* Highest firmware API version supported */
-#define IWL5000_UCODE_API_MAX 1
+#define IWL5000_UCODE_API_MAX 2
 #define IWL5150_UCODE_API_MAX 2
 
 /* Lowest firmware API version supported */
@@ -124,10 +124,6 @@
 		return ret;
 	}
 
-	ret = iwl_grab_nic_access(priv);
-	if (ret)
-		return ret;
-
 	/* enable DMA */
 	iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
 
@@ -137,8 +133,6 @@
 	iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
 			  APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
 
-	iwl_release_nic_access(priv);
-
 	return ret;
 }
 
@@ -165,12 +159,9 @@
 static int iwl5000_apm_reset(struct iwl_priv *priv)
 {
 	int ret = 0;
-	unsigned long flags;
 
 	iwl5000_apm_stop_master(priv);
 
-	spin_lock_irqsave(&priv->lock, flags);
-
 	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
 
 	udelay(10);
@@ -193,10 +184,6 @@
 		goto out;
 	}
 
-	ret = iwl_grab_nic_access(priv);
-	if (ret)
-		goto out;
-
 	/* enable DMA */
 	iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
 
@@ -205,11 +192,7 @@
 	/* disable L1-Active */
 	iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
 			  APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
-
-	iwl_release_nic_access(priv);
-
 out:
-	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return ret;
 }
@@ -252,11 +235,9 @@
 	 * (PCIe power is lost before PERST# is asserted),
 	 * causing ME FW to lose ownership and not being able to obtain it back.
 	 */
-	iwl_grab_nic_access(priv);
 	iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
 				APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
 				~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
-	iwl_release_nic_access(priv);
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
@@ -434,15 +415,19 @@
 	return &priv->eeprom[address];
 }
 
-static s32 iwl5150_get_ct_threshold(struct iwl_priv *priv)
+static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
 {
-	const s32 volt2temp_coef = -5;
-	u16 *temp_calib = (u16 *)iwl_eeprom_query_addr(priv,
-						EEPROM_5000_TEMPERATURE);
-	/* offset =  temperate -  voltage / coef */
-	s32 offset = temp_calib[0] - temp_calib[1] / volt2temp_coef;
-	s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD) - offset;
-	return threshold * volt2temp_coef;
+	const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF;
+	s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD) -
+			iwl_temp_calib_to_offset(priv);
+
+	priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef;
+}
+
+static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
+{
+	/* want Celsius */
+	priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
 }
 
 /*
@@ -533,19 +518,9 @@
 				struct fw_desc *image,
 				u32 dst_addr)
 {
-	int ret = 0;
-	unsigned long flags;
-
 	dma_addr_t phy_addr = image->p_addr;
 	u32 byte_cnt = image->len;
 
-	spin_lock_irqsave(&priv->lock, flags);
-	ret = iwl_grab_nic_access(priv);
-	if (ret) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return ret;
-	}
-
 	iwl_write_direct32(priv,
 		FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
 		FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
@@ -574,8 +549,6 @@
 		FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE	|
 		FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
 
-	iwl_release_nic_access(priv);
-	spin_unlock_irqrestore(&priv->lock, flags);
 	return 0;
 }
 
@@ -736,18 +709,11 @@
 {
 	u32 a;
 	unsigned long flags;
-	int ret;
 	int i, chan;
 	u32 reg_val;
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	ret = iwl_grab_nic_access(priv);
-	if (ret) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return ret;
-	}
-
 	priv->scd_base_addr = iwl_read_prph(priv, IWL50_SCD_SRAM_BASE_ADDR);
 	a = priv->scd_base_addr + IWL50_SCD_CONTEXT_DATA_OFFSET;
 	for (; a < priv->scd_base_addr + IWL50_SCD_TX_STTS_BITMAP_OFFSET;
@@ -815,7 +781,6 @@
 	iwl_txq_ctx_activate(priv, 8);
 	iwl_txq_ctx_activate(priv, 9);
 
-	iwl_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 
@@ -868,17 +833,8 @@
 	priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
 	priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
 
-	switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
-	case CSR_HW_REV_TYPE_5150:
-		/* 5150 wants in Kelvin */
-		priv->hw_params.ct_kill_threshold =
-				iwl5150_get_ct_threshold(priv);
-		break;
-	default:
-		/* all others want Celsius */
-		priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
-		break;
-	}
+	if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
+		priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
 
 	/* Set initial calibration set */
 	switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
@@ -900,7 +856,6 @@
 		break;
 	}
 
-
 	return 0;
 }
 
@@ -1006,7 +961,6 @@
 				  int tx_fifo, int sta_id, int tid, u16 ssn_idx)
 {
 	unsigned long flags;
-	int ret;
 	u16 ra_tid;
 
 	if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
@@ -1024,11 +978,6 @@
 	iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
 
 	spin_lock_irqsave(&priv->lock, flags);
-	ret = iwl_grab_nic_access(priv);
-	if (ret) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return ret;
-	}
 
 	/* Stop this Tx queue before configuring it */
 	iwl5000_tx_queue_stop_scheduler(priv, txq_id);
@@ -1064,7 +1013,6 @@
 	/* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
 	iwl5000_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
 
-	iwl_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
@@ -1073,8 +1021,6 @@
 static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
 				   u16 ssn_idx, u8 tx_fifo)
 {
-	int ret;
-
 	if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
 	    (IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) {
 		IWL_ERR(priv,
@@ -1084,10 +1030,6 @@
 		return -EINVAL;
 	}
 
-	ret = iwl_grab_nic_access(priv);
-	if (ret)
-		return ret;
-
 	iwl5000_tx_queue_stop_scheduler(priv, txq_id);
 
 	iwl_clear_bits_prph(priv, IWL50_SCD_AGGR_SEL, (1 << txq_id));
@@ -1101,8 +1043,6 @@
 	iwl_txq_ctx_deactivate(priv, txq_id);
 	iwl5000_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0);
 
-	iwl_release_nic_access(priv);
-
 	return 0;
 }
 
@@ -1434,6 +1374,17 @@
 	priv->temperature = le32_to_cpu(priv->statistics.general.temperature);
 }
 
+static void iwl5150_temperature(struct iwl_priv *priv)
+{
+	u32 vt = 0;
+	s32 offset =  iwl_temp_calib_to_offset(priv);
+
+	vt = le32_to_cpu(priv->statistics.general.temperature);
+	vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset;
+	/* now vt hold the temperature in Kelvin */
+	priv->temperature = KELVIN_TO_CELSIUS(vt);
+}
+
 /* Calc max signal level (dBm) among 3 possible receivers */
 int iwl5000_calc_rssi(struct iwl_priv *priv,
 			     struct iwl_rx_phy_res *rx_resp)
@@ -1511,7 +1462,6 @@
 	.init_alive_start = iwl5000_init_alive_start,
 	.alive_notify = iwl5000_alive_notify,
 	.send_tx_power = iwl5000_send_tx_power,
-	.temperature = iwl5000_temperature,
 	.update_chain_flags = iwl_update_chain_flags,
 	.apm_ops = {
 		.init =	iwl5000_apm_init,
@@ -1537,7 +1487,62 @@
 		.query_addr = iwl5000_eeprom_query_addr,
 	},
 	.post_associate = iwl_post_associate,
+	.isr = iwl_isr_ict,
 	.config_ap = iwl_config_ap,
+	.temp_ops = {
+		.temperature = iwl5000_temperature,
+		.set_ct_kill = iwl5000_set_ct_threshold,
+	 },
+};
+
+static struct iwl_lib_ops iwl5150_lib = {
+	.set_hw_params = iwl5000_hw_set_hw_params,
+	.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
+	.txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
+	.txq_set_sched = iwl5000_txq_set_sched,
+	.txq_agg_enable = iwl5000_txq_agg_enable,
+	.txq_agg_disable = iwl5000_txq_agg_disable,
+	.txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
+	.txq_free_tfd = iwl_hw_txq_free_tfd,
+	.txq_init = iwl_hw_tx_queue_init,
+	.rx_handler_setup = iwl5000_rx_handler_setup,
+	.setup_deferred_work = iwl5000_setup_deferred_work,
+	.is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
+	.load_ucode = iwl5000_load_ucode,
+	.init_alive_start = iwl5000_init_alive_start,
+	.alive_notify = iwl5000_alive_notify,
+	.send_tx_power = iwl5000_send_tx_power,
+	.update_chain_flags = iwl_update_chain_flags,
+	.apm_ops = {
+		.init =	iwl5000_apm_init,
+		.reset = iwl5000_apm_reset,
+		.stop = iwl5000_apm_stop,
+		.config = iwl5000_nic_config,
+		.set_pwr_src = iwl_set_pwr_src,
+	},
+	.eeprom_ops = {
+		.regulatory_bands = {
+			EEPROM_5000_REG_BAND_1_CHANNELS,
+			EEPROM_5000_REG_BAND_2_CHANNELS,
+			EEPROM_5000_REG_BAND_3_CHANNELS,
+			EEPROM_5000_REG_BAND_4_CHANNELS,
+			EEPROM_5000_REG_BAND_5_CHANNELS,
+			EEPROM_5000_REG_BAND_24_FAT_CHANNELS,
+			EEPROM_5000_REG_BAND_52_FAT_CHANNELS
+		},
+		.verify_signature  = iwlcore_eeprom_verify_signature,
+		.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
+		.release_semaphore = iwlcore_eeprom_release_semaphore,
+		.calib_version	= iwl5000_eeprom_calib_version,
+		.query_addr = iwl5000_eeprom_query_addr,
+	},
+	.post_associate = iwl_post_associate,
+	.isr = iwl_isr_ict,
+	.config_ap = iwl_config_ap,
+	.temp_ops = {
+		.temperature = iwl5150_temperature,
+		.set_ct_kill = iwl5150_set_ct_threshold,
+	 },
 };
 
 struct iwl_ops iwl5000_ops = {
@@ -1547,6 +1552,13 @@
 	.smgmt = &iwl5000_station_mgmt,
 };
 
+static struct iwl_ops iwl5150_ops = {
+	.lib = &iwl5150_lib,
+	.hcmd = &iwl5000_hcmd,
+	.utils = &iwl5000_hcmd_utils,
+	.smgmt = &iwl5000_station_mgmt,
+};
+
 struct iwl_mod_params iwl50_mod_params = {
 	.num_of_queues = IWL50_NUM_QUEUES,
 	.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
@@ -1642,7 +1654,7 @@
 	.ucode_api_max = IWL5150_UCODE_API_MAX,
 	.ucode_api_min = IWL5150_UCODE_API_MIN,
 	.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
-	.ops = &iwl5000_ops,
+	.ops = &iwl5150_ops,
 	.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
 	.eeprom_ver = EEPROM_5050_EEPROM_VERSION,
 	.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index 4c88e87..23a58b0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -270,6 +270,8 @@
   {"60", "64QAM 5/6"}
 };
 
+#define MCS_INDEX_PER_STREAM	(8)
+
 static inline u8 rs_extract_rate(u32 rate_n_flags)
 {
 	return (u8)(rate_n_flags & 0xFF);
@@ -652,19 +654,19 @@
 	return 1;
 }
 
-/* FIXME:RS: in 4965 we don't use greenfield at all */
-/* FIXME:RS: don't use greenfield for now in TX */
-#if 0
-static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf)
+/* in 4965 we don't use greenfield at all */
+static inline u8 rs_use_green(struct iwl_priv *priv,
+			      struct ieee80211_conf *conf)
 {
-	return (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
-		priv->current_ht_config.is_green_field &&
-		!priv->current_ht_config.non_GF_STA_present;
-}
-#endif
-static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf)
-{
-	return 0;
+	u8 is_green;
+
+	if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
+		is_green = 0;
+	else
+		is_green = (conf_is_ht(conf) &&
+			   priv->current_ht_config.is_green_field &&
+			   !priv->current_ht_config.non_GF_STA_present);
+	return is_green;
 }
 
 /**
@@ -2061,6 +2063,10 @@
 		active_tbl = 1 - lq_sta->active_tbl;
 
 	tbl = &(lq_sta->lq_info[active_tbl]);
+	if (is_legacy(tbl->lq_type))
+		lq_sta->is_green = 0;
+	else
+		lq_sta->is_green = rs_use_green(priv, conf);
 	is_green = lq_sta->is_green;
 
 	/* current tx rate */
@@ -2514,12 +2520,33 @@
 		}
 	}
 
-	if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT)
-		rate_idx = rate_lowest_index(sband, sta);
-	else if (sband->band == IEEE80211_BAND_5GHZ)
+	if (lq_sta->last_rate_n_flags & RATE_MCS_HT_MSK) {
 		rate_idx -= IWL_FIRST_OFDM_RATE;
-
+		/* 6M and 9M shared same MCS index */
+		rate_idx = (rate_idx > 0) ? (rate_idx - 1) : 0;
+		if (rs_extract_rate(lq_sta->last_rate_n_flags) >=
+		    IWL_RATE_MIMO3_6M_PLCP)
+			rate_idx = rate_idx + (2 * MCS_INDEX_PER_STREAM);
+		else if (rs_extract_rate(lq_sta->last_rate_n_flags) >=
+			 IWL_RATE_MIMO2_6M_PLCP)
+			rate_idx = rate_idx + MCS_INDEX_PER_STREAM;
+		info->control.rates[0].flags = IEEE80211_TX_RC_MCS;
+		if (lq_sta->last_rate_n_flags & RATE_MCS_SGI_MSK)
+			info->control.rates[0].flags |= IEEE80211_TX_RC_SHORT_GI;
+		if (lq_sta->last_rate_n_flags & RATE_MCS_DUP_MSK)
+			info->control.rates[0].flags |= IEEE80211_TX_RC_DUP_DATA;
+		if (lq_sta->last_rate_n_flags & RATE_MCS_FAT_MSK)
+			info->control.rates[0].flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+		if (lq_sta->last_rate_n_flags & RATE_MCS_GF_MSK)
+			info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD;
+	} else {
+		if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT)
+			rate_idx = rate_lowest_index(sband, sta);
+		else if (sband->band == IEEE80211_BAND_5GHZ)
+			rate_idx -= IWL_FIRST_OFDM_RATE;
+	}
 	info->control.rates[0].idx = rate_idx;
+
 }
 
 static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
@@ -2896,7 +2923,8 @@
 		   ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3"));
 		   desc += sprintf(buff+desc, " %s",
 		   (tbl->is_fat) ? "40MHz" : "20MHz");
-		desc += sprintf(buff+desc, " %s\n", (tbl->is_SGI) ? "SGI" : "");
+		   desc += sprintf(buff+desc, " %s %s\n", (tbl->is_SGI) ? "SGI" : "",
+		   (lq_sta->is_green) ? "GF enabled" : "");
 	}
 	desc += sprintf(buff+desc, "last tx rate=0x%X\n",
 		lq_sta->last_rate_n_flags);
@@ -2959,13 +2987,14 @@
 		return -ENOMEM;
 
 	for (i = 0; i < LQ_SIZE; i++) {
-		desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n"
+		desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d GF=%d\n"
 				"rate=0x%X\n",
 				lq_sta->active_tbl == i ? "*" : "x",
 				lq_sta->lq_info[i].lq_type,
 				lq_sta->lq_info[i].is_SGI,
 				lq_sta->lq_info[i].is_fat,
 				lq_sta->lq_info[i].is_dup,
+				lq_sta->is_green,
 				lq_sta->lq_info[i].current_rate);
 		for (j = 0; j < IWL_RATE_COUNT; j++) {
 			desc += sprintf(buff+desc,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 596977d..0a5507c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -503,24 +503,12 @@
 int iwl_hw_tx_queue_init(struct iwl_priv *priv,
 			 struct iwl_tx_queue *txq)
 {
-	int ret;
-	unsigned long flags;
 	int txq_id = txq->q.id;
 
-	spin_lock_irqsave(&priv->lock, flags);
-	ret = iwl_grab_nic_access(priv);
-	if (ret) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return ret;
-	}
-
 	/* Circular buffer (TFD queue in DRAM) physical base address */
 	iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
 			     txq->q.dma_addr >> 8);
 
-	iwl_release_nic_access(priv);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
 	return 0;
 }
 
@@ -709,6 +697,7 @@
 	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
 	u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
 	unsigned long status = priv->status;
+	unsigned long reg_flags;
 
 	IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n",
 			  (flags & HW_CARD_DISABLED) ? "Kill" : "On",
@@ -720,32 +709,25 @@
 		iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
 			    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
 
-		if (!iwl_grab_nic_access(priv)) {
-			iwl_write_direct32(
-				priv, HBUS_TARG_MBX_C,
-				HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
-
-			iwl_release_nic_access(priv);
-		}
+		iwl_write_direct32(priv, HBUS_TARG_MBX_C,
+					HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
 
 		if (!(flags & RXON_CARD_DISABLED)) {
 			iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
 				    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-			if (!iwl_grab_nic_access(priv)) {
-				iwl_write_direct32(
-					priv, HBUS_TARG_MBX_C,
+			iwl_write_direct32(priv, HBUS_TARG_MBX_C,
 					HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
 
-				iwl_release_nic_access(priv);
-			}
 		}
 
 		if (flags & RF_CARD_DISABLED) {
 			iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
 				    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
 			iwl_read32(priv, CSR_UCODE_DRV_GP1);
+			spin_lock_irqsave(&priv->reg_lock, reg_flags);
 			if (!iwl_grab_nic_access(priv))
 				iwl_release_nic_access(priv);
+			spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
 		}
 	}
 
@@ -774,14 +756,6 @@
 
 int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
 {
-	int ret;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	ret = iwl_grab_nic_access(priv);
-	if (ret)
-		goto err;
-
 	if (src == IWL_PWR_SRC_VAUX) {
 		if (pci_pme_capable(priv->pci_dev, PCI_D3cold))
 			iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
@@ -793,10 +767,7 @@
 				       ~APMG_PS_CTRL_MSK_PWR_SRC);
 	}
 
-	iwl_release_nic_access(priv);
-err:
-	spin_unlock_irqrestore(&priv->lock, flags);
-	return ret;
+	return 0;
 }
 
 /**
@@ -860,6 +831,7 @@
 	unsigned long flags;
 	u8 fill_rx = 0;
 	u32 count = 8;
+	int total_empty;
 
 	/* uCode's read index (stored in shared DRAM) indicates the last Rx
 	 * buffer that the driver may process (last buffer filled by ucode). */
@@ -870,7 +842,12 @@
 	if (i == r)
 		IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i);
 
-	if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2))
+	/* calculate total frames need to be restock after handling RX */
+	total_empty = r - priv->rxq.write_actual;
+	if (total_empty < 0)
+		total_empty += RX_QUEUE_SIZE;
+
+	if (total_empty > (RX_QUEUE_SIZE / 2))
 		fill_rx = 1;
 
 	while (i != r) {
@@ -947,7 +924,7 @@
 			count++;
 			if (count >= 8) {
 				priv->rxq.read = i;
-				iwl_rx_queue_restock(priv);
+				iwl_rx_replenish_now(priv);
 				count = 0;
 			}
 		}
@@ -955,7 +932,10 @@
 
 	/* Backtrack one entry */
 	priv->rxq.read = i;
-	iwl_rx_queue_restock(priv);
+	if (fill_rx)
+		iwl_rx_replenish_now(priv);
+	else
+		iwl_rx_queue_restock(priv);
 }
 
 /* call this function to flush any scheduled tasklet */
@@ -966,7 +946,7 @@
 	tasklet_kill(&priv->irq_tasklet);
 }
 
-static void iwl_irq_tasklet(struct iwl_priv *priv)
+static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
 {
 	u32 inta, handled = 0;
 	u32 inta_fh;
@@ -1127,9 +1107,9 @@
 		priv->isr_stats.unhandled++;
 	}
 
-	if (inta & ~CSR_INI_SET_MASK) {
+	if (inta & ~(priv->inta_mask)) {
 		IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n",
-			 inta & ~CSR_INI_SET_MASK);
+			 inta & ~priv->inta_mask);
 		IWL_WARN(priv, "   with FH_INT = 0x%08x\n", inta_fh);
 	}
 
@@ -1150,6 +1130,199 @@
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
+/* tasklet for iwlagn interrupt */
+static void iwl_irq_tasklet(struct iwl_priv *priv)
+{
+	u32 inta = 0;
+	u32 handled = 0;
+	unsigned long flags;
+#ifdef CONFIG_IWLWIFI_DEBUG
+	u32 inta_mask;
+#endif
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	/* 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);
+
+	inta = priv->inta;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (priv->debug_level & IWL_DL_ISR) {
+		/* just for debug */
+		inta_mask = iwl_read32(priv, CSR_INT_MASK);
+		IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ",
+				inta, inta_mask);
+	}
+#endif
+	/* saved interrupt in inta variable now we can reset priv->inta */
+	priv->inta = 0;
+
+	/* Now service all interrupt bits discovered above. */
+	if (inta & CSR_INT_BIT_HW_ERR) {
+		IWL_ERR(priv, "Microcode HW error detected.  Restarting.\n");
+
+		/* Tell the device to stop sending interrupts */
+		iwl_disable_interrupts(priv);
+
+		priv->isr_stats.hw++;
+		iwl_irq_handle_error(priv);
+
+		handled |= CSR_INT_BIT_HW_ERR;
+
+		spin_unlock_irqrestore(&priv->lock, flags);
+
+		return;
+	}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (priv->debug_level & (IWL_DL_ISR)) {
+		/* NIC fires this, but we don't use it, redundant with WAKEUP */
+		if (inta & CSR_INT_BIT_SCD) {
+			IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
+				      "the frame/frames.\n");
+			priv->isr_stats.sch++;
+		}
+
+		/* Alive notification via Rx interrupt will do the real work */
+		if (inta & CSR_INT_BIT_ALIVE) {
+			IWL_DEBUG_ISR(priv, "Alive interrupt\n");
+			priv->isr_stats.alive++;
+		}
+	}
+#endif
+	/* Safely ignore these bits for debug checks below */
+	inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE);
+
+	/* HW RF KILL switch toggled */
+	if (inta & CSR_INT_BIT_RF_KILL) {
+		int hw_rf_kill = 0;
+		if (!(iwl_read32(priv, CSR_GP_CNTRL) &
+				CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
+			hw_rf_kill = 1;
+
+		IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n",
+				hw_rf_kill ? "disable radio" : "enable radio");
+
+		priv->isr_stats.rfkill++;
+
+		/* driver only loads ucode once setting the interface up.
+		 * the driver allows loading the ucode even if the radio
+		 * is killed. Hence update the killswitch state here. The
+		 * rfkill handler will care about restarting if needed.
+		 */
+		if (!test_bit(STATUS_ALIVE, &priv->status)) {
+			if (hw_rf_kill)
+				set_bit(STATUS_RF_KILL_HW, &priv->status);
+			else
+				clear_bit(STATUS_RF_KILL_HW, &priv->status);
+			queue_work(priv->workqueue, &priv->rf_kill);
+		}
+
+		handled |= CSR_INT_BIT_RF_KILL;
+	}
+
+	/* Chip got too hot and stopped itself */
+	if (inta & CSR_INT_BIT_CT_KILL) {
+		IWL_ERR(priv, "Microcode CT kill error detected.\n");
+		priv->isr_stats.ctkill++;
+		handled |= CSR_INT_BIT_CT_KILL;
+	}
+
+	/* Error detected by uCode */
+	if (inta & CSR_INT_BIT_SW_ERR) {
+		IWL_ERR(priv, "Microcode SW error detected. "
+			" Restarting 0x%X.\n", inta);
+		priv->isr_stats.sw++;
+		priv->isr_stats.sw_err = inta;
+		iwl_irq_handle_error(priv);
+		handled |= CSR_INT_BIT_SW_ERR;
+	}
+
+	/* uCode wakes up after power-down sleep */
+	if (inta & CSR_INT_BIT_WAKEUP) {
+		IWL_DEBUG_ISR(priv, "Wakeup interrupt\n");
+		iwl_rx_queue_update_write_ptr(priv, &priv->rxq);
+		iwl_txq_update_write_ptr(priv, &priv->txq[0]);
+		iwl_txq_update_write_ptr(priv, &priv->txq[1]);
+		iwl_txq_update_write_ptr(priv, &priv->txq[2]);
+		iwl_txq_update_write_ptr(priv, &priv->txq[3]);
+		iwl_txq_update_write_ptr(priv, &priv->txq[4]);
+		iwl_txq_update_write_ptr(priv, &priv->txq[5]);
+
+		priv->isr_stats.wakeup++;
+
+		handled |= CSR_INT_BIT_WAKEUP;
+	}
+
+	/* All uCode command responses, including Tx command responses,
+	 * Rx "responses" (frame-received notification), and other
+	 * notifications from uCode come through here*/
+	if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX |
+			CSR_INT_BIT_RX_PERIODIC)) {
+		IWL_DEBUG_ISR(priv, "Rx interrupt\n");
+		if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
+			handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
+			iwl_write32(priv, CSR_FH_INT_STATUS,
+					CSR49_FH_INT_RX_MASK);
+		}
+		if (inta & CSR_INT_BIT_RX_PERIODIC) {
+			handled |= CSR_INT_BIT_RX_PERIODIC;
+			iwl_write32(priv, CSR_INT, CSR_INT_BIT_RX_PERIODIC);
+		}
+		/* Sending RX interrupt require many steps to be done in the
+		 * the device:
+		 * 1- write interrupt to current index in ICT table.
+		 * 2- dma RX frame.
+		 * 3- update RX shared data to indicate last write index.
+		 * 4- send interrupt.
+		 * This could lead to RX race, driver could receive RX interrupt
+		 * but the shared data changes does not reflect this.
+		 * this could lead to RX race, RX periodic will solve this race
+		 */
+		iwl_write32(priv, CSR_INT_PERIODIC_REG,
+			    CSR_INT_PERIODIC_DIS);
+		iwl_rx_handle(priv);
+		/* Only set RX periodic if real RX is received. */
+		if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX))
+			iwl_write32(priv, CSR_INT_PERIODIC_REG,
+				    CSR_INT_PERIODIC_ENA);
+
+		priv->isr_stats.rx++;
+	}
+
+	if (inta & CSR_INT_BIT_FH_TX) {
+		iwl_write32(priv, CSR_FH_INT_STATUS, CSR49_FH_INT_TX_MASK);
+		IWL_DEBUG_ISR(priv, "Tx interrupt\n");
+		priv->isr_stats.tx++;
+		handled |= CSR_INT_BIT_FH_TX;
+		/* FH finished to write, send event */
+		priv->ucode_write_complete = 1;
+		wake_up_interruptible(&priv->wait_command_queue);
+	}
+
+	if (inta & ~handled) {
+		IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled);
+		priv->isr_stats.unhandled++;
+	}
+
+	if (inta & ~(priv->inta_mask)) {
+		IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n",
+			 inta & ~priv->inta_mask);
+	}
+
+
+	/* Re-enable all interrupts */
+	/* only Re-enable if diabled by irq */
+	if (test_bit(STATUS_INT_ENABLED, &priv->status))
+		iwl_enable_interrupts(priv);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+}
+
 
 /******************************************************************************
  *
@@ -1579,6 +1752,8 @@
 		       test_bit(STATUS_EXIT_PENDING, &priv->status) <<
 				STATUS_EXIT_PENDING;
 
+	/* device going down, Stop using ICT table */
+	iwl_disable_ict(priv);
 	spin_lock_irqsave(&priv->lock, flags);
 	iwl_clear_bit(priv, CSR_GP_CNTRL,
 			 CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
@@ -1587,13 +1762,8 @@
 	iwl_txq_ctx_stop(priv);
 	iwl_rxq_stop(priv);
 
-	spin_lock_irqsave(&priv->lock, flags);
-	if (!iwl_grab_nic_access(priv)) {
-		iwl_write_prph(priv, APMG_CLK_DIS_REG,
-					 APMG_CLK_VAL_DMA_CLK_RQT);
-		iwl_release_nic_access(priv);
-	}
-	spin_unlock_irqrestore(&priv->lock, flags);
+	iwl_write_prph(priv, APMG_CLK_DIS_REG,
+				APMG_CLK_VAL_DMA_CLK_RQT);
 
 	udelay(5);
 
@@ -1622,6 +1792,49 @@
 	iwl_cancel_deferred_work(priv);
 }
 
+#define HW_READY_TIMEOUT (50)
+
+static int iwl_set_hw_ready(struct iwl_priv *priv)
+{
+	int ret = 0;
+
+	iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+		CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
+
+	/* See if we got it */
+	ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
+				CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
+				CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
+				HW_READY_TIMEOUT);
+	if (ret != -ETIMEDOUT)
+		priv->hw_ready = true;
+	else
+		priv->hw_ready = false;
+
+	IWL_DEBUG_INFO(priv, "hardware %s\n",
+		      (priv->hw_ready == 1) ? "ready" : "not ready");
+	return ret;
+}
+
+static int iwl_prepare_card_hw(struct iwl_priv *priv)
+{
+	int ret = 0;
+
+	IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter \n");
+
+	iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+			CSR_HW_IF_CONFIG_REG_PREPARE);
+
+	ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
+			~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
+			CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
+
+	if (ret != -ETIMEDOUT)
+		iwl_set_hw_ready(priv);
+
+	return ret;
+}
+
 #define MAX_HW_RESTARTS 5
 
 static int __iwl_up(struct iwl_priv *priv)
@@ -1639,6 +1852,13 @@
 		return -EIO;
 	}
 
+	iwl_prepare_card_hw(priv);
+
+	if (!priv->hw_ready) {
+		IWL_WARN(priv, "Exit HW not ready\n");
+		return -EIO;
+	}
+
 	/* If platform's RF_KILL switch is NOT set to KILL */
 	if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
 		clear_bit(STATUS_RF_KILL_HW, &priv->status);
@@ -1667,6 +1887,8 @@
 
 	/* clear (again), then enable host interrupts */
 	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+	/* enable dram interrupt */
+	iwl_reset_ict(priv);
 	iwl_enable_interrupts(priv);
 
 	/* really make sure rfkill handshake bits are cleared */
@@ -2298,8 +2520,10 @@
 
 	if (priv->eeprom) {
 		eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
-		pos += sprintf(buf + pos, "EEPROM version: 0x%x\n",
-				 eeprom_ver);
+		pos += sprintf(buf + pos, "NVM Type: %s, version: 0x%x\n",
+			       (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
+			       ? "OTP" : "EEPROM", eeprom_ver);
+
 	} else {
 		pos += sprintf(buf + pos, "EEPROM not initialzed\n");
 	}
@@ -2478,7 +2702,7 @@
 static ssize_t show_qos(struct device *d,
 				struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl_priv *priv = dev_get_drvdata(d);
 	char *p = buf;
 	int   q;
 
@@ -2565,8 +2789,12 @@
 	priv->statistics_periodic.data = (unsigned long)priv;
 	priv->statistics_periodic.function = iwl_bg_statistics_periodic;
 
-	tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
-		     iwl_irq_tasklet, (unsigned long)priv);
+	if (!priv->cfg->use_isr_legacy)
+		tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
+			iwl_irq_tasklet, (unsigned long)priv);
+	else
+		tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
+			iwl_irq_tasklet_legacy, (unsigned long)priv);
 }
 
 static void iwl_cancel_deferred_work(struct iwl_priv *priv)
@@ -2655,6 +2883,7 @@
 	IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n");
 	priv->cfg = cfg;
 	priv->pci_dev = pdev;
+	priv->inta_mask = CSR_INI_SET_MASK;
 
 #ifdef CONFIG_IWLWIFI_DEBUG
 	priv->debug_level = priv->cfg->mod_params->debug;
@@ -2705,6 +2934,10 @@
 		(unsigned long long) pci_resource_len(pdev, 0));
 	IWL_DEBUG_INFO(priv, "pci_resource_base = %p\n", priv->hw_base);
 
+	/* this spin lock will be used in apm_ops.init and EEPROM access
+	 * we should init now
+	 */
+	spin_lock_init(&priv->reg_lock);
 	iwl_hw_detect(priv);
 	IWL_INFO(priv, "Detected Intel Wireless WiFi Link %s REV=0x%X\n",
 		priv->cfg->name, priv->hw_rev);
@@ -2713,6 +2946,12 @@
 	 * PCI Tx retries from interfering with C3 CPU state */
 	pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
 
+	iwl_prepare_card_hw(priv);
+	if (!priv->hw_ready) {
+		IWL_WARN(priv, "Failed, HW not ready\n");
+		goto out_iounmap;
+	}
+
 	/* amp init */
 	err = priv->cfg->ops->lib->apm_ops.init(priv);
 	if (err < 0) {
@@ -2763,8 +3002,9 @@
 
 	pci_enable_msi(priv->pci_dev);
 
-	err = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED,
-			  DRV_NAME, priv);
+	iwl_alloc_isr_ict(priv);
+	err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr,
+			  IRQF_SHARED, DRV_NAME, priv);
 	if (err) {
 		IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq);
 		goto out_disable_msi;
@@ -2821,6 +3061,7 @@
 	sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
  out_free_irq:
 	free_irq(priv->pci_dev->irq, priv);
+	iwl_free_isr_ict(priv);
  out_disable_msi:
 	pci_disable_msi(priv->pci_dev);
 	iwl_uninit_drv(priv);
@@ -2902,6 +3143,8 @@
 
 	iwl_uninit_drv(priv);
 
+	iwl_free_isr_ict(priv);
+
 	if (priv->ibss_beacon)
 		dev_kfree_skb(priv->ibss_beacon);
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 7b84d52..e581dc3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -614,8 +614,18 @@
 
 #define RXON_FLG_CHANNEL_MODE_POS		(25)
 #define RXON_FLG_CHANNEL_MODE_MSK		cpu_to_le32(0x3 << 25)
-#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK	cpu_to_le32(0x1 << 25)
-#define RXON_FLG_CHANNEL_MODE_MIXED_MSK		cpu_to_le32(0x2 << 25)
+
+/* channel mode */
+enum {
+	CHANNEL_MODE_LEGACY = 0,
+	CHANNEL_MODE_PURE_40 = 1,
+	CHANNEL_MODE_MIXED = 2,
+	CHANNEL_MODE_RESERVED = 3,
+};
+#define RXON_FLG_CHANNEL_MODE_LEGACY	cpu_to_le32(CHANNEL_MODE_LEGACY << RXON_FLG_CHANNEL_MODE_POS)
+#define RXON_FLG_CHANNEL_MODE_PURE_40	cpu_to_le32(CHANNEL_MODE_PURE_40 << RXON_FLG_CHANNEL_MODE_POS)
+#define RXON_FLG_CHANNEL_MODE_MIXED	cpu_to_le32(CHANNEL_MODE_MIXED << RXON_FLG_CHANNEL_MODE_POS)
+
 /* CTS to self (if spec allows) flag */
 #define RXON_FLG_SELF_CTS_EN			cpu_to_le32(0x1<<30)
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 5393fb3..e93ddb7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -39,6 +39,7 @@
 #include "iwl-rfkill.h"
 #include "iwl-power.h"
 #include "iwl-sta.h"
+#include "iwl-helpers.h"
 
 
 MODULE_DESCRIPTION("iwl core");
@@ -59,6 +60,8 @@
 				    IWL_RATE_##pp##M_INDEX,    \
 				    IWL_RATE_##np##M_INDEX }
 
+static irqreturn_t iwl_isr(int irq, void *data);
+
 /*
  * Parameter order:
  *   rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate
@@ -603,10 +606,10 @@
 
 	if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
 		return !(ch_info->fat_extension_channel &
-					IEEE80211_CHAN_NO_FAT_ABOVE);
+					IEEE80211_CHAN_NO_HT40PLUS);
 	else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)
 		return !(ch_info->fat_extension_channel &
-					IEEE80211_CHAN_NO_FAT_BELOW);
+					IEEE80211_CHAN_NO_HT40MINUS);
 
 	return 0;
 }
@@ -617,19 +620,23 @@
 	struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config;
 
 	if ((!iwl_ht_conf->is_ht) ||
-	   (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) ||
-	   (iwl_ht_conf->extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE))
+	    (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ))
 		return 0;
 
+	/* We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40
+	 * the bit will not set if it is pure 40MHz case
+	 */
 	if (sta_ht_inf) {
-		if ((!sta_ht_inf->ht_supported) ||
-		   (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)))
+		if (!sta_ht_inf->ht_supported)
 			return 0;
 	}
 
-	return iwl_is_channel_extension(priv, priv->band,
-					le16_to_cpu(priv->staging_rxon.channel),
-					iwl_ht_conf->extension_chan_offset);
+	if (iwl_ht_conf->ht_protection & IEEE80211_HT_OP_MODE_PROTECTION_20MHZ)
+		return 1;
+	else
+		return iwl_is_channel_extension(priv, priv->band,
+				le16_to_cpu(priv->staging_rxon.channel),
+				iwl_ht_conf->extension_chan_offset);
 }
 EXPORT_SYMBOL(iwl_is_fat_tx_allowed);
 
@@ -799,42 +806,51 @@
 void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
 {
 	struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
-	u32 val;
 
 	if (!ht_info->is_ht) {
-		rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
-			RXON_FLG_CHANNEL_MODE_PURE_40_MSK |
+		rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
 			RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
 			RXON_FLG_FAT_PROT_MSK |
 			RXON_FLG_HT_PROT_MSK);
 		return;
 	}
 
-	/* Set up channel bandwidth:  20 MHz only, or 20/40 mixed if fat ok */
-	if (iwl_is_fat_tx_allowed(priv, NULL))
-		rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK;
-	else
-		rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
-				 RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
+	/* FIXME: if the definition of ht_protection changed, the "translation"
+	 * will be needed for rxon->flags
+	 */
+	rxon->flags |= cpu_to_le32(ht_info->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS);
 
-	/* Note: control channel is opposite of extension channel */
-	switch (ht_info->extension_chan_offset) {
-	case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
-		rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
-		break;
-	case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
-		rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
-		break;
-	case IEEE80211_HT_PARAM_CHA_SEC_NONE:
-	default:
-		rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK;
-		break;
+	/* Set up channel bandwidth:
+	 * 20 MHz only, 20/40 mixed or pure 40 if fat ok */
+	/* clear the HT channel mode before set the mode */
+	rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
+			 RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
+	if (iwl_is_fat_tx_allowed(priv, NULL)) {
+		/* pure 40 fat */
+		if (rxon->flags & RXON_FLG_FAT_PROT_MSK)
+			rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40;
+		else {
+			/* Note: control channel is opposite of extension channel */
+			switch (ht_info->extension_chan_offset) {
+			case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+				rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
+				rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
+				break;
+			case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+				rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
+				rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
+				break;
+			case IEEE80211_HT_PARAM_CHA_SEC_NONE:
+			default:
+				/* channel location only valid if in Mixed mode */
+				IWL_ERR(priv, "invalid extension channel offset\n");
+				break;
+			}
+		}
+	} else {
+		rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY;
 	}
 
-	val = ht_info->ht_protection;
-
-	rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS);
-
 	if (priv->cfg->ops->hcmd->set_rxon_chain)
 		priv->cfg->ops->hcmd->set_rxon_chain(priv);
 
@@ -1122,8 +1138,9 @@
 	priv->staging_rxon.cck_basic_rates =
 	    (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
 
-	priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
-					RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
+	/* clear both MIX and PURE40 mode flag */
+	priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED |
+					RXON_FLG_CHANNEL_MODE_PURE_40);
 	memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
 	memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN);
 	priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff;
@@ -1483,11 +1500,272 @@
 {
 	IWL_DEBUG_ISR(priv, "Enabling interrupts\n");
 	set_bit(STATUS_INT_ENABLED, &priv->status);
-	iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
+	iwl_write32(priv, CSR_INT_MASK, priv->inta_mask);
 }
 EXPORT_SYMBOL(iwl_enable_interrupts);
 
-irqreturn_t iwl_isr(int irq, void *data)
+
+#define ICT_COUNT (PAGE_SIZE/sizeof(u32))
+
+/* Free dram table */
+void iwl_free_isr_ict(struct iwl_priv *priv)
+{
+	if (priv->ict_tbl_vir) {
+		pci_free_consistent(priv->pci_dev, (sizeof(u32) * ICT_COUNT) +
+					PAGE_SIZE, priv->ict_tbl_vir,
+					priv->ict_tbl_dma);
+		priv->ict_tbl_vir = NULL;
+	}
+}
+EXPORT_SYMBOL(iwl_free_isr_ict);
+
+
+/* allocate dram shared table it is a PAGE_SIZE aligned
+ * also reset all data related to ICT table interrupt.
+ */
+int iwl_alloc_isr_ict(struct iwl_priv *priv)
+{
+
+	if (priv->cfg->use_isr_legacy)
+		return 0;
+	/* allocate shrared data table */
+	priv->ict_tbl_vir = pci_alloc_consistent(priv->pci_dev, (sizeof(u32) *
+						  ICT_COUNT) + PAGE_SIZE,
+						  &priv->ict_tbl_dma);
+	if (!priv->ict_tbl_vir)
+		return -ENOMEM;
+
+	/* align table to PAGE_SIZE boundry */
+	priv->aligned_ict_tbl_dma = ALIGN(priv->ict_tbl_dma, PAGE_SIZE);
+
+	IWL_DEBUG_ISR(priv, "ict dma addr %Lx dma aligned %Lx diff %d\n",
+			     (unsigned long long)priv->ict_tbl_dma,
+			     (unsigned long long)priv->aligned_ict_tbl_dma,
+			(int)(priv->aligned_ict_tbl_dma - priv->ict_tbl_dma));
+
+	priv->ict_tbl =  priv->ict_tbl_vir +
+			  (priv->aligned_ict_tbl_dma - priv->ict_tbl_dma);
+
+	IWL_DEBUG_ISR(priv, "ict vir addr %p vir aligned %p diff %d\n",
+			     priv->ict_tbl, priv->ict_tbl_vir,
+			(int)(priv->aligned_ict_tbl_dma - priv->ict_tbl_dma));
+
+	/* reset table and index to all 0 */
+	memset(priv->ict_tbl_vir,0, (sizeof(u32) * ICT_COUNT) + PAGE_SIZE);
+	priv->ict_index = 0;
+
+	/* add periodic RX interrupt */
+	priv->inta_mask |= CSR_INT_BIT_RX_PERIODIC;
+	return 0;
+}
+EXPORT_SYMBOL(iwl_alloc_isr_ict);
+
+/* Device is going up inform it about using ICT interrupt table,
+ * also we need to tell the driver to start using ICT interrupt.
+ */
+int iwl_reset_ict(struct iwl_priv *priv)
+{
+	u32 val;
+	unsigned long flags;
+
+	if (!priv->ict_tbl_vir)
+		return 0;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl_disable_interrupts(priv);
+
+	memset(&priv->ict_tbl[0],0, sizeof(u32) * ICT_COUNT);
+
+	val = priv->aligned_ict_tbl_dma >> PAGE_SHIFT;
+
+	val |= CSR_DRAM_INT_TBL_ENABLE;
+	val |= CSR_DRAM_INIT_TBL_WRAP_CHECK;
+
+	IWL_DEBUG_ISR(priv, "CSR_DRAM_INT_TBL_REG =0x%X "
+			"aligned dma address %Lx\n",
+			val, (unsigned long long)priv->aligned_ict_tbl_dma);
+
+	iwl_write32(priv, CSR_DRAM_INT_TBL_REG, val);
+	priv->use_ict = true;
+	priv->ict_index = 0;
+	iwl_write32(priv, CSR_INT, priv->inta_mask);
+	iwl_enable_interrupts(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(iwl_reset_ict);
+
+/* Device is going down disable ict interrupt usage */
+void iwl_disable_ict(struct iwl_priv *priv)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->use_ict = false;
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL(iwl_disable_ict);
+
+/* interrupt handler using ict table, with this interrupt driver will
+ * stop using INTA register to get device's interrupt, reading this register
+ * is expensive, device will write interrupts in ICT dram table, increment
+ * index then will fire interrupt to driver, driver will OR all ICT table
+ * entries from current index up to table entry with 0 value. the result is
+ * the interrupt we need to service, driver will set the entries back to 0 and
+ * set index.
+ */
+irqreturn_t iwl_isr_ict(int irq, void *data)
+{
+	struct iwl_priv *priv = data;
+	u32 inta, inta_mask;
+	u32 val = 0;
+
+	if (!priv)
+		return IRQ_NONE;
+
+	/* dram interrupt table not set yet,
+	 * use legacy interrupt.
+	 */
+	if (!priv->use_ict)
+		return iwl_isr(irq, data);
+
+	spin_lock(&priv->lock);
+
+	/* Disable (but don't clear!) interrupts here to avoid
+	 * back-to-back ISRs and sporadic interrupts from our NIC.
+	 * If we have something to service, the tasklet will re-enable ints.
+	 * If we *don't* have something, we'll re-enable before leaving here.
+	 */
+	inta_mask = iwl_read32(priv, CSR_INT_MASK);  /* just for debug */
+	iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+
+	/* Ignore interrupt if there's nothing in NIC to service.
+	 * This may be due to IRQ shared with another device,
+	 * or due to sporadic interrupts thrown from our NIC. */
+	if (!priv->ict_tbl[priv->ict_index]) {
+		IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n");
+		goto none;
+	}
+
+	/* read all entries that not 0 start with ict_index */
+	while (priv->ict_tbl[priv->ict_index]) {
+
+		val |= priv->ict_tbl[priv->ict_index];
+		IWL_DEBUG_ISR(priv, "ICT index %d value 0x%08X\n",
+					priv->ict_index,
+					priv->ict_tbl[priv->ict_index]);
+		priv->ict_tbl[priv->ict_index] = 0;
+		priv->ict_index = iwl_queue_inc_wrap(priv->ict_index,
+								ICT_COUNT);
+
+	}
+
+	/* We should not get this value, just ignore it. */
+	if (val == 0xffffffff)
+		val = 0;
+
+	inta = (0xff & val) | ((0xff00 & val) << 16);
+	IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n",
+			inta, inta_mask, val);
+
+	inta &= priv->inta_mask;
+	priv->inta |= inta;
+
+	/* iwl_irq_tasklet() will service interrupts and re-enable them */
+	if (likely(inta))
+		tasklet_schedule(&priv->irq_tasklet);
+	else if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta) {
+		/* Allow interrupt if was disabled by this handler and
+		 * no tasklet was schedules, We should not enable interrupt,
+		 * tasklet will enable it.
+		 */
+		iwl_enable_interrupts(priv);
+	}
+
+	spin_unlock(&priv->lock);
+	return IRQ_HANDLED;
+
+ none:
+	/* re-enable interrupts here since we don't have anything to service.
+	 * only Re-enable if disabled by irq.
+	 */
+	if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta)
+		iwl_enable_interrupts(priv);
+
+	spin_unlock(&priv->lock);
+	return IRQ_NONE;
+}
+EXPORT_SYMBOL(iwl_isr_ict);
+
+
+static irqreturn_t iwl_isr(int irq, void *data)
+{
+	struct iwl_priv *priv = data;
+	u32 inta, inta_mask;
+	u32 inta_fh;
+
+	if (!priv)
+		return IRQ_NONE;
+
+	spin_lock(&priv->lock);
+
+	/* Disable (but don't clear!) interrupts here to avoid
+	 *    back-to-back ISRs and sporadic interrupts from our NIC.
+	 * If we have something to service, the tasklet will re-enable ints.
+	 * If we *don't* have something, we'll re-enable before leaving here. */
+	inta_mask = iwl_read32(priv, CSR_INT_MASK);  /* just for debug */
+	iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+	/* Discover which interrupts are active/pending */
+	inta = iwl_read32(priv, CSR_INT);
+
+	/* Ignore interrupt if there's nothing in NIC to service.
+	 * This may be due to IRQ shared with another device,
+	 * or due to sporadic interrupts thrown from our NIC. */
+	if (!inta) {
+		IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n");
+		goto none;
+	}
+
+	if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
+		/* Hardware disappeared. It might have already raised
+		 * an interrupt */
+		IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
+		goto unplugged;
+	}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (priv->debug_level & (IWL_DL_ISR)) {
+		inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+		IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, "
+			      "fh 0x%08x\n", inta, inta_mask, inta_fh);
+	}
+#endif
+
+	priv->inta |= inta;
+	/* iwl_irq_tasklet() will service interrupts and re-enable them */
+	if (likely(inta))
+		tasklet_schedule(&priv->irq_tasklet);
+	else if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta)
+		iwl_enable_interrupts(priv);
+
+ unplugged:
+	spin_unlock(&priv->lock);
+	return IRQ_HANDLED;
+
+ none:
+	/* re-enable interrupts here since we don't have anything to service. */
+	/* only Re-enable if diabled by irq  and no schedules tasklet. */
+	if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta)
+		iwl_enable_interrupts(priv);
+
+	spin_unlock(&priv->lock);
+	return IRQ_NONE;
+}
+
+irqreturn_t iwl_isr_legacy(int irq, void *data)
 {
 	struct iwl_priv *priv = data;
 	u32 inta, inta_mask;
@@ -1544,7 +1822,7 @@
 	spin_unlock(&priv->lock);
 	return IRQ_NONE;
 }
-EXPORT_SYMBOL(iwl_isr);
+EXPORT_SYMBOL(iwl_isr_legacy);
 
 int iwl_send_bt_config(struct iwl_priv *priv)
 {
@@ -1588,10 +1866,6 @@
 
 	IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
 
-	ret = iwl_grab_nic_access(priv);
-	if (ret)
-		return ret;
-
 	for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
 		/* read data comes through single port, auto-incr addr */
 		/* NOTE: Use the debugless read so we don't flood kernel log
@@ -1607,8 +1881,6 @@
 		}
 	}
 
-	iwl_release_nic_access(priv);
-
 	return ret;
 }
 
@@ -1626,10 +1898,6 @@
 
 	IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
 
-	ret = iwl_grab_nic_access(priv);
-	if (ret)
-		return ret;
-
 	iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
 			   IWL49_RTC_INST_LOWER_BOUND);
 
@@ -1650,8 +1918,6 @@
 		}
 	}
 
-	iwl_release_nic_access(priv);
-
 	if (!errcnt)
 		IWL_DEBUG_INFO(priv,
 		    "ucode image in INSTRUCTION memory is good\n");
@@ -1760,7 +2026,6 @@
 	u32 data2, line;
 	u32 desc, time, count, base, data1;
 	u32 blink1, blink2, ilink1, ilink2;
-	int ret;
 
 	if (priv->ucode_type == UCODE_INIT)
 		base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
@@ -1772,12 +2037,6 @@
 		return;
 	}
 
-	ret = iwl_grab_nic_access(priv);
-	if (ret) {
-		IWL_WARN(priv, "Can not read from adapter at this time.\n");
-		return;
-	}
-
 	count = iwl_read_targ_mem(priv, base);
 
 	if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
@@ -1804,7 +2063,6 @@
 	IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
 		ilink1, ilink2);
 
-	iwl_release_nic_access(priv);
 }
 EXPORT_SYMBOL(iwl_dump_nic_error_log);
 
@@ -1813,7 +2071,6 @@
 /**
  * iwl_print_event_log - Dump error event log to syslog
  *
- * NOTE: Must be called with iwl_grab_nic_access() already obtained!
  */
 static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
 				u32 num_events, u32 mode)
@@ -1859,7 +2116,6 @@
 
 void iwl_dump_nic_event_log(struct iwl_priv *priv)
 {
-	int ret;
 	u32 base;       /* SRAM byte address of event log header */
 	u32 capacity;   /* event log capacity in # entries */
 	u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
@@ -1877,12 +2133,6 @@
 		return;
 	}
 
-	ret = iwl_grab_nic_access(priv);
-	if (ret) {
-		IWL_WARN(priv, "Can not read from adapter at this time.\n");
-		return;
-	}
-
 	/* event log header */
 	capacity = iwl_read_targ_mem(priv, base);
 	mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
@@ -1894,7 +2144,6 @@
 	/* bail out if nothing in log */
 	if (size == 0) {
 		IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
-		iwl_release_nic_access(priv);
 		return;
 	}
 
@@ -1909,7 +2158,6 @@
 	/* (then/else) start at top of log */
 	iwl_print_event_log(priv, 0, next_entry, mode);
 
-	iwl_release_nic_access(priv);
 }
 EXPORT_SYMBOL(iwl_dump_nic_event_log);
 
@@ -2016,11 +2264,11 @@
 	/* wake up ucode */
 	msleep(10);
 
-	spin_lock_irqsave(&priv->lock, flags);
 	iwl_read32(priv, CSR_UCODE_DRV_GP1);
+	spin_lock_irqsave(&priv->reg_lock, flags);
 	if (!iwl_grab_nic_access(priv))
 		iwl_release_nic_access(priv);
-	spin_unlock_irqrestore(&priv->lock, flags);
+	spin_unlock_irqrestore(&priv->reg_lock, flags);
 
 	if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
 		IWL_DEBUG_RF_KILL(priv, "Can not turn radio back on - "
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index f3544ea..87df1b7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -112,6 +112,19 @@
 			  struct iwl_rx_phy_res *rx_resp);
 };
 
+struct iwl_apm_ops {
+	int (*init)(struct iwl_priv *priv);
+	int (*reset)(struct iwl_priv *priv);
+	void (*stop)(struct iwl_priv *priv);
+	void (*config)(struct iwl_priv *priv);
+	int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src);
+};
+
+struct iwl_temp_ops {
+	void (*temperature)(struct iwl_priv *priv);
+	void (*set_ct_kill)(struct iwl_priv *priv);
+};
+
 struct iwl_lib_ops {
 	/* set hw dependent parameters */
 	int (*set_hw_params)(struct iwl_priv *priv);
@@ -149,23 +162,21 @@
 	int (*is_valid_rtc_data_addr)(u32 addr);
 	/* 1st ucode load */
 	int (*load_ucode)(struct iwl_priv *priv);
-	 /* power management */
-	struct {
-		int (*init)(struct iwl_priv *priv);
-		int (*reset)(struct iwl_priv *priv);
-		void (*stop)(struct iwl_priv *priv);
-		void (*config)(struct iwl_priv *priv);
-		int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src);
-	} apm_ops;
+	/* power management */
+	struct iwl_apm_ops apm_ops;
+
 	/* power */
 	int (*send_tx_power) (struct iwl_priv *priv);
 	void (*update_chain_flags)(struct iwl_priv *priv);
-	void (*temperature) (struct iwl_priv *priv);
 	void (*post_associate) (struct iwl_priv *priv);
 	void (*config_ap) (struct iwl_priv *priv);
+	irqreturn_t (*isr) (int irq, void *data);
 
 	/* eeprom operations (as defined in iwl-eeprom.h) */
 	struct iwl_eeprom_ops eeprom_ops;
+
+	/* temperature */
+	struct iwl_temp_ops temp_ops;
 };
 
 struct iwl_ops {
@@ -229,6 +240,7 @@
 	u8   valid_tx_ant;
 	u8   valid_rx_ant;
 	bool need_pll_cfg;
+	bool use_isr_legacy;
 };
 
 /***************************
@@ -306,10 +318,11 @@
 				  struct iwl_rx_queue *q);
 void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
 void iwl_rx_replenish(struct iwl_priv *priv);
+void iwl_rx_replenish_now(struct iwl_priv *priv);
 int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
 int iwl_rx_queue_restock(struct iwl_priv *priv);
 int iwl_rx_queue_space(const struct iwl_rx_queue *q);
-void iwl_rx_allocate(struct iwl_priv *priv);
+void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority);
 void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
 int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
 /* Handlers */
@@ -456,7 +469,13 @@
  *****************************************************/
 void iwl_disable_interrupts(struct iwl_priv *priv);
 void iwl_enable_interrupts(struct iwl_priv *priv);
-irqreturn_t iwl_isr(int irq, void *data);
+irqreturn_t iwl_isr_legacy(int irq, void *data);
+int iwl_reset_ict(struct iwl_priv *priv);
+void iwl_disable_ict(struct iwl_priv *priv);
+int iwl_alloc_isr_ict(struct iwl_priv *priv);
+void iwl_free_isr_ict(struct iwl_priv *priv);
+irqreturn_t iwl_isr_ict(int irq, void *data);
+
 static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv)
 {
 	int pos;
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index 6e98314..f03dae1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -89,6 +89,7 @@
 /* EEPROM reads */
 #define CSR_EEPROM_REG          (CSR_BASE+0x02c)
 #define CSR_EEPROM_GP           (CSR_BASE+0x030)
+#define CSR_OTP_GP_REG   	(CSR_BASE+0x034)
 #define CSR_GIO_REG		(CSR_BASE+0x03C)
 #define CSR_GP_UCODE		(CSR_BASE+0x044)
 #define CSR_UCODE_DRV_GP1       (CSR_BASE+0x054)
@@ -96,8 +97,10 @@
 #define CSR_UCODE_DRV_GP1_CLR   (CSR_BASE+0x05c)
 #define CSR_UCODE_DRV_GP2       (CSR_BASE+0x060)
 #define CSR_LED_REG             (CSR_BASE+0x094)
+#define CSR_DRAM_INT_TBL_REG	(CSR_BASE+0x0A0)
 #define CSR_GIO_CHICKEN_BITS    (CSR_BASE+0x100)
 
+#define CSR_INT_PERIODIC_REG	(CSR_BASE+0x005)
 /* Analog phase-lock-loop configuration  */
 #define CSR_ANA_PLL_CFG         (CSR_BASE+0x20c)
 /*
@@ -123,16 +126,18 @@
 
 #define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A		(0x00080000)
 #define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM		(0x00200000)
-#define CSR_HW_IF_CONFIG_REG_BIT_PCI_OWN_SEM		(0x00400000)
-#define CSR_HW_IF_CONFIG_REG_BIT_ME_OWN			(0x02000000)
-#define CSR_HW_IF_CONFIG_REG_BIT_WAKE_ME		(0x08000000)
+#define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY		(0x00400000)
+#define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE	(0x02000000)
+#define CSR_HW_IF_CONFIG_REG_PREPARE			(0x08000000)
 
+#define CSR_INT_PERIODIC_DIS			(0x00)
+#define CSR_INT_PERIODIC_ENA			(0xFF)
 
 /* interrupt flags in INTA, set by uCode or hardware (e.g. dma),
  * acknowledged (reset) by host writing "1" to flagged bits. */
 #define CSR_INT_BIT_FH_RX        (1 << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */
 #define CSR_INT_BIT_HW_ERR       (1 << 29) /* DMA hardware error FH_INT[31] */
-#define CSR_INT_BIT_DNLD         (1 << 28) /* uCode Download */
+#define CSR_INT_BIT_RX_PERIODIC	 (1 << 28) /* Rx periodic */
 #define CSR_INT_BIT_FH_TX        (1 << 27) /* Tx DMA FH_INT[1:0] */
 #define CSR_INT_BIT_SCD          (1 << 26) /* TXQ pointer advanced */
 #define CSR_INT_BIT_SW_ERR       (1 << 25) /* uCode error */
@@ -226,6 +231,10 @@
 #define CSR_EEPROM_GP_VALID_MSK		(0x00000007)
 #define CSR_EEPROM_GP_BAD_SIGNATURE	(0x00000000)
 #define CSR_EEPROM_GP_IF_OWNER_MSK	(0x00000180)
+#define CSR_OTP_GP_REG_DEVICE_SELECT	(0x00010000) /* 0 - EEPROM, 1 - OTP */
+#define CSR_OTP_GP_REG_OTP_ACCESS_MODE	(0x00020000) /* 0 - absolute, 1 - relative */
+#define CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK          (0x00100000) /* bit 20 */
+#define CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK        (0x00200000) /* bit 21 */
 
 /* CSR GIO */
 #define CSR_GIO_REG_VAL_L0S_ENABLED	(0x00000002)
@@ -251,6 +260,11 @@
 
 /* HPET MEM debug */
 #define CSR_DBG_HPET_MEM_REG_VAL	(0xFFFF0000)
+
+/* DRAM INT TABLE */
+#define CSR_DRAM_INT_TBL_ENABLE		(1 << 31)
+#define CSR_DRAM_INIT_TBL_WRAP_CHECK	(1 << 27)
+
 /*=== HBUS (Host-side Bus) ===*/
 #define HBUS_BASE	(0x400)
 /*
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index db06980..2cf014f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -68,7 +68,7 @@
 	struct dentry *dir_rf;
 	struct dir_data_files {
 		struct dentry *file_sram;
-		struct dentry *file_eeprom;
+		struct dentry *file_nvm;
 		struct dentry *file_stations;
 		struct dentry *file_rx_statistics;
 		struct dentry *file_tx_statistics;
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index ffc4be3..af70229 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -172,7 +172,6 @@
 	struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
 	const size_t bufsz = sizeof(buf);
 
-	iwl_grab_nic_access(priv);
 	for (i = priv->dbgfs->sram_len; i > 0; i -= 4) {
 		val = iwl_read_targ_mem(priv, priv->dbgfs->sram_offset + \
 					priv->dbgfs->sram_len - i);
@@ -192,7 +191,6 @@
 		pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val);
 	}
 	pos += scnprintf(buf + pos, bufsz - pos, "\n");
-	iwl_release_nic_access(priv);
 
 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 	return ret;
@@ -292,7 +290,7 @@
 	return ret;
 }
 
-static ssize_t iwl_dbgfs_eeprom_read(struct file *file,
+static ssize_t iwl_dbgfs_nvm_read(struct file *file,
 				       char __user *user_buf,
 				       size_t count,
 				       loff_t *ppos)
@@ -306,7 +304,7 @@
 	buf_size = 4 * eeprom_len + 256;
 
 	if (eeprom_len % 16) {
-		IWL_ERR(priv, "EEPROM size is not multiple of 16.\n");
+		IWL_ERR(priv, "NVM size is not multiple of 16.\n");
 		return -ENODATA;
 	}
 
@@ -318,6 +316,13 @@
 	}
 
 	ptr = priv->eeprom;
+	if (!ptr) {
+		IWL_ERR(priv, "Invalid EEPROM/OTP memory\n");
+		return -ENOMEM;
+	}
+	pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s\n",
+			(priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
+			? "OTP" : "EEPROM");
 	for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) {
 		pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs);
 		hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos,
@@ -375,51 +380,53 @@
 	}
 
 	supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ);
-	channels = supp_band->channels;
+	if (supp_band) {
+		channels = supp_band->channels;
 
-	pos += scnprintf(buf + pos, bufsz - pos,
-			"Displaying %d channels in 2.4GHz band 802.11bg):\n",
-			 supp_band->n_channels);
-
-	for (i = 0; i < supp_band->n_channels; i++)
 		pos += scnprintf(buf + pos, bufsz - pos,
-				"%d: %ddBm: BSS%s%s, %s.\n",
-				ieee80211_frequency_to_channel(
-				channels[i].center_freq),
-				channels[i].max_power,
-				channels[i].flags & IEEE80211_CHAN_RADAR ?
-				" (IEEE 802.11h required)" : "",
-				((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
-				|| (channels[i].flags &
-				IEEE80211_CHAN_RADAR)) ? "" :
-				", IBSS",
-				channels[i].flags &
-				IEEE80211_CHAN_PASSIVE_SCAN ?
-				"passive only" : "active/passive");
+				"Displaying %d channels in 2.4GHz band 802.11bg):\n",
+				supp_band->n_channels);
 
+		for (i = 0; i < supp_band->n_channels; i++)
+			pos += scnprintf(buf + pos, bufsz - pos,
+					"%d: %ddBm: BSS%s%s, %s.\n",
+					ieee80211_frequency_to_channel(
+					channels[i].center_freq),
+					channels[i].max_power,
+					channels[i].flags & IEEE80211_CHAN_RADAR ?
+					" (IEEE 802.11h required)" : "",
+					((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
+					|| (channels[i].flags &
+					IEEE80211_CHAN_RADAR)) ? "" :
+					", IBSS",
+					channels[i].flags &
+					IEEE80211_CHAN_PASSIVE_SCAN ?
+					"passive only" : "active/passive");
+	}
 	supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ);
-	channels = supp_band->channels;
+	if (supp_band) {
+		channels = supp_band->channels;
 
-	pos += scnprintf(buf + pos, bufsz - pos,
-			"Displaying %d channels in 5.2GHz band (802.11a)\n",
-			supp_band->n_channels);
-
-	for (i = 0; i < supp_band->n_channels; i++)
 		pos += scnprintf(buf + pos, bufsz - pos,
-				"%d: %ddBm: BSS%s%s, %s.\n",
-				ieee80211_frequency_to_channel(
-				channels[i].center_freq),
-				channels[i].max_power,
-				channels[i].flags & IEEE80211_CHAN_RADAR ?
-				" (IEEE 802.11h required)" : "",
-				((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
-				|| (channels[i].flags &
-				IEEE80211_CHAN_RADAR)) ? "" :
-				", IBSS",
-				channels[i].flags &
-				IEEE80211_CHAN_PASSIVE_SCAN ?
-				"passive only" : "active/passive");
+				"Displaying %d channels in 5.2GHz band (802.11a)\n",
+				supp_band->n_channels);
 
+		for (i = 0; i < supp_band->n_channels; i++)
+			pos += scnprintf(buf + pos, bufsz - pos,
+					"%d: %ddBm: BSS%s%s, %s.\n",
+					ieee80211_frequency_to_channel(
+					channels[i].center_freq),
+					channels[i].max_power,
+					channels[i].flags & IEEE80211_CHAN_RADAR ?
+					" (IEEE 802.11h required)" : "",
+					((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
+					|| (channels[i].flags &
+					IEEE80211_CHAN_RADAR)) ? "" :
+					", IBSS",
+					channels[i].flags &
+					IEEE80211_CHAN_PASSIVE_SCAN ?
+					"passive only" : "active/passive");
+	}
 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 	kfree(buf);
 	return ret;
@@ -564,7 +571,7 @@
 
 DEBUGFS_READ_WRITE_FILE_OPS(sram);
 DEBUGFS_WRITE_FILE_OPS(log_event);
-DEBUGFS_READ_FILE_OPS(eeprom);
+DEBUGFS_READ_FILE_OPS(nvm);
 DEBUGFS_READ_FILE_OPS(stations);
 DEBUGFS_READ_FILE_OPS(rx_statistics);
 DEBUGFS_READ_FILE_OPS(tx_statistics);
@@ -598,7 +605,7 @@
 
 	DEBUGFS_ADD_DIR(data, dbgfs->dir_drv);
 	DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv);
-	DEBUGFS_ADD_FILE(eeprom, data);
+	DEBUGFS_ADD_FILE(nvm, data);
 	DEBUGFS_ADD_FILE(sram, data);
 	DEBUGFS_ADD_FILE(log_event, data);
 	DEBUGFS_ADD_FILE(stations, data);
@@ -629,7 +636,7 @@
 	if (!priv->dbgfs)
 		return;
 
-	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_eeprom);
+	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_nvm);
 	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_rx_statistics);
 	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics);
 	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 3049ba2..2dafc26 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -382,6 +382,7 @@
 	u32 read;
 	u32 write;
 	u32 free_count;
+	u32 write_actual;
 	struct list_head rx_free;
 	struct list_head rx_used;
 	int need_update;
@@ -499,22 +500,13 @@
 #define STA_PS_STATUS_WAKE             0
 #define STA_PS_STATUS_SLEEP            1
 
-struct iwl3945_tid_data {
-	u16 seq_number;
-};
-
-struct iwl3945_hw_key {
-	enum ieee80211_key_alg alg;
-	int keylen;
-	u8 key[32];
-};
 
 struct iwl3945_station_entry {
 	struct iwl3945_addsta_cmd sta;
-	struct iwl3945_tid_data tid[MAX_TID_COUNT];
+	struct iwl_tid_data tid[MAX_TID_COUNT];
 	u8 used;
 	u8 ps_status;
-	struct iwl3945_hw_key keyinfo;
+	struct iwl_hw_key keyinfo;
 };
 
 struct iwl_station_entry {
@@ -823,6 +815,11 @@
 	MEASUREMENT_ACTIVE = (1 << 1),
 };
 
+enum iwl_nvm_type {
+	NVM_DEVICE_TYPE_EEPROM = 0,
+	NVM_DEVICE_TYPE_OTP,
+};
+
 /* interrupt statistics */
 struct isr_statistics {
 	u32 hw;
@@ -900,6 +897,7 @@
 	/* spinlock */
 	spinlock_t lock;	/* protect general shared data */
 	spinlock_t hcmd_lock;	/* protect hcmd */
+	spinlock_t reg_lock;	/* protect hw register access */
 	struct mutex mutex;
 
 	/* basic pci-network driver stuff */
@@ -1033,6 +1031,7 @@
 
 	/* eeprom */
 	u8 *eeprom;
+	int    nvm_device_type;
 	struct iwl_eeprom_calib_info *calib_info;
 
 	enum nl80211_iftype iw_mode;
@@ -1050,7 +1049,16 @@
 	/*End*/
 	struct iwl_hw_params hw_params;
 
+	/* INT ICT Table */
+	u32 *ict_tbl;
+	dma_addr_t ict_tbl_dma;
+	dma_addr_t aligned_ict_tbl_dma;
+	int ict_index;
+	void *ict_tbl_vir;
+	u32 inta;
+	bool use_ict;
 
+	u32 inta_mask;
 	/* Current association information needed to configure the
 	 * hardware */
 	u16 assoc_id;
@@ -1105,7 +1113,7 @@
 	u32 disable_tx_power_cal;
 	struct work_struct run_time_calib_work;
 	struct timer_list statistics_periodic;
-
+	bool hw_ready;
 	/*For 3945*/
 #define IWL_DEFAULT_TX_POWER 0x0F
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index 401438a..cefa501 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -152,6 +152,32 @@
 }
 EXPORT_SYMBOL(iwlcore_eeprom_verify_signature);
 
+static int iwlcore_get_nvm_type(struct iwl_priv *priv)
+{
+	u32 otpgp;
+	int nvm_type;
+
+	/* OTP only valid for CP/PP and after */
+	switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+	case CSR_HW_REV_TYPE_3945:
+	case CSR_HW_REV_TYPE_4965:
+	case CSR_HW_REV_TYPE_5300:
+	case CSR_HW_REV_TYPE_5350:
+	case CSR_HW_REV_TYPE_5100:
+	case CSR_HW_REV_TYPE_5150:
+		nvm_type = NVM_DEVICE_TYPE_EEPROM;
+		break;
+	default:
+		otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
+		if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT)
+			nvm_type = NVM_DEVICE_TYPE_OTP;
+		else
+			nvm_type = NVM_DEVICE_TYPE_EEPROM;
+		break;
+	}
+	return  nvm_type;
+}
+
 /*
  * The device's EEPROM semaphore prevents conflicts between driver and uCode
  * when accessing the EEPROM; each access is a series of pulses to/from the
@@ -198,6 +224,33 @@
 }
 EXPORT_SYMBOL(iwlcore_eeprom_query_addr);
 
+static int iwl_init_otp_access(struct iwl_priv *priv)
+{
+	int ret;
+
+	/* Enable 40MHz radio clock */
+	_iwl_write32(priv, CSR_GP_CNTRL,
+		     _iwl_read32(priv, CSR_GP_CNTRL) |
+		     CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+
+	/* wait for clock to be ready */
+	ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
+				  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+				  25000);
+	if (ret < 0)
+		IWL_ERR(priv, "Time out access OTP\n");
+	else {
+		if (!ret) {
+			iwl_set_bits_prph(priv, APMG_PS_CTRL_REG,
+					  APMG_PS_CTRL_VAL_RESET_REQ);
+			udelay(5);
+			iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG,
+					    APMG_PS_CTRL_VAL_RESET_REQ);
+		}
+	}
+	return ret;
+}
+
 /**
  * iwl_eeprom_init - read EEPROM contents
  *
@@ -209,11 +262,18 @@
 {
 	u16 *e;
 	u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
-	int sz = priv->cfg->eeprom_size;
+	int sz;
 	int ret;
 	u16 addr;
+	u32 otpgp;
+
+	priv->nvm_device_type = iwlcore_get_nvm_type(priv);
 
 	/* allocate eeprom */
+	if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
+		priv->cfg->eeprom_size =
+			OTP_BLOCK_SIZE * OTP_LOWER_BLOCKS_TOTAL;
+	sz = priv->cfg->eeprom_size;
 	priv->eeprom = kzalloc(sz, GFP_KERNEL);
 	if (!priv->eeprom) {
 		ret = -ENOMEM;
@@ -235,30 +295,77 @@
 		ret = -ENOENT;
 		goto err;
 	}
-
-	/* eeprom is an array of 16bit values */
-	for (addr = 0; addr < sz; addr += sizeof(u16)) {
-		u32 r;
-
-		_iwl_write32(priv, CSR_EEPROM_REG,
-			     CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
-
-		ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
-					  CSR_EEPROM_REG_READ_VALID_MSK,
-					  IWL_EEPROM_ACCESS_TIMEOUT);
-		if (ret < 0) {
-			IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr);
-			goto done;
+	if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
+		ret = iwl_init_otp_access(priv);
+		if (ret) {
+			IWL_ERR(priv, "Failed to initialize OTP access.\n");
+			ret = -ENOENT;
+			goto err;
 		}
-		r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
-		e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
+		_iwl_write32(priv, CSR_EEPROM_GP,
+			     iwl_read32(priv, CSR_EEPROM_GP) &
+			     ~CSR_EEPROM_GP_IF_OWNER_MSK);
+		/* clear */
+		_iwl_write32(priv, CSR_OTP_GP_REG,
+			     iwl_read32(priv, CSR_OTP_GP_REG) |
+			     CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK |
+			     CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
+
+		for (addr = 0; addr < sz; addr += sizeof(u16)) {
+			u32 r;
+
+			_iwl_write32(priv, CSR_EEPROM_REG,
+				     CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
+
+			ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
+						  CSR_EEPROM_REG_READ_VALID_MSK,
+						  IWL_EEPROM_ACCESS_TIMEOUT);
+			if (ret < 0) {
+				IWL_ERR(priv, "Time out reading OTP[%d]\n", addr);
+				goto done;
+			}
+			r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
+			/* check for ECC errors: */
+			otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
+			if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
+				/* stop in this case */
+				IWL_ERR(priv, "Uncorrectable OTP ECC error, Abort OTP read\n");
+				goto done;
+			}
+			if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
+				/* continue in this case */
+				_iwl_write32(priv, CSR_OTP_GP_REG,
+					     iwl_read32(priv, CSR_OTP_GP_REG) |
+					     CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
+				IWL_ERR(priv, "Correctable OTP ECC error, continue read\n");
+			}
+			e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
+		}
+	} else {
+		/* eeprom is an array of 16bit values */
+		for (addr = 0; addr < sz; addr += sizeof(u16)) {
+			u32 r;
+
+			_iwl_write32(priv, CSR_EEPROM_REG,
+				     CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
+
+			ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
+						  CSR_EEPROM_REG_READ_VALID_MSK,
+						  IWL_EEPROM_ACCESS_TIMEOUT);
+			if (ret < 0) {
+				IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr);
+				goto done;
+			}
+			r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
+			e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
+		}
 	}
 	ret = 0;
 done:
 	priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv);
 err:
 	if (ret)
-		kfree(priv->eeprom);
+		iwl_eeprom_free(priv);
 alloc_err:
 	return ret;
 }
@@ -301,6 +408,8 @@
 
 u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset)
 {
+	if (!priv->eeprom)
+		return 0;
 	return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8);
 }
 EXPORT_SYMBOL(iwl_eeprom_query16);
@@ -481,8 +590,8 @@
 			/* First write that fat is not enabled, and then enable
 			 * one by one */
 			ch_info->fat_extension_channel =
-				(IEEE80211_CHAN_NO_FAT_ABOVE |
-				 IEEE80211_CHAN_NO_FAT_BELOW);
+				(IEEE80211_CHAN_NO_HT40PLUS |
+				 IEEE80211_CHAN_NO_HT40MINUS);
 
 			if (!(is_channel_valid(ch_info))) {
 				IWL_DEBUG_INFO(priv, "Ch. %d Flags %x [%sGHz] - "
@@ -561,7 +670,7 @@
 				fat_extension_chan = 0;
 			else
 				fat_extension_chan =
-					IEEE80211_CHAN_NO_FAT_BELOW;
+					IEEE80211_CHAN_NO_HT40MINUS;
 
 			/* Set up driver's info for lower half */
 			iwl_set_fat_chan_info(priv, ieeeband,
@@ -573,7 +682,7 @@
 			iwl_set_fat_chan_info(priv, ieeeband,
 						(eeprom_ch_index[ch] + 4),
 						&(eeprom_ch_info[ch]),
-						IEEE80211_CHAN_NO_FAT_ABOVE);
+						IEEE80211_CHAN_NO_HT40PLUS);
 		}
 	}
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index 3479153..195b4ef 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -179,6 +179,10 @@
 #define EEPROM_5050_TX_POWER_VERSION    (4)
 #define EEPROM_5050_EEPROM_VERSION	(0x21E)
 
+/* OTP */
+#define OTP_LOWER_BLOCKS_TOTAL		(3)
+#define OTP_BLOCK_SIZE			(0x400)
+
 /* 2.4 GHz */
 extern const u8 iwl_eeprom_band_1[14];
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
index 083ea1f..d30cb02 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -131,9 +131,23 @@
 	IWL_DEBUG_IO(priv, "set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
 	_iwl_write32(priv, reg, val);
 }
-#define iwl_set_bit(p, r, m) __iwl_set_bit(__FILE__, __LINE__, p, r, m)
+static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m)
+{
+	unsigned long reg_flags;
+
+	spin_lock_irqsave(&p->reg_lock, reg_flags);
+	__iwl_set_bit(__FILE__, __LINE__, p, r, m);
+	spin_unlock_irqrestore(&p->reg_lock, reg_flags);
+}
 #else
-#define iwl_set_bit(p, r, m) _iwl_set_bit(p, r, m)
+static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m)
+{
+	unsigned long reg_flags;
+
+	spin_lock_irqsave(&p->reg_lock, reg_flags);
+	_iwl_set_bit(p, r, m);
+	spin_unlock_irqrestore(&p->reg_lock, reg_flags);
+}
 #endif
 
 static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask)
@@ -148,19 +162,30 @@
 	IWL_DEBUG_IO(priv, "clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
 	_iwl_write32(priv, reg, val);
 }
-#define iwl_clear_bit(p, r, m) __iwl_clear_bit(__FILE__, __LINE__, p, r, m)
+static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m)
+{
+	unsigned long reg_flags;
+
+	spin_lock_irqsave(&p->reg_lock, reg_flags);
+	__iwl_clear_bit(__FILE__, __LINE__, p, r, m);
+	spin_unlock_irqrestore(&p->reg_lock, reg_flags);
+}
 #else
-#define iwl_clear_bit(p, r, m) _iwl_clear_bit(p, r, m)
+static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m)
+{
+	unsigned long reg_flags;
+
+	spin_lock_irqsave(&p->reg_lock, reg_flags);
+	_iwl_clear_bit(p, r, m);
+	spin_unlock_irqrestore(&p->reg_lock, reg_flags);
+}
 #endif
 
 static inline int _iwl_grab_nic_access(struct iwl_priv *priv)
 {
 	int ret;
 	u32 val;
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (atomic_read(&priv->restrict_refcnt))
-		return 0;
-#endif
+
 	/* this bit wakes up the NIC */
 	_iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
 	ret = _iwl_poll_bit(priv, CSR_GP_CNTRL,
@@ -170,12 +195,10 @@
 	if (ret < 0) {
 		val = _iwl_read32(priv, CSR_GP_CNTRL);
 		IWL_ERR(priv, "MAC is in deep sleep!.  CSR_GP_CNTRL = 0x%08X\n", val);
+		_iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
 		return -EIO;
 	}
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-	atomic_inc(&priv->restrict_refcnt);
-#endif
 	return 0;
 }
 
@@ -183,9 +206,6 @@
 static inline int __iwl_grab_nic_access(const char *f, u32 l,
 					       struct iwl_priv *priv)
 {
-	if (atomic_read(&priv->restrict_refcnt))
-		IWL_ERR(priv, "Grabbing access while already held %s %d.\n", f, l);
-
 	IWL_DEBUG_IO(priv, "grabbing nic access - %s %d\n", f, l);
 	return _iwl_grab_nic_access(priv);
 }
@@ -198,18 +218,13 @@
 
 static inline void _iwl_release_nic_access(struct iwl_priv *priv)
 {
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (atomic_dec_and_test(&priv->restrict_refcnt))
-#endif
-		_iwl_clear_bit(priv, CSR_GP_CNTRL,
-			       CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+	_iwl_clear_bit(priv, CSR_GP_CNTRL,
+			CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
 }
 #ifdef CONFIG_IWLWIFI_DEBUG
 static inline void __iwl_release_nic_access(const char *f, u32 l,
 					    struct iwl_priv *priv)
 {
-	if (atomic_read(&priv->restrict_refcnt) <= 0)
-		IWL_ERR(priv, "Release unheld nic access at line %s %d.\n", f, l);
 
 	IWL_DEBUG_IO(priv, "releasing nic access - %s %d\n", f, l);
 	_iwl_release_nic_access(priv);
@@ -230,16 +245,37 @@
 					struct iwl_priv *priv, u32 reg)
 {
 	u32 value = _iwl_read_direct32(priv, reg);
-	if (!atomic_read(&priv->restrict_refcnt))
-		IWL_ERR(priv, "Nic access not held from %s %d\n", f, l);
 	IWL_DEBUG_IO(priv, "read_direct32(0x%4X) = 0x%08x - %s %d \n", reg, value,
 		     f, l);
 	return value;
 }
-#define iwl_read_direct32(priv, reg) \
-	__iwl_read_direct32(__FILE__, __LINE__, priv, reg)
+static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg)
+{
+	u32 value;
+	unsigned long reg_flags;
+
+	spin_lock_irqsave(&priv->reg_lock, reg_flags);
+	iwl_grab_nic_access(priv);
+	value = __iwl_read_direct32(__FILE__, __LINE__, priv, reg);
+	iwl_release_nic_access(priv);
+	spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
+	return value;
+}
+
 #else
-#define iwl_read_direct32 _iwl_read_direct32
+static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg)
+{
+	u32 value;
+	unsigned long reg_flags;
+
+	spin_lock_irqsave(&priv->reg_lock, reg_flags);
+	iwl_grab_nic_access(priv);
+	value = _iwl_read_direct32(priv, reg);
+	iwl_release_nic_access(priv);
+	spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
+	return value;
+
+}
 #endif
 
 static inline void _iwl_write_direct32(struct iwl_priv *priv,
@@ -247,19 +283,17 @@
 {
 	_iwl_write32(priv, reg, value);
 }
-#ifdef CONFIG_IWLWIFI_DEBUG
-static void __iwl_write_direct32(const char *f , u32 line,
-				   struct iwl_priv *priv, u32 reg, u32 value)
+static inline void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value)
 {
-	if (!atomic_read(&priv->restrict_refcnt))
-		IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line);
-	_iwl_write_direct32(priv, reg, value);
+	unsigned long reg_flags;
+
+	spin_lock_irqsave(&priv->reg_lock, reg_flags);
+	if (!iwl_grab_nic_access(priv)) {
+		_iwl_write_direct32(priv, reg, value);
+		iwl_release_nic_access(priv);
+	}
+	spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
 }
-#define iwl_write_direct32(priv, reg, value) \
-	__iwl_write_direct32(__func__, __LINE__, priv, reg, value)
-#else
-#define iwl_write_direct32 _iwl_write_direct32
-#endif
 
 static inline void iwl_write_reg_buf(struct iwl_priv *priv,
 					       u32 reg, u32 len, u32 *values)
@@ -268,14 +302,23 @@
 
 	if ((priv != NULL) && (values != NULL)) {
 		for (; 0 < len; len -= count, reg += count, values++)
-			_iwl_write_direct32(priv, reg, *values);
+			iwl_write_direct32(priv, reg, *values);
 	}
 }
 
 static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr,
 				       u32 mask, int timeout)
 {
-	return _iwl_poll_bit(priv, addr, mask, mask, timeout);
+	int t = 0;
+
+	do {
+		if ((iwl_read_direct32(priv, addr) & mask) == mask)
+			return t;
+		udelay(IWL_POLL_INTERVAL);
+		t += IWL_POLL_INTERVAL;
+	} while (t < timeout);
+
+	return -ETIMEDOUT;
 }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -305,20 +348,18 @@
 	rmb();
 	return _iwl_read_direct32(priv, HBUS_TARG_PRPH_RDAT);
 }
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline u32 __iwl_read_prph(const char *f, u32 line,
-				  struct iwl_priv *priv, u32 reg)
+static inline u32 iwl_read_prph(struct iwl_priv *priv, u32 reg)
 {
-	if (!atomic_read(&priv->restrict_refcnt))
-		IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line);
-	return _iwl_read_prph(priv, reg);
-}
+	unsigned long reg_flags;
+	u32 val;
 
-#define iwl_read_prph(priv, reg) \
-	__iwl_read_prph(__func__, __LINE__, priv, reg)
-#else
-#define iwl_read_prph _iwl_read_prph
-#endif
+	spin_lock_irqsave(&priv->reg_lock, reg_flags);
+	iwl_grab_nic_access(priv);
+	val = _iwl_read_prph(priv, reg);
+	iwl_release_nic_access(priv);
+	spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
+	return val;
+}
 
 static inline void _iwl_write_prph(struct iwl_priv *priv,
 					     u32 addr, u32 val)
@@ -328,83 +369,107 @@
 	wmb();
 	_iwl_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val);
 }
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void __iwl_write_prph(const char *f, u32 line,
-				    struct iwl_priv *priv, u32 addr, u32 val)
-{
-	if (!atomic_read(&priv->restrict_refcnt))
-		IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line);
-	_iwl_write_prph(priv, addr, val);
-}
 
-#define iwl_write_prph(priv, addr, val) \
-	__iwl_write_prph(__func__, __LINE__, priv, addr, val);
-#else
-#define iwl_write_prph _iwl_write_prph
-#endif
+static inline void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val)
+{
+	unsigned long reg_flags;
+
+	spin_lock_irqsave(&priv->reg_lock, reg_flags);
+	if (!iwl_grab_nic_access(priv)) {
+		_iwl_write_prph(priv, addr, val);
+		iwl_release_nic_access(priv);
+	}
+	spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
+}
 
 #define _iwl_set_bits_prph(priv, reg, mask) \
 	_iwl_write_prph(priv, reg, (_iwl_read_prph(priv, reg) | mask))
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void __iwl_set_bits_prph(const char *f, u32 line,
-				       struct iwl_priv *priv,
-				       u32 reg, u32 mask)
-{
-	if (!atomic_read(&priv->restrict_refcnt))
-		IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line);
 
+static inline void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask)
+{
+	unsigned long reg_flags;
+
+	spin_lock_irqsave(&priv->reg_lock, reg_flags);
+	iwl_grab_nic_access(priv);
 	_iwl_set_bits_prph(priv, reg, mask);
+	iwl_release_nic_access(priv);
+	spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
 }
-#define iwl_set_bits_prph(priv, reg, mask) \
-	__iwl_set_bits_prph(__func__, __LINE__, priv, reg, mask)
-#else
-#define iwl_set_bits_prph _iwl_set_bits_prph
-#endif
 
 #define _iwl_set_bits_mask_prph(priv, reg, bits, mask) \
 	_iwl_write_prph(priv, reg, ((_iwl_read_prph(priv, reg) & mask) | bits))
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void __iwl_set_bits_mask_prph(const char *f, u32 line,
-		struct iwl_priv *priv, u32 reg, u32 bits, u32 mask)
+static inline void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg,
+				u32 bits, u32 mask)
 {
-	if (!atomic_read(&priv->restrict_refcnt))
-		IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line);
+	unsigned long reg_flags;
+
+	spin_lock_irqsave(&priv->reg_lock, reg_flags);
+	iwl_grab_nic_access(priv);
 	_iwl_set_bits_mask_prph(priv, reg, bits, mask);
+	iwl_release_nic_access(priv);
+	spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
 }
-#define iwl_set_bits_mask_prph(priv, reg, bits, mask) \
-	__iwl_set_bits_mask_prph(__func__, __LINE__, priv, reg, bits, mask)
-#else
-#define iwl_set_bits_mask_prph _iwl_set_bits_mask_prph
-#endif
 
 static inline void iwl_clear_bits_prph(struct iwl_priv
 						 *priv, u32 reg, u32 mask)
 {
-	u32 val = _iwl_read_prph(priv, reg);
+	unsigned long reg_flags;
+	u32 val;
+
+	spin_lock_irqsave(&priv->reg_lock, reg_flags);
+	iwl_grab_nic_access(priv);
+	val = _iwl_read_prph(priv, reg);
 	_iwl_write_prph(priv, reg, (val & ~mask));
+	iwl_release_nic_access(priv);
+	spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
 }
 
 static inline u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr)
 {
-	iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr);
+	unsigned long reg_flags;
+	u32 value;
+
+	spin_lock_irqsave(&priv->reg_lock, reg_flags);
+	iwl_grab_nic_access(priv);
+
+	_iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr);
 	rmb();
-	return iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+	value = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+
+	iwl_release_nic_access(priv);
+	spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
+	return value;
 }
 
 static inline void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val)
 {
-	iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
-	wmb();
-	iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val);
+	unsigned long reg_flags;
+
+	spin_lock_irqsave(&priv->reg_lock, reg_flags);
+	if (!iwl_grab_nic_access(priv)) {
+		_iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
+		wmb();
+		_iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val);
+		iwl_release_nic_access(priv);
+	}
+	spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
 }
 
 static inline void iwl_write_targ_mem_buf(struct iwl_priv *priv, u32 addr,
 					  u32 len, u32 *values)
 {
-	iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
-	wmb();
-	for (; 0 < len; len -= sizeof(u32), values++)
-		iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values);
+	unsigned long reg_flags;
+
+	spin_lock_irqsave(&priv->reg_lock, reg_flags);
+	if (!iwl_grab_nic_access(priv)) {
+		_iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
+		wmb();
+		for (; 0 < len; len -= sizeof(u32), values++)
+			_iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values);
+
+		iwl_release_nic_access(priv);
+	}
+	spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
 }
 #endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index fae8426..2b8d40b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -145,18 +145,14 @@
 			goto exit_unlock;
 		}
 
-		ret = iwl_grab_nic_access(priv);
-		if (ret)
-			goto exit_unlock;
-
-		/* Device expects a multiple of 8 */
-		iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write & ~0x7);
-		iwl_release_nic_access(priv);
+		q->write_actual = (q->write & ~0x7);
+		iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write_actual);
 
 	/* Else device is assumed to be awake */
 	} else {
 		/* Device expects a multiple of 8 */
-		iwl_write32(priv, rx_wrt_ptr_reg, q->write & ~0x7);
+		q->write_actual = (q->write & ~0x7);
+		iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write_actual);
 	}
 
 	q->need_update = 0;
@@ -218,7 +214,7 @@
 
 	/* If we've added more space for the firmware to place data, tell it.
 	 * Increment device's write pointer in multiples of 8. */
-	if (write != (rxq->write & ~0x7)) {
+	if (rxq->write_actual != (rxq->write & ~0x7)) {
 		spin_lock_irqsave(&rxq->lock, flags);
 		rxq->need_update = 1;
 		spin_unlock_irqrestore(&rxq->lock, flags);
@@ -238,7 +234,7 @@
  * Also restock the Rx queue via iwl_rx_queue_restock.
  * This is called as a scheduled work item (except for during initialization)
  */
-void iwl_rx_allocate(struct iwl_priv *priv)
+void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
 {
 	struct iwl_rx_queue *rxq = &priv->rxq;
 	struct list_head *element;
@@ -260,7 +256,8 @@
 
 		/* Alloc a new receive buffer */
 		rxb->skb = alloc_skb(priv->hw_params.rx_buf_size + 256,
-				     GFP_KERNEL);
+						priority);
+
 		if (!rxb->skb) {
 			IWL_CRIT(priv, "Can not allocate SKB buffers\n");
 			/* We don't reschedule replenish work here -- we will
@@ -295,7 +292,7 @@
 {
 	unsigned long flags;
 
-	iwl_rx_allocate(priv);
+	iwl_rx_allocate(priv, GFP_KERNEL);
 
 	spin_lock_irqsave(&priv->lock, flags);
 	iwl_rx_queue_restock(priv);
@@ -303,6 +300,14 @@
 }
 EXPORT_SYMBOL(iwl_rx_replenish);
 
+void iwl_rx_replenish_now(struct iwl_priv *priv)
+{
+	iwl_rx_allocate(priv, GFP_ATOMIC);
+
+	iwl_rx_queue_restock(priv);
+}
+EXPORT_SYMBOL(iwl_rx_replenish_now);
+
 
 /* Assumes that the skb field of the buffers in 'pool' is kept accurate.
  * If an SKB has been detached, the POOL needs to have its SKB set to NULL
@@ -358,6 +363,7 @@
 	/* Set us so that we have processed and used all buffers, but have
 	 * not restocked the Rx queue with fresh buffers */
 	rxq->read = rxq->write = 0;
+	rxq->write_actual = 0;
 	rxq->free_count = 0;
 	rxq->need_update = 0;
 	return 0;
@@ -396,6 +402,7 @@
 	/* Set us so that we have processed and used all buffers, but have
 	 * not restocked the Rx queue with fresh buffers */
 	rxq->read = rxq->write = 0;
+	rxq->write_actual = 0;
 	rxq->free_count = 0;
 	spin_unlock_irqrestore(&rxq->lock, flags);
 }
@@ -403,18 +410,12 @@
 
 int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
 {
-	int ret;
-	unsigned long flags;
 	u32 rb_size;
 	const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
-	const u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT why this stalls RX */
+	u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */
 
-	spin_lock_irqsave(&priv->lock, flags);
-	ret = iwl_grab_nic_access(priv);
-	if (ret) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return ret;
-	}
+	if (!priv->cfg->use_isr_legacy)
+		rb_timeout = RX_RB_TIMEOUT;
 
 	if (priv->cfg->mod_params->amsdu_size_8K)
 		rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
@@ -452,35 +453,19 @@
 			   (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
 			   (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
 
-	iwl_release_nic_access(priv);
-
 	iwl_write32(priv, CSR_INT_COALESCING, 0x40);
 
-	spin_unlock_irqrestore(&priv->lock, flags);
-
 	return 0;
 }
 
 int iwl_rxq_stop(struct iwl_priv *priv)
 {
-	int ret;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	ret = iwl_grab_nic_access(priv);
-	if (unlikely(ret)) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return ret;
-	}
 
 	/* stop Rx DMA */
 	iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
 	iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
 			    FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
 
-	iwl_release_nic_access(priv);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
 	return 0;
 }
 EXPORT_SYMBOL(iwl_rxq_stop);
@@ -582,8 +567,8 @@
 
 	iwl_leds_background(priv);
 
-	if (priv->cfg->ops->lib->temperature && change)
-		priv->cfg->ops->lib->temperature(priv);
+	if (priv->cfg->ops->lib->temp_ops.temperature && change)
+		priv->cfg->ops->lib->temp_ops.temperature(priv);
 }
 EXPORT_SYMBOL(iwl_rx_statistics);
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 065214b..e26875d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -227,9 +227,6 @@
 	/* The HW is no longer scanning */
 	clear_bit(STATUS_SCAN_HW, &priv->status);
 
-	/* The scan completion notification came in, so kill that timer... */
-	cancel_delayed_work(&priv->scan_check);
-
 	IWL_DEBUG_INFO(priv, "Scan pass on %sGHz took %dms\n",
 		       (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) ?
 						"2.4" : "5.2",
@@ -586,11 +583,14 @@
 	u8 rx_ant = priv->hw_params.valid_rx_ant;
 	u8 rate;
 	bool is_active = false;
+	int  chan_mod;
 
 	conf = ieee80211_get_hw_conf(priv->hw);
 
 	mutex_lock(&priv->mutex);
 
+	cancel_delayed_work(&priv->scan_check);
+
 	if (!iwl_is_ready(priv)) {
 		IWL_WARN(priv, "request scan called when driver not ready.\n");
 		goto done;
@@ -703,7 +703,9 @@
 	if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) {
 		band = IEEE80211_BAND_2GHZ;
 		scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
-		if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) {
+		chan_mod = le32_to_cpu(priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_MSK)
+				       >> RXON_FLG_CHANNEL_MODE_POS;
+		if (chan_mod == CHANNEL_MODE_PURE_40) {
 			rate = IWL_RATE_6M_PLCP;
 		} else {
 			rate = IWL_RATE_1M_PLCP;
@@ -816,6 +818,8 @@
 
 	IWL_DEBUG_SCAN(priv, "SCAN complete scan\n");
 
+	cancel_delayed_work(&priv->scan_check);
+
 	ieee80211_scan_completed(priv->hw, false);
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index a82cca0..85ae7a6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -102,13 +102,8 @@
 			return ret;
 		}
 
-		/* restore this queue's parameters in nic hardware. */
-		ret = iwl_grab_nic_access(priv);
-		if (ret)
-			return ret;
 		iwl_write_direct32(priv, HBUS_TARG_WRPTR,
 				     txq->q.write_ptr | (txq_id << 8));
-		iwl_release_nic_access(priv);
 
 	/* else not in power-save mode, uCode will never sleep when we're
 	 * trying to tx (during RFKILL, we're not trying to tx). */
@@ -429,11 +424,6 @@
 		goto error_kw;
 	}
 	spin_lock_irqsave(&priv->lock, flags);
-	ret = iwl_grab_nic_access(priv);
-	if (unlikely(ret)) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		goto error_reset;
-	}
 
 	/* Turn off all Tx DMA fifos */
 	priv->cfg->ops->lib->txq_set_sched(priv, 0);
@@ -441,7 +431,6 @@
 	/* Tell NIC where to find the "keep warm" buffer */
 	iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
 
-	iwl_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	/* Alloc and init all Tx queues, including the command queue (#4) */
@@ -460,7 +449,6 @@
 
  error:
 	iwl_hw_txq_ctx_free(priv);
- error_reset:
 	iwl_free_dma_ptr(priv, &priv->kw);
  error_kw:
 	iwl_free_dma_ptr(priv, &priv->scd_bc_tbls);
@@ -478,10 +466,6 @@
 
 	/* Turn off all Tx DMA fifos */
 	spin_lock_irqsave(&priv->lock, flags);
-	if (iwl_grab_nic_access(priv)) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return;
-	}
 
 	priv->cfg->ops->lib->txq_set_sched(priv, 0);
 
@@ -492,7 +476,6 @@
 				    FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
 				    1000);
 	}
-	iwl_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	/* Deallocate memory for all Tx queues */
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index c32ec80..5c10b87 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -340,7 +340,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->sta_lock, flags);
-	memset(&priv->stations_39[sta_id].keyinfo, 0, sizeof(struct iwl3945_hw_key));
+	memset(&priv->stations_39[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key));
 	memset(&priv->stations_39[sta_id].sta.key, 0,
 		sizeof(struct iwl4965_keyinfo));
 	priv->stations_39[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
@@ -578,8 +578,7 @@
 				      int sta_id)
 {
 	struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
-	struct iwl3945_hw_key *keyinfo =
-	    &priv->stations_39[sta_id].keyinfo;
+	struct iwl_hw_key *keyinfo = &priv->stations_39[sta_id].keyinfo;
 
 	switch (keyinfo->alg) {
 	case ALG_CCMP:
@@ -1687,7 +1686,6 @@
 	u32 i;
 	u32 desc, time, count, base, data1;
 	u32 blink1, blink2, ilink1, ilink2;
-	int rc;
 
 	base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
 
@@ -1696,11 +1694,6 @@
 		return;
 	}
 
-	rc = iwl_grab_nic_access(priv);
-	if (rc) {
-		IWL_WARN(priv, "Can not read from adapter at this time.\n");
-		return;
-	}
 
 	count = iwl_read_targ_mem(priv, base);
 
@@ -1735,8 +1728,6 @@
 			ilink1, ilink2, data1);
 	}
 
-	iwl_release_nic_access(priv);
-
 }
 
 #define EVENT_START_OFFSET  (6 * sizeof(u32))
@@ -1744,7 +1735,6 @@
 /**
  * iwl3945_print_event_log - Dump error event log to syslog
  *
- * NOTE: Must be called with iwl_grab_nic_access() already obtained!
  */
 static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
 				u32 num_events, u32 mode)
@@ -1787,7 +1777,6 @@
 
 static void iwl3945_dump_nic_event_log(struct iwl_priv *priv)
 {
-	int rc;
 	u32 base;       /* SRAM byte address of event log header */
 	u32 capacity;   /* event log capacity in # entries */
 	u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
@@ -1801,12 +1790,6 @@
 		return;
 	}
 
-	rc = iwl_grab_nic_access(priv);
-	if (rc) {
-		IWL_WARN(priv, "Can not read from adapter at this time.\n");
-		return;
-	}
-
 	/* event log header */
 	capacity = iwl_read_targ_mem(priv, base);
 	mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
@@ -1818,7 +1801,6 @@
 	/* bail out if nothing in log */
 	if (size == 0) {
 		IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
-		iwl_release_nic_access(priv);
 		return;
 	}
 
@@ -1834,7 +1816,6 @@
 	/* (then/else) start at top of log */
 	iwl3945_print_event_log(priv, 0, next_entry, mode);
 
-	iwl_release_nic_access(priv);
 }
 
 static void iwl3945_irq_tasklet(struct iwl_priv *priv)
@@ -1953,11 +1934,8 @@
 		priv->isr_stats.tx++;
 
 		iwl_write32(priv, CSR_FH_INT_STATUS, (1 << 6));
-		if (!iwl_grab_nic_access(priv)) {
-			iwl_write_direct32(priv, FH39_TCSR_CREDIT
-					     (FH39_SRVC_CHNL), 0x0);
-			iwl_release_nic_access(priv);
-		}
+		iwl_write_direct32(priv, FH39_TCSR_CREDIT
+					(FH39_SRVC_CHNL), 0x0);
 		handled |= CSR_INT_BIT_FH_TX;
 	}
 
@@ -1966,9 +1944,9 @@
 		priv->isr_stats.unhandled++;
 	}
 
-	if (inta & ~CSR_INI_SET_MASK) {
+	if (inta & ~priv->inta_mask) {
 		IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n",
-			 inta & ~CSR_INI_SET_MASK);
+			 inta & ~priv->inta_mask);
 		IWL_WARN(priv, "   with FH_INT = 0x%08x\n", inta_fh);
 	}
 
@@ -2132,10 +2110,6 @@
 
 	IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
 
-	rc = iwl_grab_nic_access(priv);
-	if (rc)
-		return rc;
-
 	iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
 			       IWL39_RTC_INST_LOWER_BOUND);
 
@@ -2156,7 +2130,6 @@
 		}
 	}
 
-	iwl_release_nic_access(priv);
 
 	if (!errcnt)
 		IWL_DEBUG_INFO(priv,
@@ -2180,10 +2153,6 @@
 
 	IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
 
-	rc = iwl_grab_nic_access(priv);
-	if (rc)
-		return rc;
-
 	for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
 		/* read data comes through single port, auto-incr addr */
 		/* NOTE: Use the debugless read so we don't flood kernel log
@@ -2204,8 +2173,6 @@
 		}
 	}
 
-	iwl_release_nic_access(priv);
-
 	return rc;
 }
 
@@ -2529,20 +2496,11 @@
 {
 	dma_addr_t pinst;
 	dma_addr_t pdata;
-	int rc = 0;
-	unsigned long flags;
 
 	/* bits 31:0 for 3945 */
 	pinst = priv->ucode_code.p_addr;
 	pdata = priv->ucode_data_backup.p_addr;
 
-	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_nic_access(priv);
-	if (rc) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return rc;
-	}
-
 	/* Tell bootstrap uCode where to find image to load */
 	iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
 	iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
@@ -2554,13 +2512,9 @@
 	iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG,
 				 priv->ucode_code.len | BSM_DRAM_INST_LOAD);
 
-	iwl_release_nic_access(priv);
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-
 	IWL_DEBUG_INFO(priv, "Runtime uCode pointers are set.\n");
 
-	return rc;
+	return 0;
 }
 
 /**
@@ -2613,7 +2567,6 @@
  */
 static void iwl3945_alive_start(struct iwl_priv *priv)
 {
-	int rc = 0;
 	int thermal_spin = 0;
 	u32 rfkill;
 
@@ -2638,15 +2591,8 @@
 
 	priv->cfg->ops->smgmt->clear_station_table(priv);
 
-	rc = iwl_grab_nic_access(priv);
-	if (rc) {
-		IWL_WARN(priv, "Can not read RFKILL status from adapter\n");
-		return;
-	}
-
 	rfkill = iwl_read_prph(priv, APMG_RFKILL_REG);
 	IWL_DEBUG_INFO(priv, "RFKILL status: 0x%x\n", rfkill);
-	iwl_release_nic_access(priv);
 
 	if (rfkill & 0x1) {
 		clear_bit(STATUS_RF_KILL_HW, &priv->status);
@@ -2792,13 +2738,8 @@
 	iwl3945_hw_txq_ctx_stop(priv);
 	iwl3945_hw_rxq_stop(priv);
 
-	spin_lock_irqsave(&priv->lock, flags);
-	if (!iwl_grab_nic_access(priv)) {
-		iwl_write_prph(priv, APMG_CLK_DIS_REG,
-					 APMG_CLK_VAL_DMA_CLK_RQT);
-		iwl_release_nic_access(priv);
-	}
-	spin_unlock_irqrestore(&priv->lock, flags);
+	iwl_write_prph(priv, APMG_CLK_DIS_REG,
+				APMG_CLK_VAL_DMA_CLK_RQT);
 
 	udelay(5);
 
@@ -2996,6 +2937,8 @@
 
 	mutex_lock(&priv->mutex);
 
+	cancel_delayed_work(&priv->scan_check);
+
 	if (!iwl_is_ready(priv)) {
 		IWL_WARN(priv, "request scan called when driver not ready.\n");
 		goto done;
@@ -4243,6 +4186,7 @@
 	IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n");
 	priv->cfg = cfg;
 	priv->pci_dev = pdev;
+	priv->inta_mask = CSR_INI_SET_MASK;
 
 #ifdef CONFIG_IWLWIFI_DEBUG
 	priv->debug_level = iwl3945_mod_params.debug;
@@ -4289,6 +4233,11 @@
 	 * PCI Tx retries from interfering with C3 CPU state */
 	pci_write_config_byte(pdev, 0x41, 0x00);
 
+	/* this spin lock will be used in apm_ops.init and EEPROM access
+	 * we should init now
+	 */
+	spin_lock_init(&priv->reg_lock);
+
 	/* amp init */
 	err = priv->cfg->ops->lib->apm_ops.init(priv);
 	if (err < 0) {
@@ -4344,8 +4293,8 @@
 
 	pci_enable_msi(priv->pci_dev);
 
-	err = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED,
-			  DRV_NAME, priv);
+	err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr,
+			  IRQF_SHARED, DRV_NAME, priv);
 	if (err) {
 		IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq);
 		goto out_disable_msi;
diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig
new file mode 100644
index 0000000..41bd4b2
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/Kconfig
@@ -0,0 +1,24 @@
+config IWM
+	tristate "Intel Wireless Multicomm 3200 WiFi driver"
+	depends on MMC && WLAN_80211 && EXPERIMENTAL
+	select WIRELESS_EXT
+	select CFG80211
+	select FW_LOADER
+	select RFKILL
+
+config IWM_DEBUG
+	bool "Enable full debugging output in iwmc3200wifi"
+	depends on IWM && DEBUG_FS
+	---help---
+	  This option will enable debug tracing and setting for iwm
+
+	  You can set the debug level and module through debugfs. By
+	  default all modules are set to the IWL_DL_ERR level.
+	  To see the list of debug modules and levels, see iwm/debug.h
+
+	  For example, if you want the full MLME debug output:
+	  echo 0xff > /debug/iwm/phyN/debug/mlme
+
+	  Or, if you want the full debug, for all modules:
+	  echo 0xff > /debug/iwm/phyN/debug/level
+	  echo 0xff > /debug/iwm/phyN/debug/modules
diff --git a/drivers/net/wireless/iwmc3200wifi/Makefile b/drivers/net/wireless/iwmc3200wifi/Makefile
new file mode 100644
index 0000000..7cb415e
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_IWM) := iwmc3200wifi.o
+iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o
+iwmc3200wifi-objs += commands.o wext.o cfg80211.o eeprom.o rfkill.o
+
+iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o
diff --git a/drivers/net/wireless/iwmc3200wifi/bus.h b/drivers/net/wireless/iwmc3200wifi/bus.h
new file mode 100644
index 0000000..836663e
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/bus.h
@@ -0,0 +1,57 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifndef __IWM_BUS_H__
+#define __IWM_BUS_H__
+
+#include "iwm.h"
+
+struct iwm_if_ops {
+	int (*enable)(struct iwm_priv *iwm);
+	int (*disable)(struct iwm_priv *iwm);
+	int (*send_chunk)(struct iwm_priv *iwm, u8* buf, int count);
+
+	int (*debugfs_init)(struct iwm_priv *iwm, struct dentry *parent_dir);
+	void (*debugfs_exit)(struct iwm_priv *iwm);
+
+	const char *umac_name;
+	const char *calib_lmac_name;
+	const char *lmac_name;
+};
+
+static inline int iwm_bus_send_chunk(struct iwm_priv *iwm, u8 *buf, int count)
+{
+	return iwm->bus_ops->send_chunk(iwm, buf, count);
+}
+
+static inline int iwm_bus_enable(struct iwm_priv *iwm)
+{
+	return iwm->bus_ops->enable(iwm);
+}
+
+static inline int iwm_bus_disable(struct iwm_priv *iwm)
+{
+	return iwm->bus_ops->disable(iwm);
+}
+
+#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
new file mode 100644
index 0000000..3256ad2
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -0,0 +1,409 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
+
+#include "iwm.h"
+#include "commands.h"
+#include "cfg80211.h"
+#include "debug.h"
+
+#define RATETAB_ENT(_rate, _rateid, _flags) \
+	{								\
+		.bitrate	= (_rate),				\
+		.hw_value	= (_rateid),				\
+		.flags		= (_flags),				\
+	}
+
+#define CHAN2G(_channel, _freq, _flags) {			\
+	.band			= IEEE80211_BAND_2GHZ,		\
+	.center_freq		= (_freq),			\
+	.hw_value		= (_channel),			\
+	.flags			= (_flags),			\
+	.max_antenna_gain	= 0,				\
+	.max_power		= 30,				\
+}
+
+#define CHAN5G(_channel, _flags) {				\
+	.band			= IEEE80211_BAND_5GHZ,		\
+	.center_freq		= 5000 + (5 * (_channel)),	\
+	.hw_value		= (_channel),			\
+	.flags			= (_flags),			\
+	.max_antenna_gain	= 0,				\
+	.max_power		= 30,				\
+}
+
+static struct ieee80211_rate iwm_rates[] = {
+	RATETAB_ENT(10,  0x1,   0),
+	RATETAB_ENT(20,  0x2,   0),
+	RATETAB_ENT(55,  0x4,   0),
+	RATETAB_ENT(110, 0x8,   0),
+	RATETAB_ENT(60,  0x10,  0),
+	RATETAB_ENT(90,  0x20,  0),
+	RATETAB_ENT(120, 0x40,  0),
+	RATETAB_ENT(180, 0x80,  0),
+	RATETAB_ENT(240, 0x100, 0),
+	RATETAB_ENT(360, 0x200, 0),
+	RATETAB_ENT(480, 0x400, 0),
+	RATETAB_ENT(540, 0x800, 0),
+};
+
+#define iwm_a_rates		(iwm_rates + 4)
+#define iwm_a_rates_size	8
+#define iwm_g_rates		(iwm_rates + 0)
+#define iwm_g_rates_size	12
+
+static struct ieee80211_channel iwm_2ghz_channels[] = {
+	CHAN2G(1, 2412, 0),
+	CHAN2G(2, 2417, 0),
+	CHAN2G(3, 2422, 0),
+	CHAN2G(4, 2427, 0),
+	CHAN2G(5, 2432, 0),
+	CHAN2G(6, 2437, 0),
+	CHAN2G(7, 2442, 0),
+	CHAN2G(8, 2447, 0),
+	CHAN2G(9, 2452, 0),
+	CHAN2G(10, 2457, 0),
+	CHAN2G(11, 2462, 0),
+	CHAN2G(12, 2467, 0),
+	CHAN2G(13, 2472, 0),
+	CHAN2G(14, 2484, 0),
+};
+
+static struct ieee80211_channel iwm_5ghz_a_channels[] = {
+	CHAN5G(34, 0),		CHAN5G(36, 0),
+	CHAN5G(38, 0),		CHAN5G(40, 0),
+	CHAN5G(42, 0),		CHAN5G(44, 0),
+	CHAN5G(46, 0),		CHAN5G(48, 0),
+	CHAN5G(52, 0),		CHAN5G(56, 0),
+	CHAN5G(60, 0),		CHAN5G(64, 0),
+	CHAN5G(100, 0),		CHAN5G(104, 0),
+	CHAN5G(108, 0),		CHAN5G(112, 0),
+	CHAN5G(116, 0),		CHAN5G(120, 0),
+	CHAN5G(124, 0),		CHAN5G(128, 0),
+	CHAN5G(132, 0),		CHAN5G(136, 0),
+	CHAN5G(140, 0),		CHAN5G(149, 0),
+	CHAN5G(153, 0),		CHAN5G(157, 0),
+	CHAN5G(161, 0),		CHAN5G(165, 0),
+	CHAN5G(184, 0),		CHAN5G(188, 0),
+	CHAN5G(192, 0),		CHAN5G(196, 0),
+	CHAN5G(200, 0),		CHAN5G(204, 0),
+	CHAN5G(208, 0),		CHAN5G(212, 0),
+	CHAN5G(216, 0),
+};
+
+static struct ieee80211_supported_band iwm_band_2ghz = {
+	.channels = iwm_2ghz_channels,
+	.n_channels = ARRAY_SIZE(iwm_2ghz_channels),
+	.bitrates = iwm_g_rates,
+	.n_bitrates = iwm_g_rates_size,
+};
+
+static struct ieee80211_supported_band iwm_band_5ghz = {
+	.channels = iwm_5ghz_a_channels,
+	.n_channels = ARRAY_SIZE(iwm_5ghz_a_channels),
+	.bitrates = iwm_a_rates,
+	.n_bitrates = iwm_a_rates_size,
+};
+
+int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
+{
+	struct wiphy *wiphy = iwm_to_wiphy(iwm);
+	struct iwm_bss_info *bss, *next;
+	struct iwm_umac_notif_bss_info *umac_bss;
+	struct ieee80211_mgmt *mgmt;
+	struct ieee80211_channel *channel;
+	struct ieee80211_supported_band *band;
+	s32 signal;
+	int freq;
+
+	list_for_each_entry_safe(bss, next, &iwm->bss_list, node) {
+		umac_bss = bss->bss;
+		mgmt = (struct ieee80211_mgmt *)(umac_bss->frame_buf);
+
+		if (umac_bss->band == UMAC_BAND_2GHZ)
+			band = wiphy->bands[IEEE80211_BAND_2GHZ];
+		else if (umac_bss->band == UMAC_BAND_5GHZ)
+			band = wiphy->bands[IEEE80211_BAND_5GHZ];
+		else {
+			IWM_ERR(iwm, "Invalid band: %d\n", umac_bss->band);
+			return -EINVAL;
+		}
+
+		freq = ieee80211_channel_to_frequency(umac_bss->channel);
+		channel = ieee80211_get_channel(wiphy, freq);
+		signal = umac_bss->rssi * 100;
+
+		if (!cfg80211_inform_bss_frame(wiphy, channel, mgmt,
+					       le16_to_cpu(umac_bss->frame_len),
+					       signal, GFP_KERNEL))
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int iwm_cfg80211_change_iface(struct wiphy *wiphy, int ifindex,
+				     enum nl80211_iftype type, u32 *flags,
+				     struct vif_params *params)
+{
+	struct net_device *ndev;
+	struct wireless_dev *wdev;
+	struct iwm_priv *iwm;
+	u32 old_mode;
+
+	/* we're under RTNL */
+	ndev = __dev_get_by_index(&init_net, ifindex);
+	if (!ndev)
+		return -ENODEV;
+
+	wdev = ndev->ieee80211_ptr;
+	iwm = ndev_to_iwm(ndev);
+	old_mode = iwm->conf.mode;
+
+	switch (type) {
+	case NL80211_IFTYPE_STATION:
+		iwm->conf.mode = UMAC_MODE_BSS;
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		iwm->conf.mode = UMAC_MODE_IBSS;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	wdev->iftype = type;
+
+	if ((old_mode == iwm->conf.mode) || !iwm->umac_profile)
+		return 0;
+
+	iwm->umac_profile->mode = cpu_to_le32(iwm->conf.mode);
+
+	if (iwm->umac_profile_active) {
+		int ret = iwm_invalidate_mlme_profile(iwm);
+		if (ret < 0)
+			IWM_ERR(iwm, "Couldn't invalidate profile\n");
+	}
+
+	return 0;
+}
+
+static int iwm_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
+			     struct cfg80211_scan_request *request)
+{
+	struct iwm_priv *iwm = ndev_to_iwm(ndev);
+	int ret;
+
+	if (!test_bit(IWM_STATUS_READY, &iwm->status)) {
+		IWM_ERR(iwm, "Scan while device is not ready\n");
+		return -EIO;
+	}
+
+	if (test_bit(IWM_STATUS_SCANNING, &iwm->status)) {
+		IWM_ERR(iwm, "Scanning already\n");
+		return -EAGAIN;
+	}
+
+	if (test_bit(IWM_STATUS_SCAN_ABORTING, &iwm->status)) {
+		IWM_ERR(iwm, "Scanning being aborted\n");
+		return -EAGAIN;
+	}
+
+	set_bit(IWM_STATUS_SCANNING, &iwm->status);
+
+	ret = iwm_scan_ssids(iwm, request->ssids, request->n_ssids);
+	if (ret) {
+		clear_bit(IWM_STATUS_SCANNING, &iwm->status);
+		return ret;
+	}
+
+	iwm->scan_request = request;
+	return 0;
+}
+
+static int iwm_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+	struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+
+	if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
+	    (iwm->conf.rts_threshold != wiphy->rts_threshold)) {
+		int ret;
+
+		iwm->conf.rts_threshold = wiphy->rts_threshold;
+
+		ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+					     CFG_RTS_THRESHOLD,
+					     iwm->conf.rts_threshold);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
+	    (iwm->conf.frag_threshold != wiphy->frag_threshold)) {
+		int ret;
+
+		iwm->conf.frag_threshold = wiphy->frag_threshold;
+
+		ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+					     CFG_FRAG_THRESHOLD,
+					     iwm->conf.frag_threshold);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int iwm_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+				  struct cfg80211_ibss_params *params)
+{
+	struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+	struct ieee80211_channel *chan = params->channel;
+	struct cfg80211_bss *bss;
+
+	if (!test_bit(IWM_STATUS_READY, &iwm->status))
+		return -EIO;
+
+	/* UMAC doesn't support creating IBSS network with specified bssid.
+	 * This should be removed after we have join only mode supported. */
+	if (params->bssid)
+		return -EOPNOTSUPP;
+
+	bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL,
+				params->ssid, params->ssid_len);
+	if (!bss) {
+		iwm_scan_one_ssid(iwm, params->ssid, params->ssid_len);
+		schedule_timeout_interruptible(2 * HZ);
+		bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL,
+					params->ssid, params->ssid_len);
+	}
+	/* IBSS join only mode is not supported by UMAC ATM */
+	if (bss) {
+		cfg80211_put_bss(bss);
+		return -EOPNOTSUPP;
+	}
+
+	iwm->channel = ieee80211_frequency_to_channel(chan->center_freq);
+	iwm->umac_profile->ibss.band = chan->band;
+	iwm->umac_profile->ibss.channel = iwm->channel;
+	iwm->umac_profile->ssid.ssid_len = params->ssid_len;
+	memcpy(iwm->umac_profile->ssid.ssid, params->ssid, params->ssid_len);
+
+	if (params->bssid)
+		memcpy(&iwm->umac_profile->bssid[0], params->bssid, ETH_ALEN);
+
+	return iwm_send_mlme_profile(iwm);
+}
+
+static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
+{
+	struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+
+	if (iwm->umac_profile_active)
+		return iwm_invalidate_mlme_profile(iwm);
+
+	return 0;
+}
+
+static struct cfg80211_ops iwm_cfg80211_ops = {
+	.change_virtual_intf = iwm_cfg80211_change_iface,
+	.scan = iwm_cfg80211_scan,
+	.set_wiphy_params = iwm_cfg80211_set_wiphy_params,
+	.join_ibss = iwm_cfg80211_join_ibss,
+	.leave_ibss = iwm_cfg80211_leave_ibss,
+};
+
+struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
+{
+	int ret = 0;
+	struct wireless_dev *wdev;
+
+	/*
+	 * We're trying to have the following memory
+	 * layout:
+	 *
+	 * +-------------------------+
+	 * | struct wiphy	     |
+	 * +-------------------------+
+	 * | struct iwm_priv         |
+	 * +-------------------------+
+	 * | bus private data        |
+	 * | (e.g. iwm_priv_sdio)    |
+	 * +-------------------------+
+	 *
+	 */
+
+	wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+	if (!wdev) {
+		dev_err(dev, "Couldn't allocate wireless device\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	wdev->wiphy = wiphy_new(&iwm_cfg80211_ops,
+				sizeof(struct iwm_priv) + sizeof_bus);
+	if (!wdev->wiphy) {
+		dev_err(dev, "Couldn't allocate wiphy device\n");
+		ret = -ENOMEM;
+		goto out_err_new;
+	}
+
+	set_wiphy_dev(wdev->wiphy, dev);
+	wdev->wiphy->max_scan_ssids = UMAC_WIFI_IF_PROBE_OPTION_MAX;
+	wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+				       BIT(NL80211_IFTYPE_ADHOC);
+	wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &iwm_band_2ghz;
+	wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz;
+	wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+	ret = wiphy_register(wdev->wiphy);
+	if (ret < 0) {
+		dev_err(dev, "Couldn't register wiphy device\n");
+		goto out_err_register;
+	}
+
+	return wdev;
+
+ out_err_register:
+	wiphy_free(wdev->wiphy);
+
+ out_err_new:
+	kfree(wdev);
+
+	return ERR_PTR(ret);
+}
+
+void iwm_wdev_free(struct iwm_priv *iwm)
+{
+	struct wireless_dev *wdev = iwm_to_wdev(iwm);
+
+	if (!wdev)
+		return;
+
+	wiphy_unregister(wdev->wiphy);
+	wiphy_free(wdev->wiphy);
+	kfree(wdev);
+}
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.h b/drivers/net/wireless/iwmc3200wifi/cfg80211.h
new file mode 100644
index 0000000..56a3414
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.h
@@ -0,0 +1,31 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifndef __IWM_CFG80211_H__
+#define __IWM_CFG80211_H__
+
+int iwm_cfg80211_inform_bss(struct iwm_priv *iwm);
+struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev);
+void iwm_wdev_free(struct iwm_priv *iwm);
+
+#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c
new file mode 100644
index 0000000..834a7f5
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/commands.c
@@ -0,0 +1,920 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ *
+ * Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/wireless.h>
+#include <linux/etherdevice.h>
+#include <linux/ieee80211.h>
+
+#include "iwm.h"
+#include "bus.h"
+#include "hal.h"
+#include "umac.h"
+#include "commands.h"
+#include "debug.h"
+
+static int iwm_send_lmac_ptrough_cmd(struct iwm_priv *iwm,
+				     u8 lmac_cmd_id,
+				     const void *lmac_payload,
+				     u16 lmac_payload_size,
+				     u8 resp)
+{
+	struct iwm_udma_wifi_cmd udma_cmd = UDMA_LMAC_INIT;
+	struct iwm_umac_cmd umac_cmd;
+	struct iwm_lmac_cmd lmac_cmd;
+
+	lmac_cmd.id = lmac_cmd_id;
+
+	umac_cmd.id = UMAC_CMD_OPCODE_WIFI_PASS_THROUGH;
+	umac_cmd.resp = resp;
+
+	return iwm_hal_send_host_cmd(iwm, &udma_cmd, &umac_cmd, &lmac_cmd,
+				     lmac_payload, lmac_payload_size);
+}
+
+int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
+			 bool resp)
+{
+	struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
+	struct iwm_umac_cmd umac_cmd;
+
+	umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER;
+	umac_cmd.resp = resp;
+
+	return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd,
+				     payload, payload_size);
+}
+
+static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] =
+{
+	{4, 3, 0, COEX_UNASSOC_IDLE_FLAGS},
+	{4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS},
+	{4, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS},
+	{4, 3, 0, COEX_CALIBRATION_FLAGS},
+	{4, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS},
+	{4, 3, 0, COEX_CONNECTION_ESTAB_FLAGS},
+	{4, 3, 0, COEX_ASSOCIATED_IDLE_FLAGS},
+	{4, 3, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS},
+	{4, 3, 0, COEX_ASSOC_AUTO_SCAN_FLAGS},
+	{4, 3, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS},
+	{6, 3, 0, COEX_XOR_RF_ON_FLAGS},
+	{4, 3, 0, COEX_RF_OFF_FLAGS},
+	{6, 6, 0, COEX_STAND_ALONE_DEBUG_FLAGS},
+	{4, 3, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS},
+	{4, 3, 0, COEX_RSRVD1_FLAGS},
+	{4, 3, 0, COEX_RSRVD2_FLAGS}
+};
+
+static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] =
+{
+	{1, 1, 0, COEX_UNASSOC_IDLE_FLAGS},
+	{4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS},
+	{3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS},
+	{5, 5, 0, COEX_CALIBRATION_FLAGS},
+	{4, 4, 0, COEX_PERIODIC_CALIBRATION_FLAGS},
+	{5, 4, 0, COEX_CONNECTION_ESTAB_FLAGS},
+	{4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS},
+	{4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS},
+	{4, 4, 0, COEX_ASSOC_AUTO_SCAN_FLAGS},
+	{4, 4, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS},
+	{1, 1, 0, COEX_RF_ON_FLAGS},
+	{1, 1, 0, COEX_RF_OFF_FLAGS},
+	{6, 6, 0, COEX_STAND_ALONE_DEBUG_FLAGS},
+	{5, 4, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS},
+	{1, 1, 0, COEX_RSRVD1_FLAGS},
+	{1, 1, 0, COEX_RSRVD2_FLAGS}
+};
+
+int iwm_send_prio_table(struct iwm_priv *iwm)
+{
+	struct iwm_coex_prio_table_cmd coex_table_cmd;
+	u32 coex_enabled, mode_enabled;
+
+	memset(&coex_table_cmd, 0, sizeof(struct iwm_coex_prio_table_cmd));
+
+	coex_table_cmd.flags = COEX_FLAGS_STA_TABLE_VALID_MSK;
+
+	switch (iwm->conf.coexist_mode) {
+	case COEX_MODE_XOR:
+	case COEX_MODE_CM:
+		coex_enabled = 1;
+		break;
+	default:
+		coex_enabled = 0;
+		break;
+	}
+
+	switch (iwm->conf.mode) {
+	case UMAC_MODE_BSS:
+	case UMAC_MODE_IBSS:
+		mode_enabled = 1;
+		break;
+	default:
+		mode_enabled = 0;
+		break;
+	}
+
+	if (coex_enabled && mode_enabled) {
+		coex_table_cmd.flags |= COEX_FLAGS_COEX_ENABLE_MSK |
+					COEX_FLAGS_ASSOC_WAKEUP_UMASK_MSK |
+					COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK;
+
+		switch (iwm->conf.coexist_mode) {
+		case COEX_MODE_XOR:
+			memcpy(coex_table_cmd.sta_prio, iwm_sta_xor_prio_tbl,
+			       sizeof(iwm_sta_xor_prio_tbl));
+			break;
+		case COEX_MODE_CM:
+			memcpy(coex_table_cmd.sta_prio, iwm_sta_cm_prio_tbl,
+			       sizeof(iwm_sta_cm_prio_tbl));
+			break;
+		default:
+			IWM_ERR(iwm, "Invalid coex_mode 0x%x\n",
+				iwm->conf.coexist_mode);
+			break;
+		}
+	} else
+		IWM_WARN(iwm, "coexistense disabled\n");
+
+	return iwm_send_lmac_ptrough_cmd(iwm, COEX_PRIORITY_TABLE_CMD,
+				&coex_table_cmd,
+				sizeof(struct iwm_coex_prio_table_cmd), 1);
+}
+
+int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested)
+{
+	struct iwm_lmac_cal_cfg_cmd cal_cfg_cmd;
+
+	memset(&cal_cfg_cmd, 0, sizeof(struct iwm_lmac_cal_cfg_cmd));
+
+	cal_cfg_cmd.ucode_cfg.init.enable = cpu_to_le32(calib_requested);
+	cal_cfg_cmd.ucode_cfg.init.start = cpu_to_le32(calib_requested);
+	cal_cfg_cmd.ucode_cfg.init.send_res = cpu_to_le32(calib_requested);
+	cal_cfg_cmd.ucode_cfg.flags =
+		cpu_to_le32(CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK);
+
+	return iwm_send_lmac_ptrough_cmd(iwm, CALIBRATION_CFG_CMD, &cal_cfg_cmd,
+				sizeof(struct iwm_lmac_cal_cfg_cmd), 1);
+}
+
+int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested)
+{
+	struct iwm_lmac_cal_cfg_cmd cal_cfg_cmd;
+
+	memset(&cal_cfg_cmd, 0, sizeof(struct iwm_lmac_cal_cfg_cmd));
+
+	cal_cfg_cmd.ucode_cfg.periodic.enable = cpu_to_le32(calib_requested);
+	cal_cfg_cmd.ucode_cfg.periodic.start = cpu_to_le32(calib_requested);
+
+	return iwm_send_lmac_ptrough_cmd(iwm, CALIBRATION_CFG_CMD, &cal_cfg_cmd,
+				sizeof(struct iwm_lmac_cal_cfg_cmd), 0);
+}
+
+int iwm_store_rxiq_calib_result(struct iwm_priv *iwm)
+{
+	struct iwm_calib_rxiq *rxiq;
+	u8 *eeprom_rxiq = iwm_eeprom_access(iwm, IWM_EEPROM_CALIB_RXIQ);
+	int grplen = sizeof(struct iwm_calib_rxiq_group);
+
+	rxiq = kzalloc(sizeof(struct iwm_calib_rxiq), GFP_KERNEL);
+	if (!rxiq) {
+		IWM_ERR(iwm, "Couldn't alloc memory for RX IQ\n");
+		return -ENOMEM;
+	}
+
+	eeprom_rxiq = iwm_eeprom_access(iwm, IWM_EEPROM_CALIB_RXIQ);
+	if (IS_ERR(eeprom_rxiq)) {
+		IWM_ERR(iwm, "Couldn't access EEPROM RX IQ entry\n");
+		return PTR_ERR(eeprom_rxiq);
+	}
+
+	iwm->calib_res[SHILOH_PHY_CALIBRATE_RX_IQ_CMD].buf = (u8 *)rxiq;
+	iwm->calib_res[SHILOH_PHY_CALIBRATE_RX_IQ_CMD].size = sizeof(*rxiq);
+
+	rxiq->hdr.opcode = SHILOH_PHY_CALIBRATE_RX_IQ_CMD;
+	rxiq->hdr.first_grp = 0;
+	rxiq->hdr.grp_num = 1;
+	rxiq->hdr.all_data_valid = 1;
+
+	memcpy(&rxiq->group[0], eeprom_rxiq, 4 * grplen);
+	memcpy(&rxiq->group[4], eeprom_rxiq + 6 * grplen, grplen);
+
+	return 0;
+}
+
+int iwm_send_calib_results(struct iwm_priv *iwm)
+{
+	int i, ret = 0;
+
+	for (i = PHY_CALIBRATE_OPCODES_NUM; i < CALIBRATION_CMD_NUM; i++) {
+		if (test_bit(i - PHY_CALIBRATE_OPCODES_NUM,
+			     &iwm->calib_done_map)) {
+			IWM_DBG_CMD(iwm, DBG,
+				    "Send calibration %d result\n", i);
+			ret |= iwm_send_lmac_ptrough_cmd(iwm,
+					REPLY_PHY_CALIBRATION_CMD,
+					iwm->calib_res[i].buf,
+					iwm->calib_res[i].size, 0);
+
+			kfree(iwm->calib_res[i].buf);
+			iwm->calib_res[i].buf = NULL;
+			iwm->calib_res[i].size = 0;
+		}
+	}
+
+	return ret;
+}
+
+int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp)
+{
+	struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
+	struct iwm_umac_cmd umac_cmd;
+	struct iwm_umac_cmd_reset reset;
+
+	reset.flags = reset_flags;
+
+	umac_cmd.id = UMAC_CMD_OPCODE_RESET;
+	umac_cmd.resp = resp;
+
+	return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &reset,
+				     sizeof(struct iwm_umac_cmd_reset));
+}
+
+int iwm_umac_set_config_fix(struct iwm_priv *iwm, u16 tbl, u16 key, u32 value)
+{
+	struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
+	struct iwm_umac_cmd umac_cmd;
+	struct iwm_umac_cmd_set_param_fix param;
+
+	if ((tbl != UMAC_PARAM_TBL_CFG_FIX) &&
+	    (tbl != UMAC_PARAM_TBL_FA_CFG_FIX))
+		return -EINVAL;
+
+	umac_cmd.id = UMAC_CMD_OPCODE_SET_PARAM_FIX;
+	umac_cmd.resp = 0;
+
+	param.tbl = cpu_to_le16(tbl);
+	param.key = cpu_to_le16(key);
+	param.value = cpu_to_le32(value);
+
+	return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &param,
+				     sizeof(struct iwm_umac_cmd_set_param_fix));
+}
+
+int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key,
+			    void *payload, u16 payload_size)
+{
+	struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
+	struct iwm_umac_cmd umac_cmd;
+	struct iwm_umac_cmd_set_param_var *param_hdr;
+	u8 *param;
+	int ret;
+
+	param = kzalloc(payload_size +
+			sizeof(struct iwm_umac_cmd_set_param_var), GFP_KERNEL);
+	if (!param) {
+		IWM_ERR(iwm, "Couldn't allocate param\n");
+		return -ENOMEM;
+	}
+
+	param_hdr = (struct iwm_umac_cmd_set_param_var *)param;
+
+	umac_cmd.id = UMAC_CMD_OPCODE_SET_PARAM_VAR;
+	umac_cmd.resp = 0;
+
+	param_hdr->tbl = cpu_to_le16(UMAC_PARAM_TBL_CFG_VAR);
+	param_hdr->key = cpu_to_le16(key);
+	param_hdr->len = cpu_to_le16(payload_size);
+	memcpy(param + sizeof(struct iwm_umac_cmd_set_param_var),
+	       payload, payload_size);
+
+	ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, param,
+				    sizeof(struct iwm_umac_cmd_set_param_var) +
+				    payload_size);
+	kfree(param);
+
+	return ret;
+}
+
+int iwm_send_umac_config(struct iwm_priv *iwm,
+			 __le32 reset_flags)
+{
+	int ret;
+
+	/* Use UMAC default values */
+	ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+				      CFG_POWER_INDEX, iwm->conf.power_index);
+	if (ret < 0)
+		return ret;
+
+	ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX,
+				      CFG_FRAG_THRESHOLD,
+				      iwm->conf.frag_threshold);
+	if (ret < 0)
+		return ret;
+
+	ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+				      CFG_RTS_THRESHOLD,
+				      iwm->conf.rts_threshold);
+	if (ret < 0)
+		return ret;
+
+	ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+				      CFG_CTS_TO_SELF, iwm->conf.cts_to_self);
+	if (ret < 0)
+		return ret;
+
+	ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+				      CFG_COEX_MODE, iwm->conf.coexist_mode);
+	if (ret < 0)
+		return ret;
+
+	/*
+	ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+				      CFG_ASSOCIATION_TIMEOUT,
+				      iwm->conf.assoc_timeout);
+	if (ret < 0)
+		return ret;
+
+	ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+				      CFG_ROAM_TIMEOUT,
+				      iwm->conf.roam_timeout);
+	if (ret < 0)
+		return ret;
+
+	ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+				      CFG_WIRELESS_MODE,
+				      WIRELESS_MODE_11A | WIRELESS_MODE_11G);
+	if (ret < 0)
+		return ret;
+	*/
+
+	ret = iwm_umac_set_config_var(iwm, CFG_NET_ADDR,
+				      iwm_to_ndev(iwm)->dev_addr, ETH_ALEN);
+	if (ret < 0)
+		return ret;
+
+	/* UMAC PM static configurations */
+	ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+				      CFG_PM_LEGACY_RX_TIMEOUT, 0x12C);
+	if (ret < 0)
+		return ret;
+
+	ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+				      CFG_PM_LEGACY_TX_TIMEOUT, 0x15E);
+	if (ret < 0)
+		return ret;
+
+	ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+				      CFG_PM_CTRL_FLAGS, 0x30001);
+	if (ret < 0)
+		return ret;
+
+	ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+				      CFG_PM_KEEP_ALIVE_IN_BEACONS, 0x80);
+	if (ret < 0)
+		return ret;
+
+	/* reset UMAC */
+	ret = iwm_send_umac_reset(iwm, reset_flags, 1);
+	if (ret < 0)
+		return ret;
+
+	ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_RESET, IWM_SRC_UMAC,
+			       WAIT_NOTIF_TIMEOUT);
+	if (ret) {
+		IWM_ERR(iwm, "Wait for UMAC RESET timeout\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id)
+{
+	struct iwm_udma_wifi_cmd udma_cmd;
+	struct iwm_umac_cmd umac_cmd;
+	struct iwm_tx_info *tx_info = skb_to_tx_info(skb);
+
+	udma_cmd.eop = 1; /* always set eop for non-concatenated Tx */
+	udma_cmd.credit_group = pool_id;
+	udma_cmd.ra_tid = tx_info->sta << 4 | tx_info->tid;
+	udma_cmd.lmac_offset = 0;
+
+	umac_cmd.id = REPLY_TX;
+	umac_cmd.color = tx_info->color;
+	umac_cmd.resp = 0;
+
+	return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd,
+				     skb->data, skb->len);
+}
+
+static int iwm_target_read(struct iwm_priv *iwm, __le32 address,
+			   u8 *response, u32 resp_size)
+{
+	struct iwm_udma_nonwifi_cmd target_cmd;
+	struct iwm_nonwifi_cmd *cmd;
+	u16 seq_num;
+	int ret = 0;
+
+	target_cmd.opcode = UMAC_HDI_OUT_OPCODE_READ;
+	target_cmd.addr = address;
+	target_cmd.op1_sz = cpu_to_le32(resp_size);
+	target_cmd.op2 = 0;
+	target_cmd.handle_by_hw = 0;
+	target_cmd.resp = 1;
+	target_cmd.eop = 1;
+
+	ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL);
+	if (ret < 0)
+		IWM_ERR(iwm, "Couldn't send READ command\n");
+
+	/* When succeding, the send_target routine returns the seq number */
+	seq_num = ret;
+
+	ret = wait_event_interruptible_timeout(iwm->nonwifi_queue,
+		(cmd = iwm_get_pending_nonwifi_cmd(iwm, seq_num,
+					  UMAC_HDI_OUT_OPCODE_READ)) != NULL,
+					       2 * HZ);
+
+	if (!ret) {
+		IWM_ERR(iwm, "Didn't receive a target READ answer\n");
+		return ret;
+	}
+
+	memcpy(response, cmd->buf.hdr + sizeof(struct iwm_udma_in_hdr),
+	       resp_size);
+
+	kfree(cmd);
+
+	return ret;
+}
+
+int iwm_read_mac(struct iwm_priv *iwm, u8 *mac)
+{
+	int ret;
+	u8 mac_align[ALIGN(ETH_ALEN, 8)];
+
+	ret = iwm_target_read(iwm, cpu_to_le32(WICO_MAC_ADDRESS_ADDR),
+			      mac_align, sizeof(mac_align));
+	if (ret < 0)
+		return ret;
+
+	if (is_valid_ether_addr(mac_align))
+		memcpy(mac, mac_align, ETH_ALEN);
+	else {
+		IWM_ERR(iwm, "Invalid EEPROM MAC\n");
+		memcpy(mac, iwm->conf.mac_addr, ETH_ALEN);
+		get_random_bytes(&mac[3], 3);
+	}
+
+	return 0;
+}
+
+int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx)
+{
+	struct iwm_umac_tx_key_id tx_key_id;
+
+	if (!iwm->default_key || !iwm->default_key->in_use)
+		return -EINVAL;
+
+	tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID;
+	tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) -
+					     sizeof(struct iwm_umac_wifi_if));
+
+	tx_key_id.key_idx = key_idx;
+
+	return iwm_send_wifi_if_cmd(iwm, &tx_key_id, sizeof(tx_key_id), 1);
+}
+
+static int iwm_check_profile(struct iwm_priv *iwm)
+{
+	if (!iwm->umac_profile_active)
+		return -EAGAIN;
+
+	if (iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_40 &&
+	    iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_104 &&
+	    iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_TKIP &&
+	    iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_CCMP) {
+		IWM_ERR(iwm, "Wrong unicast cipher: 0x%x\n",
+			iwm->umac_profile->sec.ucast_cipher);
+		return -EAGAIN;
+	}
+
+	if (iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_WEP_40 &&
+	    iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_WEP_104 &&
+	    iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_TKIP &&
+	    iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_CCMP) {
+		IWM_ERR(iwm, "Wrong multicast cipher: 0x%x\n",
+			iwm->umac_profile->sec.mcast_cipher);
+		return -EAGAIN;
+	}
+
+	if ((iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_40 ||
+	     iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_104) &&
+	    (iwm->umac_profile->sec.ucast_cipher !=
+	     iwm->umac_profile->sec.mcast_cipher)) {
+		IWM_ERR(iwm, "Unicast and multicast ciphers differ for WEP\n");
+	}
+
+	return 0;
+}
+
+int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
+		struct iwm_key *key)
+{
+	int ret;
+	u8 cmd[64], *sta_addr, *key_data, key_len;
+	s8 key_idx;
+	u16 cmd_size = 0;
+	struct iwm_umac_key_hdr *key_hdr = &key->hdr;
+	struct iwm_umac_key_wep40 *wep40 = (struct iwm_umac_key_wep40 *)cmd;
+	struct iwm_umac_key_wep104 *wep104 = (struct iwm_umac_key_wep104 *)cmd;
+	struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd;
+	struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd;
+
+	if (set_tx_key)
+		iwm->default_key = key;
+
+	/*
+	 * We check if our current profile is valid.
+	 * If not, we dont push the key, we just cache them,
+	 * so that with the next siwsessid call, the keys
+	 * will be actually pushed.
+	 */
+	if (!remove) {
+		ret = iwm_check_profile(iwm);
+		if (ret < 0)
+			return ret;
+	}
+
+	sta_addr = key->hdr.mac;
+	key_data = key->key;
+	key_len = key->key_len;
+	key_idx = key->hdr.key_idx;
+
+	if (!remove) {
+		IWM_DBG_WEXT(iwm, DBG, "key_idx:%d set tx key:%d\n",
+			     key_idx, set_tx_key);
+		IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len);
+		IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n",
+		       key_hdr->mac, key_hdr->key_idx, key_hdr->multicast);
+
+		IWM_DBG_WEXT(iwm, DBG, "profile: mcast:0x%x, ucast:0x%x\n",
+			     iwm->umac_profile->sec.mcast_cipher,
+			     iwm->umac_profile->sec.ucast_cipher);
+		IWM_DBG_WEXT(iwm, DBG, "profile: auth_type:0x%x, flags:0x%x\n",
+			     iwm->umac_profile->sec.auth_type,
+			     iwm->umac_profile->sec.flags);
+
+		switch (key->alg) {
+		case UMAC_CIPHER_TYPE_WEP_40:
+			wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY;
+			wep40->hdr.buf_size =
+				cpu_to_le16(sizeof(struct iwm_umac_key_wep40) -
+					    sizeof(struct iwm_umac_wifi_if));
+
+			memcpy(&wep40->key_hdr, key_hdr,
+			       sizeof(struct iwm_umac_key_hdr));
+			memcpy(wep40->key, key_data, key_len);
+			wep40->static_key = 1;
+
+			cmd_size = sizeof(struct iwm_umac_key_wep40);
+			break;
+
+		case UMAC_CIPHER_TYPE_WEP_104:
+			wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY;
+			wep104->hdr.buf_size =
+				cpu_to_le16(sizeof(struct iwm_umac_key_wep104) -
+					    sizeof(struct iwm_umac_wifi_if));
+
+			memcpy(&wep104->key_hdr, key_hdr,
+			       sizeof(struct iwm_umac_key_hdr));
+			memcpy(wep104->key, key_data, key_len);
+			wep104->static_key = 1;
+
+			cmd_size = sizeof(struct iwm_umac_key_wep104);
+			break;
+
+		case UMAC_CIPHER_TYPE_CCMP:
+			key_hdr->key_idx++;
+			ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY;
+			ccmp->hdr.buf_size =
+				cpu_to_le16(sizeof(struct iwm_umac_key_ccmp) -
+					    sizeof(struct iwm_umac_wifi_if));
+
+			memcpy(&ccmp->key_hdr, key_hdr,
+			       sizeof(struct iwm_umac_key_hdr));
+
+			memcpy(ccmp->key, key_data, key_len);
+
+			if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID)
+				memcpy(ccmp->iv_count, key->rx_seq, 6);
+
+			cmd_size = sizeof(struct iwm_umac_key_ccmp);
+			break;
+
+		case UMAC_CIPHER_TYPE_TKIP:
+			key_hdr->key_idx++;
+			tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY;
+			tkip->hdr.buf_size =
+				cpu_to_le16(sizeof(struct iwm_umac_key_tkip) -
+					    sizeof(struct iwm_umac_wifi_if));
+
+			memcpy(&tkip->key_hdr, key_hdr,
+			       sizeof(struct iwm_umac_key_hdr));
+
+			memcpy(tkip->tkip_key, key_data, IWM_TKIP_KEY_SIZE);
+			memcpy(tkip->mic_tx_key, key_data + IWM_TKIP_KEY_SIZE,
+			       IWM_TKIP_MIC_SIZE);
+			memcpy(tkip->mic_rx_key,
+			       key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE,
+			       IWM_TKIP_MIC_SIZE);
+
+			if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID)
+				memcpy(ccmp->iv_count, key->rx_seq, 6);
+
+			cmd_size = sizeof(struct iwm_umac_key_tkip);
+			break;
+
+		default:
+			return -ENOTSUPP;
+		}
+
+		if ((key->alg == UMAC_CIPHER_TYPE_CCMP) ||
+		    (key->alg == UMAC_CIPHER_TYPE_TKIP))
+			/*
+			 * UGLY_UGLY_UGLY
+			 * Copied HACK from the MWG driver.
+			 * Without it, the key is set before the second
+			 * EAPOL frame is sent, and the latter is thus
+			 * encrypted.
+			 */
+			schedule_timeout_interruptible(usecs_to_jiffies(300));
+
+		ret =  iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1);
+		if (ret < 0)
+			goto err;
+
+		/*
+		 * We need a default key only if it is set and
+		 * if we're doing WEP.
+		 */
+		if (iwm->default_key == key &&
+			((key->alg == UMAC_CIPHER_TYPE_WEP_40) ||
+			 (key->alg == UMAC_CIPHER_TYPE_WEP_104))) {
+			ret = iwm_set_tx_key(iwm, key_idx);
+			if (ret < 0)
+				goto err;
+		}
+	} else {
+		struct iwm_umac_key_remove key_remove;
+
+		key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY;
+		key_remove.hdr.buf_size =
+			cpu_to_le16(sizeof(struct iwm_umac_key_remove) -
+				    sizeof(struct iwm_umac_wifi_if));
+		memcpy(&key_remove.key_hdr, key_hdr,
+		       sizeof(struct iwm_umac_key_hdr));
+
+		ret =  iwm_send_wifi_if_cmd(iwm, &key_remove,
+					    sizeof(struct iwm_umac_key_remove),
+					    1);
+		if (ret < 0)
+			return ret;
+
+		iwm->keys[key_idx].in_use = 0;
+	}
+
+	return 0;
+
+ err:
+	kfree(key);
+	return ret;
+}
+
+
+int iwm_send_mlme_profile(struct iwm_priv *iwm)
+{
+	int ret, i;
+	struct iwm_umac_profile profile;
+
+	memcpy(&profile, iwm->umac_profile, sizeof(profile));
+
+	profile.hdr.oid = UMAC_WIFI_IF_CMD_SET_PROFILE;
+	profile.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_profile) -
+					   sizeof(struct iwm_umac_wifi_if));
+
+	ret = iwm_send_wifi_if_cmd(iwm, &profile, sizeof(profile), 1);
+	if (ret < 0) {
+		IWM_ERR(iwm, "Send profile command failed\n");
+		return ret;
+	}
+
+	/* Wait for the profile to be active */
+	ret = wait_event_interruptible_timeout(iwm->mlme_queue,
+					       iwm->umac_profile_active == 1,
+					       3 * HZ);
+	if (!ret)
+		return -EBUSY;
+
+
+	for (i = 0; i < IWM_NUM_KEYS; i++)
+		if (iwm->keys[i].in_use) {
+			int default_key = 0;
+			struct iwm_key *key = &iwm->keys[i];
+
+			if (key == iwm->default_key)
+				default_key = 1;
+
+			/* Wait for the profile before sending the keys */
+			wait_event_interruptible_timeout(iwm->mlme_queue,
+			     (test_bit(IWM_STATUS_ASSOCIATING, &iwm->status) ||
+			      test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)),
+							 3 * HZ);
+
+			ret = iwm_set_key(iwm, 0, default_key, key);
+			if (ret < 0)
+				return ret;
+		}
+
+	return 0;
+}
+
+int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
+{
+	int ret;
+	struct iwm_umac_invalidate_profile invalid;
+
+	invalid.hdr.oid = UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE;
+	invalid.hdr.buf_size =
+		cpu_to_le16(sizeof(struct iwm_umac_invalidate_profile) -
+			    sizeof(struct iwm_umac_wifi_if));
+
+	invalid.reason = WLAN_REASON_UNSPECIFIED;
+
+	ret = iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1);
+	if (ret < 0)
+		return ret;
+
+	ret = wait_event_interruptible_timeout(iwm->mlme_queue,
+				 (iwm->umac_profile_active == 0),
+					       2 * HZ);
+	if (!ret)
+		return -EBUSY;
+
+	return 0;
+}
+
+int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags)
+{
+	struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
+	struct iwm_umac_cmd umac_cmd;
+	struct iwm_umac_cmd_stats_req stats_req;
+
+	stats_req.flags = cpu_to_le32(flags);
+
+	umac_cmd.id = UMAC_CMD_OPCODE_STATISTIC_REQUEST;
+	umac_cmd.resp = 0;
+
+	return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &stats_req,
+				     sizeof(struct iwm_umac_cmd_stats_req));
+}
+
+int iwm_send_umac_channel_list(struct iwm_priv *iwm)
+{
+	struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
+	struct iwm_umac_cmd umac_cmd;
+	struct iwm_umac_cmd_get_channel_list *ch_list;
+	int size = sizeof(struct iwm_umac_cmd_get_channel_list) +
+		   sizeof(struct iwm_umac_channel_info) * 4;
+	int ret;
+
+	ch_list = kzalloc(size, GFP_KERNEL);
+	if (!ch_list) {
+		IWM_ERR(iwm, "Couldn't allocate channel list cmd\n");
+		return -ENOMEM;
+	}
+
+	ch_list->ch[0].band = UMAC_BAND_2GHZ;
+	ch_list->ch[0].type = UMAC_CHANNEL_WIDTH_20MHZ;
+	ch_list->ch[0].flags = UMAC_CHANNEL_FLAG_VALID;
+
+	ch_list->ch[1].band = UMAC_BAND_5GHZ;
+	ch_list->ch[1].type = UMAC_CHANNEL_WIDTH_20MHZ;
+	ch_list->ch[1].flags = UMAC_CHANNEL_FLAG_VALID;
+
+	ch_list->ch[2].band = UMAC_BAND_2GHZ;
+	ch_list->ch[2].type = UMAC_CHANNEL_WIDTH_20MHZ;
+	ch_list->ch[2].flags = UMAC_CHANNEL_FLAG_VALID | UMAC_CHANNEL_FLAG_IBSS;
+
+	ch_list->ch[3].band = UMAC_BAND_5GHZ;
+	ch_list->ch[3].type = UMAC_CHANNEL_WIDTH_20MHZ;
+	ch_list->ch[3].flags = UMAC_CHANNEL_FLAG_VALID | UMAC_CHANNEL_FLAG_IBSS;
+
+	ch_list->count = cpu_to_le16(4);
+
+	umac_cmd.id = UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST;
+	umac_cmd.resp = 1;
+
+	ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, ch_list, size);
+
+	kfree(ch_list);
+
+	return ret;
+}
+
+int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
+		   int ssid_num)
+{
+	struct iwm_umac_cmd_scan_request req;
+	int i, ret;
+
+	memset(&req, 0, sizeof(struct iwm_umac_cmd_scan_request));
+
+	req.hdr.oid = UMAC_WIFI_IF_CMD_SCAN_REQUEST;
+	req.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_cmd_scan_request)
+				       - sizeof(struct iwm_umac_wifi_if));
+	req.type = UMAC_WIFI_IF_SCAN_TYPE_USER;
+	req.timeout = 2;
+	req.seq_num = iwm->scan_id;
+	req.ssid_num = min(ssid_num, UMAC_WIFI_IF_PROBE_OPTION_MAX);
+
+	for (i = 0; i < req.ssid_num; i++) {
+		memcpy(req.ssids[i].ssid, ssids[i].ssid, ssids[i].ssid_len);
+		req.ssids[i].ssid_len = ssids[i].ssid_len;
+	}
+
+	ret = iwm_send_wifi_if_cmd(iwm, &req, sizeof(req), 0);
+	if (ret < 0) {
+		IWM_ERR(iwm, "Couldn't send scan request\n");
+		return ret;
+	}
+
+	iwm->scan_id = iwm->scan_id++ % IWM_SCAN_ID_MAX;
+
+	return 0;
+}
+
+int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len)
+{
+	struct cfg80211_ssid one_ssid;
+
+	if (test_and_set_bit(IWM_STATUS_SCANNING, &iwm->status))
+		return 0;
+
+	one_ssid.ssid_len = min(ssid_len, IEEE80211_MAX_SSID_LEN);
+	memcpy(&one_ssid.ssid, ssid, one_ssid.ssid_len);
+
+	return iwm_scan_ssids(iwm, &one_ssid, 1);
+}
+
+int iwm_target_reset(struct iwm_priv *iwm)
+{
+	struct iwm_udma_nonwifi_cmd target_cmd;
+
+	target_cmd.opcode = UMAC_HDI_OUT_OPCODE_REBOOT;
+	target_cmd.addr = 0;
+	target_cmd.op1_sz = 0;
+	target_cmd.op2 = 0;
+	target_cmd.handle_by_hw = 0;
+	target_cmd.resp = 0;
+	target_cmd.eop = 1;
+
+	return iwm_hal_send_target_cmd(iwm, &target_cmd, NULL);
+}
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h
new file mode 100644
index 0000000..36b13a1
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/commands.h
@@ -0,0 +1,419 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ *
+ * Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ */
+
+#ifndef __IWM_COMMANDS_H__
+#define __IWM_COMMANDS_H__
+
+#include <linux/ieee80211.h>
+
+#define IWM_BARKER_REBOOT_NOTIFICATION	0xF
+#define IWM_ACK_BARKER_NOTIFICATION	0x10
+
+/* UMAC commands */
+#define UMAC_RST_CTRL_FLG_LARC_CLK_EN	0x0001
+#define UMAC_RST_CTRL_FLG_LARC_RESET	0x0002
+#define UMAC_RST_CTRL_FLG_FUNC_RESET	0x0004
+#define UMAC_RST_CTRL_FLG_DEV_RESET	0x0008
+#define UMAC_RST_CTRL_FLG_WIFI_CORE_EN	0x0010
+#define UMAC_RST_CTRL_FLG_WIFI_LINK_EN	0x0040
+#define UMAC_RST_CTRL_FLG_WIFI_MLME_EN	0x0080
+#define UMAC_RST_CTRL_FLG_NVM_RELOAD	0x0100
+
+struct iwm_umac_cmd_reset {
+	__le32 flags;
+} __attribute__ ((packed));
+
+#define UMAC_PARAM_TBL_ORD_FIX    0x0
+#define UMAC_PARAM_TBL_ORD_VAR    0x1
+#define UMAC_PARAM_TBL_CFG_FIX    0x2
+#define UMAC_PARAM_TBL_CFG_VAR    0x3
+#define UMAC_PARAM_TBL_BSS_TRK    0x4
+#define UMAC_PARAM_TBL_FA_CFG_FIX 0x5
+#define UMAC_PARAM_TBL_STA        0x6
+#define UMAC_PARAM_TBL_CHN        0x7
+#define UMAC_PARAM_TBL_STATISTICS 0x8
+
+/* fast access table */
+enum {
+	CFG_FRAG_THRESHOLD = 0,
+	CFG_FRAME_RETRY_LIMIT,
+	CFG_OS_QUEUE_UTIL_TH,
+	CFG_RX_FILTER,
+	/* <-- LAST --> */
+	FAST_ACCESS_CFG_TBL_FIX_LAST
+};
+
+/* fixed size table */
+enum {
+	CFG_POWER_INDEX = 0,
+	CFG_PM_LEGACY_RX_TIMEOUT,
+	CFG_PM_LEGACY_TX_TIMEOUT,
+	CFG_PM_CTRL_FLAGS,
+	CFG_PM_KEEP_ALIVE_IN_BEACONS,
+	CFG_BT_ON_THRESHOLD,
+	CFG_RTS_THRESHOLD,
+	CFG_CTS_TO_SELF,
+	CFG_COEX_MODE,
+	CFG_WIRELESS_MODE,
+	CFG_ASSOCIATION_TIMEOUT,
+	CFG_ROAM_TIMEOUT,
+	CFG_CAPABILITY_SUPPORTED_RATES,
+	CFG_SCAN_ALLOWED_UNASSOC_FLAGS,
+	CFG_SCAN_ALLOWED_MAIN_ASSOC_FLAGS,
+	CFG_SCAN_ALLOWED_PAN_ASSOC_FLAGS,
+	CFG_SCAN_INTERNAL_PERIODIC_ENABLED,
+	CFG_SCAN_IMM_INTERNAL_PERIODIC_SCAN_ON_INIT,
+	CFG_SCAN_DEFAULT_PERIODIC_FREQ_SEC,
+	CFG_SCAN_NUM_PASSIVE_CHAN_PER_PARTIAL_SCAN,
+	CFG_TLC_SUPPORTED_TX_HT_RATES,
+	CFG_TLC_SUPPORTED_TX_RATES,
+	CFG_TLC_VALID_ANTENNA,
+	CFG_TLC_SPATIAL_STREAM_SUPPORTED,
+	CFG_TLC_RETRY_PER_RATE,
+	CFG_TLC_RETRY_PER_HT_RATE,
+	CFG_TLC_FIXED_RATE,
+	CFG_TLC_FIXED_RATE_FLAGS,
+	CFG_TLC_CONTROL_FLAGS,
+	CFG_TLC_SR_MIN_FAIL,
+	CFG_TLC_SR_MIN_PASS,
+	CFG_TLC_HT_STAY_IN_COL_PASS_THRESH,
+	CFG_TLC_HT_STAY_IN_COL_FAIL_THRESH,
+	CFG_TLC_LEGACY_STAY_IN_COL_PASS_THRESH,
+	CFG_TLC_LEGACY_STAY_IN_COL_FAIL_THRESH,
+	CFG_TLC_HT_FLUSH_STATS_PACKETS,
+	CFG_TLC_LEGACY_FLUSH_STATS_PACKETS,
+	CFG_TLC_LEGACY_FLUSH_STATS_MS,
+	CFG_TLC_HT_FLUSH_STATS_MS,
+	CFG_TLC_STAY_IN_COL_TIME_OUT,
+	CFG_TLC_AGG_SHORT_LIM,
+	CFG_TLC_AGG_LONG_LIM,
+	CFG_TLC_HT_SR_NO_DECREASE,
+	CFG_TLC_LEGACY_SR_NO_DECREASE,
+	CFG_TLC_SR_FORCE_DECREASE,
+	CFG_TLC_SR_ALLOW_INCREASE,
+	CFG_TLC_AGG_SET_LONG,
+	CFG_TLC_AUTO_AGGREGATION,
+	CFG_TLC_AGG_THRESHOLD,
+	CFG_TLC_TID_LOAD_THRESHOLD,
+	CFG_TLC_BLOCK_ACK_TIMEOUT,
+	CFG_TLC_NO_BA_COUNTED_AS_ONE,
+	CFG_TLC_NUM_BA_STREAMS_ALLOWED,
+	CFG_TLC_NUM_BA_STREAMS_PRESENT,
+	CFG_TLC_RENEW_ADDBA_DELAY,
+	CFG_TLC_NUM_OF_MULTISEC_TO_COUN_LOAD,
+	CFG_TLC_IS_STABLE_IN_HT,
+	CFG_RLC_CHAIN_CTRL,
+	CFG_TRK_TABLE_OP_MODE,
+	CFG_TRK_TABLE_RSSI_THRESHOLD,
+	CFG_TX_PWR_TARGET, /* Used By xVT */
+	CFG_TX_PWR_LIMIT_USR,
+	CFG_TX_PWR_LIMIT_BSS, /* 11d limit */
+	CFG_TX_PWR_LIMIT_BSS_CONSTRAINT, /* 11h constraint */
+	CFG_TX_PWR_MODE,
+	CFG_MLME_DBG_NOTIF_BLOCK,
+	CFG_BT_OFF_BECONS_INTERVALS,
+	CFG_BT_FRAG_DURATION,
+
+	/* <-- LAST --> */
+	CFG_TBL_FIX_LAST
+};
+
+/* variable size table */
+enum {
+	CFG_NET_ADDR = 0,
+	CFG_PROFILE,
+	/* <-- LAST --> */
+	CFG_TBL_VAR_LAST
+};
+
+struct iwm_umac_cmd_set_param_fix {
+	__le16 tbl;
+	__le16 key;
+	__le32 value;
+} __attribute__ ((packed));
+
+struct iwm_umac_cmd_set_param_var {
+	__le16 tbl;
+	__le16 key;
+	__le16 len;
+	__le16 reserved;
+} __attribute__ ((packed));
+
+struct iwm_umac_cmd_get_param {
+	__le16 tbl;
+	__le16 key;
+} __attribute__ ((packed));
+
+struct iwm_umac_cmd_get_param_resp {
+	__le16 tbl;
+	__le16 key;
+	__le16 len;
+	__le16 reserved;
+} __attribute__ ((packed));
+
+struct iwm_umac_cmd_eeprom_proxy_hdr {
+	__le32 type;
+	__le32 offset;
+	__le32 len;
+} __attribute__ ((packed));
+
+struct iwm_umac_cmd_eeprom_proxy {
+	struct iwm_umac_cmd_eeprom_proxy_hdr hdr;
+	u8 buf[0];
+} __attribute__ ((packed));
+
+#define IWM_UMAC_CMD_EEPROM_TYPE_READ       0x1
+#define IWM_UMAC_CMD_EEPROM_TYPE_WRITE      0x2
+
+#define UMAC_CHANNEL_FLAG_VALID		BIT(0)
+#define UMAC_CHANNEL_FLAG_IBSS		BIT(1)
+#define UMAC_CHANNEL_FLAG_ACTIVE	BIT(3)
+#define UMAC_CHANNEL_FLAG_RADAR		BIT(4)
+#define UMAC_CHANNEL_FLAG_DFS		BIT(7)
+
+struct iwm_umac_channel_info {
+	u8 band;
+	u8 type;
+	u8 reserved;
+	u8 flags;
+	__le32 channels_mask;
+} __attribute__ ((packed));
+
+struct iwm_umac_cmd_get_channel_list {
+	__le16 count;
+	__le16 reserved;
+	struct iwm_umac_channel_info ch[0];
+} __attribute__ ((packed));
+
+
+/* UMAC WiFi interface commands */
+
+/* Coexistence mode */
+#define COEX_MODE_SA  0x1
+#define COEX_MODE_XOR 0x2
+#define COEX_MODE_CM  0x3
+#define COEX_MODE_MAX 0x4
+
+/* Wireless mode */
+#define WIRELESS_MODE_11A  0x1
+#define WIRELESS_MODE_11G  0x2
+
+#define UMAC_PROFILE_EX_IE_REQUIRED	0x1
+#define UMAC_PROFILE_QOS_ALLOWED	0x2
+
+/* Scanning */
+#define UMAC_WIFI_IF_PROBE_OPTION_MAX        10
+
+#define UMAC_WIFI_IF_SCAN_TYPE_USER          0x0
+#define UMAC_WIFI_IF_SCAN_TYPE_UMAC_RESERVED 0x1
+#define UMAC_WIFI_IF_SCAN_TYPE_HOST_PERIODIC 0x2
+#define UMAC_WIFI_IF_SCAN_TYPE_MAX           0x3
+
+struct iwm_umac_ssid {
+	u8 ssid_len;
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
+	u8 reserved[3];
+} __attribute__ ((packed));
+
+struct iwm_umac_cmd_scan_request {
+	struct iwm_umac_wifi_if hdr;
+	__le32 type; /* UMAC_WIFI_IF_SCAN_TYPE_* */
+	u8 ssid_num;
+	u8 seq_num;
+	u8 timeout; /* In seconds */
+	u8 reserved;
+	struct iwm_umac_ssid ssids[UMAC_WIFI_IF_PROBE_OPTION_MAX];
+} __attribute__ ((packed));
+
+#define UMAC_CIPHER_TYPE_NONE		0xFF
+#define UMAC_CIPHER_TYPE_USE_GROUPCAST	0x00
+#define UMAC_CIPHER_TYPE_WEP_40		0x01
+#define UMAC_CIPHER_TYPE_WEP_104	0x02
+#define UMAC_CIPHER_TYPE_TKIP		0x04
+#define UMAC_CIPHER_TYPE_CCMP		0x08
+
+/* Supported authentication types - bitmap */
+#define UMAC_AUTH_TYPE_OPEN		0x00
+#define UMAC_AUTH_TYPE_LEGACY_PSK	0x01
+#define UMAC_AUTH_TYPE_8021X		0x02
+#define UMAC_AUTH_TYPE_RSNA_PSK		0x04
+
+/* iwm_umac_security.flag is WPA supported -- bits[0:0] */
+#define UMAC_SEC_FLG_WPA_ON_POS		0
+#define UMAC_SEC_FLG_WPA_ON_SEED	1
+#define UMAC_SEC_FLG_WPA_ON_MSK (UMAC_SEC_FLG_WPA_ON_SEED << \
+				 UMAC_SEC_FLG_WPA_ON_POS)
+
+/* iwm_umac_security.flag is WPA2 supported -- bits [1:1] */
+#define UMAC_SEC_FLG_RSNA_ON_POS	1
+#define UMAC_SEC_FLG_RSNA_ON_SEED	1
+#define UMAC_SEC_FLG_RSNA_ON_MSK        (UMAC_SEC_FLG_RSNA_ON_SEED << \
+					 UMAC_SEC_FLG_RSNA_ON_POS)
+
+/* iwm_umac_security.flag is WSC mode on -- bits [2:2] */
+#define UMAC_SEC_FLG_WSC_ON_POS		2
+#define UMAC_SEC_FLG_WSC_ON_SEED	1
+
+/* Legacy profile can use only WEP40 and WEP104 for encryption and
+ * OPEN or PSK for authentication */
+#define UMAC_SEC_FLG_LEGACY_PROFILE	0
+
+struct iwm_umac_security {
+	u8 auth_type;
+	u8 ucast_cipher;
+	u8 mcast_cipher;
+	u8 flags;
+} __attribute__ ((packed));
+
+struct iwm_umac_ibss {
+	u8 beacon_interval;	/* in millisecond */
+	u8 atim;		/* in millisecond */
+	s8 join_only;
+	u8 band;
+	u8 channel;
+	u8 reserved[3];
+} __attribute__ ((packed));
+
+#define UMAC_MODE_BSS	0
+#define UMAC_MODE_IBSS	1
+
+#define UMAC_BSSID_MAX	4
+
+struct iwm_umac_profile {
+	struct iwm_umac_wifi_if hdr;
+	__le32 mode;
+	struct iwm_umac_ssid ssid;
+	u8 bssid[UMAC_BSSID_MAX][ETH_ALEN];
+	struct iwm_umac_security sec;
+	struct iwm_umac_ibss ibss;
+	__le32 channel_2ghz;
+	__le32 channel_5ghz;
+	__le16 flags;
+	u8 wireless_mode;
+	u8 bss_num;
+} __attribute__ ((packed));
+
+struct iwm_umac_invalidate_profile {
+	struct iwm_umac_wifi_if hdr;
+	u8 reason;
+	u8 reserved[3];
+} __attribute__ ((packed));
+
+/* Encryption key commands */
+struct iwm_umac_key_wep40 {
+	struct iwm_umac_wifi_if hdr;
+	struct iwm_umac_key_hdr key_hdr;
+	u8 key[WLAN_KEY_LEN_WEP40];
+	u8 static_key;
+	u8 reserved[2];
+} __attribute__ ((packed));
+
+struct iwm_umac_key_wep104 {
+	struct iwm_umac_wifi_if hdr;
+	struct iwm_umac_key_hdr key_hdr;
+	u8 key[WLAN_KEY_LEN_WEP104];
+	u8 static_key;
+	u8 reserved[2];
+} __attribute__ ((packed));
+
+#define IWM_TKIP_KEY_SIZE 16
+#define IWM_TKIP_MIC_SIZE 8
+struct iwm_umac_key_tkip {
+	struct iwm_umac_wifi_if hdr;
+	struct iwm_umac_key_hdr key_hdr;
+	u8 iv_count[6];
+	u8 reserved[2];
+	u8 tkip_key[IWM_TKIP_KEY_SIZE];
+	u8 mic_rx_key[IWM_TKIP_MIC_SIZE];
+	u8 mic_tx_key[IWM_TKIP_MIC_SIZE];
+} __attribute__ ((packed));
+
+struct iwm_umac_key_ccmp {
+	struct iwm_umac_wifi_if hdr;
+	struct iwm_umac_key_hdr key_hdr;
+	u8 iv_count[6];
+	u8 reserved[2];
+	u8 key[WLAN_KEY_LEN_CCMP];
+} __attribute__ ((packed));
+
+struct iwm_umac_key_remove {
+	struct iwm_umac_wifi_if hdr;
+	struct iwm_umac_key_hdr key_hdr;
+} __attribute__ ((packed));
+
+struct iwm_umac_tx_key_id {
+	struct iwm_umac_wifi_if hdr;
+	u8 key_idx;
+	u8 reserved[3];
+} __attribute__ ((packed));
+
+struct iwm_umac_cmd_stats_req {
+	__le32 flags;
+} __attribute__ ((packed));
+
+/* LMAC commands */
+int iwm_read_mac(struct iwm_priv *iwm, u8 *mac);
+int iwm_send_prio_table(struct iwm_priv *iwm);
+int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested);
+int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested);
+int iwm_send_calib_results(struct iwm_priv *iwm);
+int iwm_store_rxiq_calib_result(struct iwm_priv *iwm);
+
+/* UMAC commands */
+int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
+			 bool resp);
+int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp);
+int iwm_umac_set_config_fix(struct iwm_priv *iwm, u16 tbl, u16 key, u32 value);
+int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key,
+			    void *payload, u16 payload_size);
+int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags);
+int iwm_send_mlme_profile(struct iwm_priv *iwm);
+int iwm_invalidate_mlme_profile(struct iwm_priv *iwm);
+int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id);
+int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx);
+int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
+		struct iwm_key *key);
+int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags);
+int iwm_send_umac_channel_list(struct iwm_priv *iwm);
+int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
+		   int ssid_num);
+int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len);
+
+/* UDMA commands */
+int iwm_target_reset(struct iwm_priv *iwm);
+#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/debug.h b/drivers/net/wireless/iwmc3200wifi/debug.h
new file mode 100644
index 0000000..8fbb42d
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/debug.h
@@ -0,0 +1,124 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifndef __IWM_DEBUG_H__
+#define __IWM_DEBUG_H__
+
+#define IWM_ERR(p, f, a...) dev_err(iwm_to_dev(p), f, ## a)
+#define IWM_WARN(p, f, a...) dev_warn(iwm_to_dev(p), f, ## a)
+#define IWM_INFO(p, f, a...) dev_info(iwm_to_dev(p), f, ## a)
+#define IWM_CRIT(p, f, a...) dev_crit(iwm_to_dev(p), f, ## a)
+
+#ifdef CONFIG_IWM_DEBUG
+
+#define IWM_DEBUG_MODULE(i, level, module, f, a...)			     \
+do {									     \
+	if (unlikely(i->dbg.dbg_module[IWM_DM_##module] >= (IWM_DL_##level)))\
+		dev_printk(KERN_INFO, (iwm_to_dev(i)),	             \
+			   "%s " f, __func__ , ## a);			     \
+} while (0)
+
+#define IWM_HEXDUMP(i, level, module, pref, buf, len)		             \
+do {									     \
+	if (unlikely(i->dbg.dbg_module[IWM_DM_##module] >= (IWM_DL_##level)))\
+		print_hex_dump(KERN_INFO, pref, DUMP_PREFIX_OFFSET,	     \
+			       16, 1, buf, len, 1);			     \
+} while (0)
+
+#else
+
+#define IWM_DEBUG_MODULE(i, level, module, f, a...)
+#define IWM_HEXDUMP(i, level, module, pref, buf, len)
+
+#endif /* CONFIG_IWM_DEBUG */
+
+/* Debug modules */
+enum iwm_debug_module_id {
+	IWM_DM_BOOT = 0,
+	IWM_DM_FW,
+	IWM_DM_SDIO,
+	IWM_DM_NTF,
+	IWM_DM_RX,
+	IWM_DM_TX,
+	IWM_DM_MLME,
+	IWM_DM_CMD,
+	IWM_DM_WEXT,
+	__IWM_DM_NR,
+};
+#define IWM_DM_DEFAULT 0
+
+#define IWM_DBG_BOOT(i, l, f, a...) IWM_DEBUG_MODULE(i, l, BOOT, f, ## a)
+#define IWM_DBG_FW(i, l, f, a...)   IWM_DEBUG_MODULE(i, l, FW, f, ## a)
+#define IWM_DBG_SDIO(i, l, f, a...) IWM_DEBUG_MODULE(i, l, SDIO, f, ## a)
+#define IWM_DBG_NTF(i, l, f, a...)  IWM_DEBUG_MODULE(i, l, NTF, f, ## a)
+#define IWM_DBG_RX(i, l, f, a...)   IWM_DEBUG_MODULE(i, l, RX, f, ## a)
+#define IWM_DBG_TX(i, l, f, a...)   IWM_DEBUG_MODULE(i, l, TX, f, ## a)
+#define IWM_DBG_MLME(i, l, f, a...) IWM_DEBUG_MODULE(i, l, MLME, f, ## a)
+#define IWM_DBG_CMD(i, l, f, a...)  IWM_DEBUG_MODULE(i, l, CMD, f, ## a)
+#define IWM_DBG_WEXT(i, l, f, a...) IWM_DEBUG_MODULE(i, l, WEXT, f, ## a)
+
+/* Debug levels */
+enum iwm_debug_level {
+	IWM_DL_NONE = 0,
+	IWM_DL_ERR,
+	IWM_DL_WARN,
+	IWM_DL_INFO,
+	IWM_DL_DBG,
+};
+#define IWM_DL_DEFAULT IWM_DL_ERR
+
+struct iwm_debugfs {
+	struct iwm_priv *iwm;
+	struct dentry *rootdir;
+	struct dentry *devdir;
+	struct dentry *dbgdir;
+	struct dentry *txdir;
+	struct dentry *rxdir;
+	struct dentry *busdir;
+
+	u32 dbg_level;
+	struct dentry *dbg_level_dentry;
+
+	unsigned long dbg_modules;
+	struct dentry *dbg_modules_dentry;
+
+	u8 dbg_module[__IWM_DM_NR];
+	struct dentry *dbg_module_dentries[__IWM_DM_NR];
+
+	struct dentry *txq_dentry;
+	struct dentry *tx_credit_dentry;
+	struct dentry *rx_ticket_dentry;
+};
+
+#ifdef CONFIG_IWM_DEBUG
+int iwm_debugfs_init(struct iwm_priv *iwm);
+void iwm_debugfs_exit(struct iwm_priv *iwm);
+#else
+static inline int iwm_debugfs_init(struct iwm_priv *iwm)
+{
+	return 0;
+}
+static inline void iwm_debugfs_exit(struct iwm_priv *iwm) {}
+#endif
+
+#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/debugfs.c b/drivers/net/wireless/iwmc3200wifi/debugfs.c
new file mode 100644
index 0000000..0fa7b91
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/debugfs.c
@@ -0,0 +1,453 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/debugfs.h>
+
+#include "iwm.h"
+#include "bus.h"
+#include "rx.h"
+#include "debug.h"
+
+static struct {
+	u8 id;
+	char *name;
+} iwm_debug_module[__IWM_DM_NR] = {
+	 {IWM_DM_BOOT, "boot"},
+	 {IWM_DM_FW,   "fw"},
+	 {IWM_DM_SDIO, "sdio"},
+	 {IWM_DM_NTF,  "ntf"},
+	 {IWM_DM_RX,   "rx"},
+	 {IWM_DM_TX,   "tx"},
+	 {IWM_DM_MLME, "mlme"},
+	 {IWM_DM_CMD,  "cmd"},
+	 {IWM_DM_WEXT,  "wext"},
+};
+
+#define add_dbg_module(dbg, name, id, initlevel) 	\
+do {							\
+	struct dentry *d;				\
+	dbg.dbg_module[id] = (initlevel);		\
+	d = debugfs_create_x8(name, 0600, dbg.dbgdir,	\
+			     &(dbg.dbg_module[id]));	\
+	if (!IS_ERR(d))					\
+		dbg.dbg_module_dentries[id] = d;        \
+} while (0)
+
+static int iwm_debugfs_u32_read(void *data, u64 *val)
+{
+	struct iwm_priv *iwm = data;
+
+	*val = iwm->dbg.dbg_level;
+	return 0;
+}
+
+static int iwm_debugfs_dbg_level_write(void *data, u64 val)
+{
+	struct iwm_priv *iwm = data;
+	int i;
+
+	iwm->dbg.dbg_level = val;
+
+	for (i = 0; i < __IWM_DM_NR; i++)
+		iwm->dbg.dbg_module[i] = val;
+
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_level,
+			iwm_debugfs_u32_read, iwm_debugfs_dbg_level_write,
+			"%llu\n");
+
+static int iwm_debugfs_dbg_modules_write(void *data, u64 val)
+{
+	struct iwm_priv *iwm = data;
+	int i, bit;
+
+	iwm->dbg.dbg_modules = val;
+
+	for (i = 0; i < __IWM_DM_NR; i++)
+		iwm->dbg.dbg_module[i] = 0;
+
+	for_each_bit(bit, &iwm->dbg.dbg_modules, __IWM_DM_NR)
+		iwm->dbg.dbg_module[bit] = iwm->dbg.dbg_level;
+
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_modules,
+			iwm_debugfs_u32_read, iwm_debugfs_dbg_modules_write,
+			"%llu\n");
+
+static int iwm_txrx_open(struct inode *inode, struct file *filp)
+{
+	filp->private_data = inode->i_private;
+	return 0;
+}
+
+
+static ssize_t iwm_debugfs_txq_read(struct file *filp, char __user *buffer,
+				   size_t count, loff_t *ppos)
+{
+	struct iwm_priv *iwm = filp->private_data;
+	char *buf;
+	int i, buf_len = 4096;
+	size_t len = 0;
+	ssize_t ret;
+
+	if (*ppos != 0)
+		return 0;
+	if (count < sizeof(buf))
+		return -ENOSPC;
+
+	buf = kzalloc(buf_len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	for (i = 0; i < IWM_TX_QUEUES; i++) {
+		struct iwm_tx_queue *txq = &iwm->txq[i];
+		struct sk_buff *skb;
+		int j;
+		unsigned long flags;
+
+		spin_lock_irqsave(&txq->queue.lock, flags);
+
+		skb = (struct sk_buff *)&txq->queue;
+
+		len += snprintf(buf + len, buf_len - len, "TXQ #%d\n", i);
+		len += snprintf(buf + len, buf_len - len, "\tStopped:     %d\n",
+				__netif_subqueue_stopped(iwm_to_ndev(iwm),
+							 txq->id));
+		len += snprintf(buf + len, buf_len - len, "\tConcat count:%d\n",
+				txq->concat_count);
+		len += snprintf(buf + len, buf_len - len, "\tQueue len:   %d\n",
+				skb_queue_len(&txq->queue));
+		for (j = 0; j < skb_queue_len(&txq->queue); j++) {
+			struct iwm_tx_info *tx_info;
+
+			skb = skb->next;
+			tx_info = skb_to_tx_info(skb);
+
+			len += snprintf(buf + len, buf_len - len,
+					"\tSKB #%d\n", j);
+			len += snprintf(buf + len, buf_len - len,
+					"\t\tsta:   %d\n", tx_info->sta);
+			len += snprintf(buf + len, buf_len - len,
+					"\t\tcolor: %d\n", tx_info->color);
+			len += snprintf(buf + len, buf_len - len,
+					"\t\ttid:   %d\n", tx_info->tid);
+		}
+
+		spin_unlock_irqrestore(&txq->queue.lock, flags);
+	}
+
+	ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len);
+	kfree(buf);
+
+	return ret;
+}
+
+static ssize_t iwm_debugfs_tx_credit_read(struct file *filp,
+					  char __user *buffer,
+					  size_t count, loff_t *ppos)
+{
+	struct iwm_priv *iwm = filp->private_data;
+	struct iwm_tx_credit *credit = &iwm->tx_credit;
+	char *buf;
+	int i, buf_len = 4096;
+	size_t len = 0;
+	ssize_t ret;
+
+	if (*ppos != 0)
+		return 0;
+	if (count < sizeof(buf))
+		return -ENOSPC;
+
+	buf = kzalloc(buf_len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	len += snprintf(buf + len, buf_len - len,
+			"NR pools:  %d\n", credit->pool_nr);
+	len += snprintf(buf + len, buf_len - len,
+			"pools map: 0x%lx\n", credit->full_pools_map);
+
+	len += snprintf(buf + len, buf_len - len, "\n### POOLS ###\n");
+	for (i = 0; i < IWM_MACS_OUT_GROUPS; i++) {
+		len += snprintf(buf + len, buf_len - len,
+				"pools entry #%d\n", i);
+		len += snprintf(buf + len, buf_len - len,
+				"\tid:          %d\n",
+				credit->pools[i].id);
+		len += snprintf(buf + len, buf_len - len,
+				"\tsid:         %d\n",
+				credit->pools[i].sid);
+		len += snprintf(buf + len, buf_len - len,
+				"\tmin_pages:   %d\n",
+				credit->pools[i].min_pages);
+		len += snprintf(buf + len, buf_len - len,
+				"\tmax_pages:   %d\n",
+				credit->pools[i].max_pages);
+		len += snprintf(buf + len, buf_len - len,
+				"\talloc_pages: %d\n",
+				credit->pools[i].alloc_pages);
+		len += snprintf(buf + len, buf_len - len,
+				"\tfreed_pages: %d\n",
+				credit->pools[i].total_freed_pages);
+	}
+
+	len += snprintf(buf + len, buf_len - len, "\n### SPOOLS ###\n");
+	for (i = 0; i < IWM_MACS_OUT_SGROUPS; i++) {
+		len += snprintf(buf + len, buf_len - len,
+				"spools entry #%d\n", i);
+		len += snprintf(buf + len, buf_len - len,
+				"\tid:          %d\n",
+				credit->spools[i].id);
+		len += snprintf(buf + len, buf_len - len,
+				"\tmax_pages:   %d\n",
+				credit->spools[i].max_pages);
+		len += snprintf(buf + len, buf_len - len,
+				"\talloc_pages: %d\n",
+				credit->spools[i].alloc_pages);
+
+	}
+
+	ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len);
+	kfree(buf);
+
+	return ret;
+}
+
+static ssize_t iwm_debugfs_rx_ticket_read(struct file *filp,
+					  char __user *buffer,
+					  size_t count, loff_t *ppos)
+{
+	struct iwm_priv *iwm = filp->private_data;
+	struct iwm_rx_ticket_node *ticket, *next;
+	char *buf;
+	int buf_len = 4096, i;
+	size_t len = 0;
+	ssize_t ret;
+
+	if (*ppos != 0)
+		return 0;
+	if (count < sizeof(buf))
+		return -ENOSPC;
+
+	buf = kzalloc(buf_len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	list_for_each_entry_safe(ticket, next, &iwm->rx_tickets, node) {
+		len += snprintf(buf + len, buf_len - len, "Ticket #%d\n",
+				ticket->ticket->id);
+		len += snprintf(buf + len, buf_len - len, "\taction: 0x%x\n",
+				ticket->ticket->action);
+		len += snprintf(buf + len, buf_len - len, "\tflags:  0x%x\n",
+				ticket->ticket->flags);
+	}
+
+	for (i = 0; i < IWM_RX_ID_HASH; i++) {
+		struct iwm_rx_packet *packet, *nxt;
+		struct list_head *pkt_list = &iwm->rx_packets[i];
+		if (!list_empty(pkt_list)) {
+			len += snprintf(buf + len, buf_len - len,
+					"Packet hash #%d\n", i);
+			list_for_each_entry_safe(packet, nxt, pkt_list, node) {
+				len += snprintf(buf + len, buf_len - len,
+						"\tPacket id:     %d\n",
+						packet->id);
+				len += snprintf(buf + len, buf_len - len,
+						"\tPacket length: %lu\n",
+						packet->pkt_size);
+			}
+		}
+	}
+
+	ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len);
+	kfree(buf);
+
+	return ret;
+}
+
+
+static const struct file_operations iwm_debugfs_txq_fops = {
+	.owner =	THIS_MODULE,
+	.open =		iwm_txrx_open,
+	.read =		iwm_debugfs_txq_read,
+};
+
+static const struct file_operations iwm_debugfs_tx_credit_fops = {
+	.owner =	THIS_MODULE,
+	.open =		iwm_txrx_open,
+	.read =		iwm_debugfs_tx_credit_read,
+};
+
+static const struct file_operations iwm_debugfs_rx_ticket_fops = {
+	.owner =	THIS_MODULE,
+	.open =		iwm_txrx_open,
+	.read =		iwm_debugfs_rx_ticket_read,
+};
+
+int iwm_debugfs_init(struct iwm_priv *iwm)
+{
+	int i, result;
+	char devdir[16];
+
+	iwm->dbg.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+	result = PTR_ERR(iwm->dbg.rootdir);
+	if (!result || IS_ERR(iwm->dbg.rootdir)) {
+		if (result == -ENODEV) {
+			IWM_ERR(iwm, "DebugFS (CONFIG_DEBUG_FS) not "
+				"enabled in kernel config\n");
+			result = 0;	/* No debugfs support */
+		}
+		IWM_ERR(iwm, "Couldn't create rootdir: %d\n", result);
+		goto error;
+	}
+
+	snprintf(devdir, sizeof(devdir), "%s", wiphy_name(iwm_to_wiphy(iwm)));
+
+	iwm->dbg.devdir = debugfs_create_dir(devdir, iwm->dbg.rootdir);
+	result = PTR_ERR(iwm->dbg.devdir);
+	if (IS_ERR(iwm->dbg.devdir) && (result != -ENODEV)) {
+		IWM_ERR(iwm, "Couldn't create devdir: %d\n", result);
+		goto error;
+	}
+
+	iwm->dbg.dbgdir = debugfs_create_dir("debug", iwm->dbg.devdir);
+	result = PTR_ERR(iwm->dbg.dbgdir);
+	if (IS_ERR(iwm->dbg.dbgdir) && (result != -ENODEV)) {
+		IWM_ERR(iwm, "Couldn't create dbgdir: %d\n", result);
+		goto error;
+	}
+
+	iwm->dbg.rxdir = debugfs_create_dir("rx", iwm->dbg.devdir);
+	result = PTR_ERR(iwm->dbg.rxdir);
+	if (IS_ERR(iwm->dbg.rxdir) && (result != -ENODEV)) {
+		IWM_ERR(iwm, "Couldn't create rx dir: %d\n", result);
+		goto error;
+	}
+
+	iwm->dbg.txdir = debugfs_create_dir("tx", iwm->dbg.devdir);
+	result = PTR_ERR(iwm->dbg.txdir);
+	if (IS_ERR(iwm->dbg.txdir) && (result != -ENODEV)) {
+		IWM_ERR(iwm, "Couldn't create tx dir: %d\n", result);
+		goto error;
+	}
+
+	iwm->dbg.busdir = debugfs_create_dir("bus", iwm->dbg.devdir);
+	result = PTR_ERR(iwm->dbg.busdir);
+	if (IS_ERR(iwm->dbg.busdir) && (result != -ENODEV)) {
+		IWM_ERR(iwm, "Couldn't create bus dir: %d\n", result);
+		goto error;
+	}
+
+	if (iwm->bus_ops->debugfs_init) {
+		result = iwm->bus_ops->debugfs_init(iwm, iwm->dbg.busdir);
+		if (result < 0) {
+			IWM_ERR(iwm, "Couldn't create bus entry: %d\n", result);
+			goto error;
+		}
+	}
+
+
+	iwm->dbg.dbg_level = IWM_DL_NONE;
+	iwm->dbg.dbg_level_dentry =
+		debugfs_create_file("level", 0200, iwm->dbg.dbgdir, iwm,
+				    &fops_iwm_dbg_level);
+	result = PTR_ERR(iwm->dbg.dbg_level_dentry);
+	if (IS_ERR(iwm->dbg.dbg_level_dentry) && (result != -ENODEV)) {
+		IWM_ERR(iwm, "Couldn't create dbg_level: %d\n", result);
+		goto error;
+	}
+
+
+	iwm->dbg.dbg_modules = IWM_DM_DEFAULT;
+	iwm->dbg.dbg_modules_dentry =
+		debugfs_create_file("modules", 0200, iwm->dbg.dbgdir, iwm,
+				    &fops_iwm_dbg_modules);
+	result = PTR_ERR(iwm->dbg.dbg_modules_dentry);
+	if (IS_ERR(iwm->dbg.dbg_modules_dentry) && (result != -ENODEV)) {
+		IWM_ERR(iwm, "Couldn't create dbg_modules: %d\n", result);
+		goto error;
+	}
+
+	for (i = 0; i < __IWM_DM_NR; i++)
+		add_dbg_module(iwm->dbg, iwm_debug_module[i].name,
+			       iwm_debug_module[i].id, IWM_DL_DEFAULT);
+
+	iwm->dbg.txq_dentry = debugfs_create_file("queues", 0200,
+						  iwm->dbg.txdir, iwm,
+						  &iwm_debugfs_txq_fops);
+	result = PTR_ERR(iwm->dbg.txq_dentry);
+	if (IS_ERR(iwm->dbg.txq_dentry) && (result != -ENODEV)) {
+		IWM_ERR(iwm, "Couldn't create tx queue: %d\n", result);
+		goto error;
+	}
+
+	iwm->dbg.tx_credit_dentry = debugfs_create_file("credits", 0200,
+						   iwm->dbg.txdir, iwm,
+						   &iwm_debugfs_tx_credit_fops);
+	result = PTR_ERR(iwm->dbg.tx_credit_dentry);
+	if (IS_ERR(iwm->dbg.tx_credit_dentry) && (result != -ENODEV)) {
+		IWM_ERR(iwm, "Couldn't create tx credit: %d\n", result);
+		goto error;
+	}
+
+	iwm->dbg.rx_ticket_dentry = debugfs_create_file("tickets", 0200,
+						  iwm->dbg.rxdir, iwm,
+						  &iwm_debugfs_rx_ticket_fops);
+	result = PTR_ERR(iwm->dbg.rx_ticket_dentry);
+	if (IS_ERR(iwm->dbg.rx_ticket_dentry) && (result != -ENODEV)) {
+		IWM_ERR(iwm, "Couldn't create rx ticket: %d\n", result);
+		goto error;
+	}
+
+	return 0;
+
+ error:
+	return result;
+}
+
+void iwm_debugfs_exit(struct iwm_priv *iwm)
+{
+	int i;
+
+	for (i = 0; i < __IWM_DM_NR; i++)
+		debugfs_remove(iwm->dbg.dbg_module_dentries[i]);
+
+	debugfs_remove(iwm->dbg.dbg_modules_dentry);
+	debugfs_remove(iwm->dbg.dbg_level_dentry);
+	debugfs_remove(iwm->dbg.txq_dentry);
+	debugfs_remove(iwm->dbg.tx_credit_dentry);
+	debugfs_remove(iwm->dbg.rx_ticket_dentry);
+	if (iwm->bus_ops->debugfs_exit)
+		iwm->bus_ops->debugfs_exit(iwm);
+
+	debugfs_remove(iwm->dbg.busdir);
+	debugfs_remove(iwm->dbg.dbgdir);
+	debugfs_remove(iwm->dbg.txdir);
+	debugfs_remove(iwm->dbg.rxdir);
+	debugfs_remove(iwm->dbg.devdir);
+	debugfs_remove(iwm->dbg.rootdir);
+}
diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.c b/drivers/net/wireless/iwmc3200wifi/eeprom.c
new file mode 100644
index 0000000..0f34b84
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/eeprom.c
@@ -0,0 +1,187 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ *
+ * Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ */
+
+#include <linux/kernel.h>
+
+#include "iwm.h"
+#include "umac.h"
+#include "commands.h"
+#include "eeprom.h"
+
+static struct iwm_eeprom_entry eeprom_map[] = {
+	[IWM_EEPROM_SIG] =
+	{"Signature", IWM_EEPROM_SIG_OFF, IWM_EEPROM_SIG_LEN},
+
+	[IWM_EEPROM_VERSION] =
+	{"Version", IWM_EEPROM_VERSION_OFF, IWM_EEPROM_VERSION_LEN},
+
+	[IWM_EEPROM_OEM_HW_VERSION] =
+	{"OEM HW version", IWM_EEPROM_OEM_HW_VERSION_OFF,
+	 IWM_EEPROM_OEM_HW_VERSION_LEN},
+
+	[IWM_EEPROM_MAC_VERSION] =
+	{"MAC version", IWM_EEPROM_MAC_VERSION_OFF, IWM_EEPROM_MAC_VERSION_LEN},
+
+	[IWM_EEPROM_CARD_ID] =
+	{"Card ID", IWM_EEPROM_CARD_ID_OFF, IWM_EEPROM_CARD_ID_LEN},
+
+	[IWM_EEPROM_RADIO_CONF] =
+	{"Radio config", IWM_EEPROM_RADIO_CONF_OFF, IWM_EEPROM_RADIO_CONF_LEN},
+
+	[IWM_EEPROM_SKU_CAP] =
+	{"SKU capabilities", IWM_EEPROM_SKU_CAP_OFF, IWM_EEPROM_SKU_CAP_LEN},
+
+	[IWM_EEPROM_CALIB_RXIQ_OFFSET] =
+	{"RX IQ offset", IWM_EEPROM_CALIB_RXIQ_OFF, IWM_EEPROM_INDIRECT_LEN},
+
+	[IWM_EEPROM_CALIB_RXIQ] =
+	{"Calib RX IQ", 0, IWM_EEPROM_CALIB_RXIQ_LEN},
+};
+
+
+static int iwm_eeprom_read(struct iwm_priv *iwm, u8 eeprom_id)
+{
+	int ret;
+	u32 entry_size, chunk_size, data_offset = 0, addr_offset = 0;
+	u32 addr;
+	struct iwm_udma_wifi_cmd udma_cmd;
+	struct iwm_umac_cmd umac_cmd;
+	struct iwm_umac_cmd_eeprom_proxy eeprom_cmd;
+
+	if (eeprom_id > (IWM_EEPROM_LAST - 1))
+		return -EINVAL;
+
+	entry_size = eeprom_map[eeprom_id].length;
+
+	if (eeprom_id >= IWM_EEPROM_INDIRECT_DATA) {
+		/* indirect data */
+		u32 off_id = eeprom_id - IWM_EEPROM_INDIRECT_DATA +
+			     IWM_EEPROM_INDIRECT_OFFSET;
+
+		eeprom_map[eeprom_id].offset =
+			*(u16 *)(iwm->eeprom + eeprom_map[off_id].offset) << 1;
+	}
+
+	addr = eeprom_map[eeprom_id].offset;
+
+	udma_cmd.eop = 1;
+	udma_cmd.credit_group = 0x4;
+	udma_cmd.ra_tid = UMAC_HDI_ACT_TBL_IDX_HOST_CMD;
+	udma_cmd.lmac_offset = 0;
+
+	umac_cmd.id = UMAC_CMD_OPCODE_EEPROM_PROXY;
+	umac_cmd.resp = 1;
+
+	while (entry_size > 0) {
+		chunk_size = min_t(u32, entry_size, IWM_MAX_EEPROM_DATA_LEN);
+
+		eeprom_cmd.hdr.type =
+			cpu_to_le32(IWM_UMAC_CMD_EEPROM_TYPE_READ);
+		eeprom_cmd.hdr.offset = cpu_to_le32(addr + addr_offset);
+		eeprom_cmd.hdr.len = cpu_to_le32(chunk_size);
+
+		ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd,
+					    &umac_cmd, &eeprom_cmd,
+				     sizeof(struct iwm_umac_cmd_eeprom_proxy));
+		if (ret < 0) {
+			IWM_ERR(iwm, "Couldn't read eeprom\n");
+			return ret;
+		}
+
+		ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_EEPROM_PROXY,
+				       IWM_SRC_UMAC, 2*HZ);
+		if (ret < 0) {
+			IWM_ERR(iwm, "Did not get any eeprom answer\n");
+			return ret;
+		}
+
+		data_offset += chunk_size;
+		addr_offset += chunk_size;
+		entry_size -= chunk_size;
+	}
+
+	return 0;
+}
+
+u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id)
+{
+	if (!iwm->eeprom)
+		return ERR_PTR(-ENODEV);
+
+	return iwm->eeprom + eeprom_map[eeprom_id].offset;
+}
+
+int iwm_eeprom_init(struct iwm_priv *iwm)
+{
+	int i, ret = 0;
+	char name[32];
+
+	iwm->eeprom = kzalloc(IWM_EEPROM_LEN, GFP_KERNEL);
+	if (!iwm->eeprom)
+		return -ENOMEM;
+
+	for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) {
+#ifdef CONFIG_IWM_B0_HW_SUPPORT
+		if (iwm->conf.hw_b0 && (i >= IWM_EEPROM_INDIRECT_OFFSET))
+			break;
+#endif
+		ret = iwm_eeprom_read(iwm, i);
+		if (ret < 0) {
+			IWM_ERR(iwm, "Couldn't read eeprom entry #%d: %s\n",
+				i, eeprom_map[i].name);
+			break;
+		}
+	}
+
+	IWM_DBG_BOOT(iwm, DBG, "EEPROM dump:\n");
+	for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) {
+		memset(name, 0, 32);
+		sprintf(name, "%s: ", eeprom_map[i].name);
+
+		IWM_HEXDUMP(iwm, DBG, BOOT, name,
+			    iwm->eeprom + eeprom_map[i].offset,
+			    eeprom_map[i].length);
+	}
+
+	return ret;
+}
+
+void iwm_eeprom_exit(struct iwm_priv *iwm)
+{
+	kfree(iwm->eeprom);
+}
diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.h b/drivers/net/wireless/iwmc3200wifi/eeprom.h
new file mode 100644
index 0000000..cdb31a6
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/eeprom.h
@@ -0,0 +1,114 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ *
+ * Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ */
+
+#ifndef __IWM_EEPROM_H__
+#define __IWM_EEPROM_H__
+
+enum {
+	IWM_EEPROM_SIG = 0,
+	IWM_EEPROM_FIRST = IWM_EEPROM_SIG,
+	IWM_EEPROM_VERSION,
+	IWM_EEPROM_OEM_HW_VERSION,
+	IWM_EEPROM_MAC_VERSION,
+	IWM_EEPROM_CARD_ID,
+	IWM_EEPROM_RADIO_CONF,
+	IWM_EEPROM_SKU_CAP,
+
+	IWM_EEPROM_INDIRECT_OFFSET,
+	IWM_EEPROM_CALIB_RXIQ_OFFSET = IWM_EEPROM_INDIRECT_OFFSET,
+
+	IWM_EEPROM_INDIRECT_DATA,
+	IWM_EEPROM_CALIB_RXIQ = IWM_EEPROM_INDIRECT_DATA,
+
+	IWM_EEPROM_LAST,
+};
+
+#define IWM_EEPROM_SIG_OFF             0x00
+#define IWM_EEPROM_VERSION_OFF        (0x54 << 1)
+#define IWM_EEPROM_OEM_HW_VERSION_OFF (0x56 << 1)
+#define IWM_EEPROM_MAC_VERSION_OFF    (0x30 << 1)
+#define IWM_EEPROM_CARD_ID_OFF        (0x5d << 1)
+#define IWM_EEPROM_RADIO_CONF_OFF     (0x58 << 1)
+#define IWM_EEPROM_SKU_CAP_OFF        (0x55 << 1)
+#define IWM_EEPROM_CALIB_CONFIG_OFF   (0x7c << 1)
+
+#define IWM_EEPROM_SIG_LEN              4
+#define IWM_EEPROM_VERSION_LEN          2
+#define IWM_EEPROM_OEM_HW_VERSION_LEN   2
+#define IWM_EEPROM_MAC_VERSION_LEN      1
+#define IWM_EEPROM_CARD_ID_LEN          2
+#define IWM_EEPROM_RADIO_CONF_LEN       2
+#define IWM_EEPROM_SKU_CAP_LEN          2
+#define IWM_EEPROM_INDIRECT_LEN		2
+
+#define IWM_MAX_EEPROM_DATA_LEN         240
+#define IWM_EEPROM_LEN                  0x800
+
+#define IWM_EEPROM_MIN_ALLOWED_VERSION          0x0610
+#define IWM_EEPROM_MAX_ALLOWED_VERSION          0x0700
+#define IWM_EEPROM_CURRENT_VERSION              0x0612
+
+#define IWM_EEPROM_SKU_CAP_BAND_24GHZ           (1 << 4)
+#define IWM_EEPROM_SKU_CAP_BAND_52GHZ           (1 << 5)
+#define IWM_EEPROM_SKU_CAP_11N_ENABLE           (1 << 6)
+
+enum {
+	IWM_EEPROM_CALIB_CAL_HDR,
+	IWM_EEPROM_CALIB_TX_POWER,
+	IWM_EEPROM_CALIB_XTAL,
+	IWM_EEPROM_CALIB_TEMPERATURE,
+	IWM_EEPROM_CALIB_RX_BB_FILTER,
+	IWM_EEPROM_CALIB_RX_IQ,
+	IWM_EEPROM_CALIB_MAX,
+};
+
+#define IWM_EEPROM_CALIB_RXIQ_OFF	(IWM_EEPROM_CALIB_CONFIG_OFF + \
+					 (IWM_EEPROM_CALIB_RX_IQ << 1))
+#define IWM_EEPROM_CALIB_RXIQ_LEN	sizeof(struct iwm_lmac_calib_rxiq)
+
+struct iwm_eeprom_entry {
+	char *name;
+	u32 offset;
+	u32 length;
+};
+
+int iwm_eeprom_init(struct iwm_priv *iwm);
+void iwm_eeprom_exit(struct iwm_priv *iwm);
+u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id);
+
+#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c
new file mode 100644
index 0000000..db4ba08
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/fw.c
@@ -0,0 +1,388 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ *
+ * Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/firmware.h>
+
+#include "iwm.h"
+#include "bus.h"
+#include "hal.h"
+#include "umac.h"
+#include "debug.h"
+#include "fw.h"
+#include "commands.h"
+
+static const char fw_barker[] = "*WESTOPFORNOONE*";
+
+/*
+ * @op_code: Op code we're looking for.
+ * @index: There can be several instances of the same opcode within
+ *         the firmware. Index specifies which one we're looking for.
+ */
+static int iwm_fw_op_offset(struct iwm_priv *iwm, const struct firmware *fw,
+			    u16 op_code, u32 index)
+{
+	int offset = -EINVAL, fw_offset;
+	u32 op_index = 0;
+	const u8 *fw_ptr;
+	struct iwm_fw_hdr_rec *rec;
+
+	fw_offset = 0;
+	fw_ptr = fw->data;
+
+	/* We first need to look for the firmware barker */
+	if (memcmp(fw_ptr, fw_barker, IWM_HDR_BARKER_LEN)) {
+		IWM_ERR(iwm, "No barker string in this FW\n");
+		return -EINVAL;
+	}
+
+	if (fw->size < IWM_HDR_LEN) {
+		IWM_ERR(iwm, "FW is too small (%d)\n", fw->size);
+		return -EINVAL;
+	}
+
+	fw_offset += IWM_HDR_BARKER_LEN;
+
+	while (fw_offset < fw->size) {
+		rec = (struct iwm_fw_hdr_rec *)(fw_ptr + fw_offset);
+
+		IWM_DBG_FW(iwm, DBG, "FW: op_code: 0x%x, len: %d @ 0x%x\n",
+			   rec->op_code, rec->len, fw_offset);
+
+		if (rec->op_code == IWM_HDR_REC_OP_INVALID) {
+			IWM_DBG_FW(iwm, DBG, "Reached INVALID op code\n");
+			break;
+		}
+
+		if (rec->op_code == op_code) {
+			if (op_index == index) {
+				fw_offset += sizeof(struct iwm_fw_hdr_rec);
+				offset = fw_offset;
+				goto out;
+			}
+			op_index++;
+		}
+
+		fw_offset += sizeof(struct iwm_fw_hdr_rec) + rec->len;
+	}
+
+ out:
+	return offset;
+}
+
+static int iwm_load_firmware_chunk(struct iwm_priv *iwm,
+				   const struct firmware *fw,
+				   struct iwm_fw_img_desc *img_desc)
+{
+	struct iwm_udma_nonwifi_cmd target_cmd;
+	u32 chunk_size;
+	const u8 *chunk_ptr;
+	int ret = 0;
+
+	IWM_DBG_FW(iwm, INFO, "Loading FW chunk: %d bytes @ 0x%x\n",
+		   img_desc->length, img_desc->address);
+
+	target_cmd.opcode = UMAC_HDI_OUT_OPCODE_WRITE;
+	target_cmd.handle_by_hw = 1;
+	target_cmd.op2 = 0;
+	target_cmd.resp = 0;
+	target_cmd.eop = 1;
+
+	chunk_size = img_desc->length;
+	chunk_ptr = fw->data + img_desc->offset;
+
+	while (chunk_size > 0) {
+		u32 tmp_chunk_size;
+
+		tmp_chunk_size = min_t(u32, chunk_size,
+				       IWM_MAX_NONWIFI_CMD_BUFF_SIZE);
+
+		target_cmd.addr = cpu_to_le32(img_desc->address +
+				    (chunk_ptr - fw->data - img_desc->offset));
+		target_cmd.op1_sz = cpu_to_le32(tmp_chunk_size);
+
+		IWM_DBG_FW(iwm, DBG, "\t%d bytes @ 0x%x\n",
+			   tmp_chunk_size, target_cmd.addr);
+
+		ret = iwm_hal_send_target_cmd(iwm, &target_cmd, chunk_ptr);
+		if (ret < 0) {
+			IWM_ERR(iwm, "Couldn't load FW chunk\n");
+			break;
+		}
+
+		chunk_size -= tmp_chunk_size;
+		chunk_ptr += tmp_chunk_size;
+	}
+
+	return ret;
+}
+/*
+ * To load a fw image to the target, we basically go through the
+ * fw, looking for OP_MEM_DESC records. Once we found one, we
+ * pass it to iwm_load_firmware_chunk().
+ * The OP_MEM_DESC records contain the actuall memory chunk to be
+ * sent, but also the destination address.
+ */
+static int iwm_load_img(struct iwm_priv *iwm, const char *img_name)
+{
+	const struct firmware *fw;
+	struct iwm_fw_img_desc *img_desc;
+	struct iwm_fw_img_ver *ver;
+	int ret = 0, fw_offset;
+	u32 opcode_idx = 0, build_date;
+	char *build_tag;
+
+	ret = request_firmware(&fw, img_name, iwm_to_dev(iwm));
+	if (ret) {
+		IWM_ERR(iwm, "Request firmware failed");
+		return ret;
+	}
+
+	IWM_DBG_FW(iwm, INFO, "Start to load FW %s\n", img_name);
+
+	while (1) {
+		fw_offset = iwm_fw_op_offset(iwm, fw,
+					     IWM_HDR_REC_OP_MEM_DESC,
+					     opcode_idx);
+		if (fw_offset < 0)
+			break;
+
+		img_desc = (struct iwm_fw_img_desc *)(fw->data + fw_offset);
+		ret = iwm_load_firmware_chunk(iwm, fw, img_desc);
+		if (ret < 0)
+			goto err_release_fw;
+		opcode_idx++;
+	};
+
+	/* Read firmware version */
+	fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_SW_VER, 0);
+	if (fw_offset < 0)
+		goto err_release_fw;
+
+	ver = (struct iwm_fw_img_ver *)(fw->data + fw_offset);
+
+	/* Read build tag */
+	fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_BUILD_TAG, 0);
+	if (fw_offset < 0)
+		goto err_release_fw;
+
+	build_tag = (char *)(fw->data + fw_offset);
+
+	/* Read build date */
+	fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_BUILD_DATE, 0);
+	if (fw_offset < 0)
+		goto err_release_fw;
+
+	build_date = *(u32 *)(fw->data + fw_offset);
+
+	IWM_INFO(iwm, "%s:\n", img_name);
+	IWM_INFO(iwm, "\tVersion:    %02X.%02X\n", ver->major, ver->minor);
+	IWM_INFO(iwm, "\tBuild tag:  %s\n", build_tag);
+	IWM_INFO(iwm, "\tBuild date: %x-%x-%x\n",
+		 IWM_BUILD_YEAR(build_date), IWM_BUILD_MONTH(build_date),
+		 IWM_BUILD_DAY(build_date));
+
+
+ err_release_fw:
+	release_firmware(fw);
+
+	return ret;
+}
+
+static int iwm_load_umac(struct iwm_priv *iwm)
+{
+	struct iwm_udma_nonwifi_cmd target_cmd;
+	int ret;
+
+	ret = iwm_load_img(iwm, iwm->bus_ops->umac_name);
+	if (ret < 0)
+		return ret;
+
+	/* We've loaded the UMAC, we can tell the target to jump there */
+	target_cmd.opcode = UMAC_HDI_OUT_OPCODE_JUMP;
+	target_cmd.addr = cpu_to_le32(UMAC_MU_FW_INST_DATA_12_ADDR);
+	target_cmd.op1_sz = 0;
+	target_cmd.op2 = 0;
+	target_cmd.handle_by_hw = 0;
+	target_cmd.resp = 1 ;
+	target_cmd.eop = 1;
+
+	ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL);
+	if (ret < 0)
+		IWM_ERR(iwm, "Couldn't send JMP command\n");
+
+	return ret;
+}
+
+static int iwm_load_lmac(struct iwm_priv *iwm, const char *img_name)
+{
+	int ret;
+
+	ret = iwm_load_img(iwm, img_name);
+	if (ret < 0)
+		return ret;
+
+	return iwm_send_umac_reset(iwm,
+			cpu_to_le32(UMAC_RST_CTRL_FLG_LARC_CLK_EN), 0);
+}
+
+/*
+ * We currently have to load 3 FWs:
+ * 1) The UMAC (Upper MAC).
+ * 2) The calibration LMAC (Lower MAC).
+ *    We then send the calibration init command, so that the device can
+ *    run a first calibration round.
+ * 3) The operational LMAC, which replaces the calibration one when it's
+ *    done with the first calibration round.
+ *
+ * Once those 3 FWs have been loaded, we send the periodic calibration
+ * command, and then the device is available for regular 802.11 operations.
+ */
+int iwm_load_fw(struct iwm_priv *iwm)
+{
+	int ret;
+
+	/* We first start downloading the UMAC */
+	ret = iwm_load_umac(iwm);
+	if (ret < 0) {
+		IWM_ERR(iwm, "UMAC loading failed\n");
+		return ret;
+	}
+
+	/* Handle UMAC_ALIVE notification */
+	ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_ALIVE, IWM_SRC_UMAC,
+			       WAIT_NOTIF_TIMEOUT);
+	if (ret) {
+		IWM_ERR(iwm, "Handle UMAC_ALIVE failed: %d\n", ret);
+		return ret;
+	}
+
+	/* UMAC is alive, we can download the calibration LMAC */
+	ret = iwm_load_lmac(iwm, iwm->bus_ops->calib_lmac_name);
+	if (ret) {
+		IWM_ERR(iwm, "Calibration LMAC loading failed\n");
+		return ret;
+	}
+
+	/* Handle UMAC_INIT_COMPLETE notification */
+	ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_INIT_COMPLETE,
+			       IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT);
+	if (ret) {
+		IWM_ERR(iwm, "Handle INIT_COMPLETE failed for calibration "
+			"LMAC: %d\n", ret);
+		return ret;
+	}
+
+	/* Read EEPROM data */
+	ret = iwm_eeprom_init(iwm);
+	if (ret < 0) {
+		IWM_ERR(iwm, "Couldn't init eeprom array\n");
+		return ret;
+	}
+
+#ifdef CONFIG_IWM_B0_HW_SUPPORT
+	if (iwm->conf.hw_b0) {
+		clear_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map);
+		clear_bit(PHY_CALIBRATE_RX_IQ_CMD,
+			  &iwm->conf.periodic_calib_map);
+	}
+#endif
+	/* Read RX IQ calibration result from EEPROM */
+	if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map)) {
+		iwm_store_rxiq_calib_result(iwm);
+		set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map);
+	}
+
+	iwm_send_prio_table(iwm);
+	iwm_send_init_calib_cfg(iwm, iwm->conf.init_calib_map);
+
+	while (iwm->calib_done_map != iwm->conf.init_calib_map) {
+		ret = iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION,
+				       IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT);
+		if (ret) {
+			IWM_ERR(iwm, "Wait for calibration result timeout\n");
+			goto out;
+		}
+		IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: "
+			   "0x%lx, requested calibrations: 0x%lx\n",
+			   iwm->calib_done_map, iwm->conf.init_calib_map);
+	}
+
+	/* Handle LMAC CALIBRATION_COMPLETE notification */
+	ret = iwm_notif_handle(iwm, CALIBRATION_COMPLETE_NOTIFICATION,
+			       IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT);
+	if (ret) {
+		IWM_ERR(iwm, "Wait for CALIBRATION_COMPLETE timeout\n");
+		goto out;
+	}
+
+	IWM_INFO(iwm, "LMAC calibration done: 0x%lx\n", iwm->calib_done_map);
+
+	iwm_send_umac_reset(iwm, cpu_to_le32(UMAC_RST_CTRL_FLG_LARC_RESET), 1);
+
+	ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_RESET, IWM_SRC_UMAC,
+			       WAIT_NOTIF_TIMEOUT);
+	if (ret) {
+		IWM_ERR(iwm, "Wait for UMAC RESET timeout\n");
+		goto out;
+	}
+
+	/* Download the operational LMAC */
+	ret = iwm_load_lmac(iwm, iwm->bus_ops->lmac_name);
+	if (ret) {
+		IWM_ERR(iwm, "LMAC loading failed\n");
+		goto out;
+	}
+
+	ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_INIT_COMPLETE,
+			       IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT);
+	if (ret) {
+		IWM_ERR(iwm, "Handle INIT_COMPLETE failed for LMAC: %d\n", ret);
+		goto out;
+	}
+
+	iwm_send_prio_table(iwm);
+	iwm_send_calib_results(iwm);
+	iwm_send_periodic_calib_cfg(iwm, iwm->conf.periodic_calib_map);
+
+	return 0;
+
+ out:
+	iwm_eeprom_exit(iwm);
+	return ret;
+}
diff --git a/drivers/net/wireless/iwmc3200wifi/fw.h b/drivers/net/wireless/iwmc3200wifi/fw.h
new file mode 100644
index 0000000..c70a3b4
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/fw.h
@@ -0,0 +1,100 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ *
+ * Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ */
+
+#ifndef __IWM_FW_H__
+#define __IWM_FW_H__
+
+/**
+ * struct iwm_fw_hdr_rec - An iwm firmware image is a
+ * concatenation of various records. Each of them is
+ * defined by an ID (aka op code), a length, and the
+ * actual data.
+ * @op_code: The record ID, see IWM_HDR_REC_OP_*
+ *
+ * @len: The record payload length
+ *
+ * @buf: The record payload
+ */
+struct iwm_fw_hdr_rec {
+	u16 op_code;
+	u16 len;
+	u8 buf[0];
+};
+
+/* Header's definitions */
+#define IWM_HDR_LEN                          (512)
+#define IWM_HDR_BARKER_LEN                   (16)
+
+/* Header's opcodes */
+#define IWM_HDR_REC_OP_INVALID             (0x00)
+#define IWM_HDR_REC_OP_BUILD_DATE          (0x01)
+#define IWM_HDR_REC_OP_BUILD_TAG           (0x02)
+#define IWM_HDR_REC_OP_SW_VER              (0x03)
+#define IWM_HDR_REC_OP_HW_SKU              (0x04)
+#define IWM_HDR_REC_OP_BUILD_OPT           (0x05)
+#define IWM_HDR_REC_OP_MEM_DESC            (0x06)
+#define IWM_HDR_REC_USERDEFS               (0x07)
+
+/* Header's records length (in bytes) */
+#define IWM_HDR_REC_LEN_BUILD_DATE           (4)
+#define IWM_HDR_REC_LEN_BUILD_TAG            (64)
+#define IWM_HDR_REC_LEN_SW_VER               (4)
+#define IWM_HDR_REC_LEN_HW_SKU               (4)
+#define IWM_HDR_REC_LEN_BUILD_OPT            (4)
+#define IWM_HDR_REC_LEN_MEM_DESC             (12)
+#define IWM_HDR_REC_LEN_USERDEF              (64)
+
+#define IWM_BUILD_YEAR(date) ((date >> 16) & 0xffff)
+#define IWM_BUILD_MONTH(date) ((date >> 8) & 0xff)
+#define IWM_BUILD_DAY(date) (date & 0xff)
+
+struct iwm_fw_img_desc {
+	u32 offset;
+	u32 address;
+	u32 length;
+};
+
+struct iwm_fw_img_ver {
+	u8 minor;
+	u8 major;
+	u16 reserved;
+};
+
+int iwm_load_fw(struct iwm_priv *iwm);
+
+#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/hal.c b/drivers/net/wireless/iwmc3200wifi/hal.c
new file mode 100644
index 0000000..ee127fe
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/hal.c
@@ -0,0 +1,464 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ *
+ * Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ */
+
+/*
+ * Hardware Abstraction Layer for iwm.
+ *
+ * This file mostly defines an abstraction API for
+ * sending various commands to the target.
+ *
+ * We have 2 types of commands: wifi and non-wifi ones.
+ *
+ * - wifi commands:
+ *   They are used for sending LMAC and UMAC commands,
+ *   and thus are the most commonly used ones.
+ *   There are 2 different wifi command types, the regular
+ *   one and the LMAC one. The former is used to send
+ *   UMAC commands (see UMAC_CMD_OPCODE_* from umac.h)
+ *   while the latter is used for sending commands to the
+ *   LMAC. If you look at LMAC commands you'll se that they
+ *   are actually regular iwlwifi target commands encapsulated
+ *   into a special UMAC command called UMAC passthrough.
+ *   This is due to the fact the the host talks exclusively
+ *   to the UMAC and so there needs to be a special UMAC
+ *   command for talking to the LMAC.
+ *   This is how a wifi command is layed out:
+ *    ------------------------
+ *   | iwm_udma_out_wifi_hdr  |
+ *    ------------------------
+ *   | SW meta_data (32 bits) |
+ *    ------------------------
+ *   | iwm_dev_cmd_hdr        |
+ *    ------------------------
+ *   | payload                |
+ *   | ....                   |
+ *
+ * - non-wifi, or general commands:
+ *   Those commands are handled by the device's bootrom,
+ *   and are typically sent when the UMAC and the LMAC
+ *   are not yet available.
+ *    *   This is how a non-wifi command is layed out:
+ *    ---------------------------
+ *   | iwm_udma_out_nonwifi_hdr  |
+ *    ---------------------------
+ *   | payload                   |
+ *   | ....                      |
+
+ *
+ * All the commands start with a UDMA header, which is
+ * basically a 32 bits field. The 4 LSB there define
+ * an opcode that allows the target to differentiate
+ * between wifi (opcode is 0xf) and non-wifi commands
+ * (opcode is [0..0xe]).
+ *
+ * When a command (wifi or non-wifi) is supposed to receive
+ * an answer, we queue the command buffer. When we do receive
+ * a command response from the UMAC, we go through the list
+ * of pending command, and pass both the command and the answer
+ * to the rx handler. Each command is sent with a unique
+ * sequence id, and the answer is sent with the same one. This
+ * is how we're supposed to match an answer with its command.
+ * See rx.c:iwm_rx_handle_[non]wifi() and iwm_get_pending_[non]wifi()
+ * for the implementation details.
+ */
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+
+#include "iwm.h"
+#include "bus.h"
+#include "hal.h"
+#include "umac.h"
+#include "debug.h"
+
+static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
+				 struct iwm_nonwifi_cmd *cmd,
+				 struct iwm_udma_nonwifi_cmd *udma_cmd)
+{
+	INIT_LIST_HEAD(&cmd->pending);
+
+	spin_lock(&iwm->cmd_lock);
+
+	cmd->resp_received = 0;
+
+	cmd->seq_num = iwm->nonwifi_seq_num;
+	udma_cmd->seq_num = cpu_to_le16(cmd->seq_num);
+
+	cmd->seq_num = iwm->nonwifi_seq_num++;
+	iwm->nonwifi_seq_num %= UMAC_NONWIFI_SEQ_NUM_MAX;
+
+	if (udma_cmd->resp)
+		list_add_tail(&cmd->pending, &iwm->nonwifi_pending_cmd);
+
+	spin_unlock(&iwm->cmd_lock);
+
+	cmd->buf.start = cmd->buf.payload;
+	cmd->buf.len = 0;
+
+	memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd));
+}
+
+u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm)
+{
+	u16 seq_num = iwm->wifi_seq_num;
+
+	iwm->wifi_seq_num++;
+	iwm->wifi_seq_num %= UMAC_WIFI_SEQ_NUM_MAX;
+
+	return seq_num;
+}
+
+static void iwm_wifi_cmd_init(struct iwm_priv *iwm,
+			      struct iwm_wifi_cmd *cmd,
+			      struct iwm_udma_wifi_cmd *udma_cmd,
+			      struct iwm_umac_cmd *umac_cmd,
+			      struct iwm_lmac_cmd *lmac_cmd,
+			      u16 payload_size)
+{
+	INIT_LIST_HEAD(&cmd->pending);
+
+	spin_lock(&iwm->cmd_lock);
+
+	cmd->seq_num = iwm_alloc_wifi_cmd_seq(iwm);
+	umac_cmd->seq_num = cpu_to_le16(cmd->seq_num);
+
+	if (umac_cmd->resp)
+		list_add_tail(&cmd->pending, &iwm->wifi_pending_cmd);
+
+	spin_unlock(&iwm->cmd_lock);
+
+	cmd->buf.start = cmd->buf.payload;
+	cmd->buf.len = 0;
+
+	if (lmac_cmd) {
+		cmd->buf.start -= sizeof(struct iwm_lmac_hdr);
+
+		lmac_cmd->seq_num = cpu_to_le16(cmd->seq_num);
+		lmac_cmd->count = cpu_to_le16(payload_size);
+
+		memcpy(&cmd->lmac_cmd, lmac_cmd, sizeof(*lmac_cmd));
+
+		umac_cmd->count = cpu_to_le16(sizeof(struct iwm_lmac_hdr));
+	} else
+		umac_cmd->count = 0;
+
+	umac_cmd->count = cpu_to_le16(payload_size +
+				      le16_to_cpu(umac_cmd->count));
+	udma_cmd->count = cpu_to_le16(sizeof(struct iwm_umac_fw_cmd_hdr) +
+				      le16_to_cpu(umac_cmd->count));
+
+	memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd));
+	memcpy(&cmd->umac_cmd, umac_cmd, sizeof(*umac_cmd));
+}
+
+void iwm_cmd_flush(struct iwm_priv *iwm)
+{
+	struct iwm_wifi_cmd *wcmd, *wnext;
+	struct iwm_nonwifi_cmd *nwcmd, *nwnext;
+
+	list_for_each_entry_safe(wcmd, wnext, &iwm->wifi_pending_cmd, pending) {
+		list_del(&wcmd->pending);
+		kfree(wcmd);
+	}
+
+	list_for_each_entry_safe(nwcmd, nwnext, &iwm->nonwifi_pending_cmd,
+				 pending) {
+		list_del(&nwcmd->pending);
+		kfree(nwcmd);
+	}
+}
+
+struct iwm_wifi_cmd *iwm_get_pending_wifi_cmd(struct iwm_priv *iwm, u16 seq_num)
+{
+	struct iwm_wifi_cmd *cmd, *next;
+
+	list_for_each_entry_safe(cmd, next, &iwm->wifi_pending_cmd, pending)
+		if (cmd->seq_num == seq_num) {
+			list_del(&cmd->pending);
+			return cmd;
+		}
+
+	return NULL;
+}
+
+struct iwm_nonwifi_cmd *
+iwm_get_pending_nonwifi_cmd(struct iwm_priv *iwm, u8 seq_num, u8 cmd_opcode)
+{
+	struct iwm_nonwifi_cmd *cmd, *next;
+
+	list_for_each_entry_safe(cmd, next, &iwm->nonwifi_pending_cmd, pending)
+		if ((cmd->seq_num == seq_num) &&
+		    (cmd->udma_cmd.opcode == cmd_opcode) &&
+		    (cmd->resp_received)) {
+			list_del(&cmd->pending);
+			return cmd;
+		}
+
+	return NULL;
+}
+
+static void iwm_build_udma_nonwifi_hdr(struct iwm_priv *iwm,
+				       struct iwm_udma_out_nonwifi_hdr *hdr,
+				       struct iwm_udma_nonwifi_cmd *cmd)
+{
+	memset(hdr, 0, sizeof(*hdr));
+
+	SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE, cmd->opcode);
+	SET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_RESP, cmd->resp);
+	SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, 1);
+	SET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW,
+		  cmd->handle_by_hw);
+	SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_SIGNATURE, UMAC_HDI_OUT_SIGNATURE);
+	SET_VAL32(hdr->cmd, UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM,
+		  le16_to_cpu(cmd->seq_num));
+
+	hdr->addr = cmd->addr;
+	hdr->op1_sz = cmd->op1_sz;
+	hdr->op2 = cmd->op2;
+}
+
+static int iwm_send_udma_nonwifi_cmd(struct iwm_priv *iwm,
+				     struct iwm_nonwifi_cmd *cmd)
+{
+	struct iwm_udma_out_nonwifi_hdr *udma_hdr;
+	struct iwm_nonwifi_cmd_buff *buf;
+	struct iwm_udma_nonwifi_cmd *udma_cmd = &cmd->udma_cmd;
+
+	buf = &cmd->buf;
+
+	buf->start -= sizeof(struct iwm_umac_nonwifi_out_hdr);
+	buf->len += sizeof(struct iwm_umac_nonwifi_out_hdr);
+
+	udma_hdr = (struct iwm_udma_out_nonwifi_hdr *)(buf->start);
+
+	iwm_build_udma_nonwifi_hdr(iwm, udma_hdr, udma_cmd);
+
+	IWM_DBG_CMD(iwm, DBG,
+		    "Send UDMA nonwifi cmd: opcode = 0x%x, resp = 0x%x, "
+		    "hw = 0x%x, seqnum = %d, addr = 0x%x, op1_sz = 0x%x, "
+		    "op2 = 0x%x\n", udma_cmd->opcode, udma_cmd->resp,
+		    udma_cmd->handle_by_hw, cmd->seq_num, udma_cmd->addr,
+		    udma_cmd->op1_sz, udma_cmd->op2);
+
+	return iwm_bus_send_chunk(iwm, buf->start, buf->len);
+}
+
+void iwm_udma_wifi_hdr_set_eop(struct iwm_priv *iwm, u8 *buf, u8 eop)
+{
+	struct iwm_udma_out_wifi_hdr *hdr = (struct iwm_udma_out_wifi_hdr *)buf;
+
+	SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, eop);
+}
+
+void iwm_build_udma_wifi_hdr(struct iwm_priv *iwm,
+			     struct iwm_udma_out_wifi_hdr *hdr,
+			     struct iwm_udma_wifi_cmd *cmd)
+{
+	memset(hdr, 0, sizeof(*hdr));
+
+	SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE, UMAC_HDI_OUT_OPCODE_WIFI);
+	SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, cmd->eop);
+	SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_SIGNATURE, UMAC_HDI_OUT_SIGNATURE);
+
+	SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_BYTE_COUNT,
+		  le16_to_cpu(cmd->count));
+	SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_CREDIT_GRP, cmd->credit_group);
+	SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_RATID, cmd->ra_tid);
+	SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_LMAC_OFFSET, cmd->lmac_offset);
+}
+
+void iwm_build_umac_hdr(struct iwm_priv *iwm,
+			struct iwm_umac_fw_cmd_hdr *hdr,
+			struct iwm_umac_cmd *cmd)
+{
+	memset(hdr, 0, sizeof(*hdr));
+
+	SET_VAL32(hdr->meta_data, UMAC_FW_CMD_BYTE_COUNT,
+		  le16_to_cpu(cmd->count));
+	SET_VAL32(hdr->meta_data, UMAC_FW_CMD_TX_STA_COLOR, cmd->color);
+	SET_VAL8(hdr->cmd.flags, UMAC_DEV_CMD_FLAGS_RESP_REQ, cmd->resp);
+
+	hdr->cmd.cmd = cmd->id;
+	hdr->cmd.seq_num = cmd->seq_num;
+}
+
+static int iwm_send_udma_wifi_cmd(struct iwm_priv *iwm,
+				  struct iwm_wifi_cmd *cmd)
+{
+	struct iwm_umac_wifi_out_hdr *umac_hdr;
+	struct iwm_wifi_cmd_buff *buf;
+	struct iwm_udma_wifi_cmd *udma_cmd = &cmd->udma_cmd;
+	struct iwm_umac_cmd *umac_cmd = &cmd->umac_cmd;
+	int ret;
+
+	buf = &cmd->buf;
+
+	buf->start -= sizeof(struct iwm_umac_wifi_out_hdr);
+	buf->len += sizeof(struct iwm_umac_wifi_out_hdr);
+
+	umac_hdr = (struct iwm_umac_wifi_out_hdr *)(buf->start);
+
+	iwm_build_udma_wifi_hdr(iwm, &umac_hdr->hw_hdr, udma_cmd);
+	iwm_build_umac_hdr(iwm, &umac_hdr->sw_hdr, umac_cmd);
+
+	IWM_DBG_CMD(iwm, DBG,
+		    "Send UDMA wifi cmd: opcode = 0x%x, UMAC opcode = 0x%x, "
+		    "eop = 0x%x, count = 0x%x, credit_group = 0x%x, "
+		    "ra_tid = 0x%x, lmac_offset = 0x%x, seqnum = %d\n",
+		    UMAC_HDI_OUT_OPCODE_WIFI, umac_cmd->id,
+		    udma_cmd->eop, udma_cmd->count, udma_cmd->credit_group,
+		    udma_cmd->ra_tid, udma_cmd->lmac_offset, cmd->seq_num);
+
+	if (umac_cmd->id == UMAC_CMD_OPCODE_WIFI_PASS_THROUGH)
+		IWM_DBG_CMD(iwm, DBG, "\tLMAC opcode: 0x%x\n",
+			    cmd->lmac_cmd.id);
+
+	ret = iwm_tx_credit_alloc(iwm, udma_cmd->credit_group, buf->len);
+
+	/* We keep sending UMAC reset regardless of the command credits.
+	 * The UMAC is supposed to be reset anyway and the Tx credits are
+	 * reinitialized afterwards. If we are lucky, the reset could
+	 * still be done even though we have run out of credits for the
+	 * command pool at this moment.*/
+	if (ret && (umac_cmd->id != UMAC_CMD_OPCODE_RESET)) {
+		IWM_DBG_TX(iwm, DBG, "Failed to alloc tx credit for cmd %d\n",
+			   umac_cmd->id);
+		return ret;
+	}
+
+	return iwm_bus_send_chunk(iwm, buf->start, buf->len);
+}
+
+/* target_cmd a.k.a udma_nonwifi_cmd can be sent when UMAC is not available */
+int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
+			    struct iwm_udma_nonwifi_cmd *udma_cmd,
+			    const void *payload)
+{
+	struct iwm_nonwifi_cmd *cmd;
+	int ret;
+
+	cmd = kzalloc(sizeof(struct iwm_nonwifi_cmd), GFP_KERNEL);
+	if (!cmd) {
+		IWM_ERR(iwm, "Couldn't alloc memory for hal cmd\n");
+		return -ENOMEM;
+	}
+
+	iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd);
+
+	if (cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE ||
+	    cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT) {
+		cmd->buf.len = le32_to_cpu(cmd->udma_cmd.op1_sz);
+		memcpy(&cmd->buf.payload, payload, cmd->buf.len);
+	}
+
+	ret = iwm_send_udma_nonwifi_cmd(iwm, cmd);
+
+	if (!udma_cmd->resp)
+		kfree(cmd);
+
+	if (ret < 0)
+		return ret;
+
+	return cmd->seq_num;
+}
+
+static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr,
+			       struct iwm_lmac_cmd *cmd)
+{
+	memset(hdr, 0, sizeof(*hdr));
+
+	hdr->id = cmd->id;
+	hdr->flags = 0; /* Is this ever used? */
+	hdr->seq_num = cmd->seq_num;
+}
+
+/*
+ * iwm_hal_send_host_cmd(): sends commands to the UMAC or the LMAC.
+ * Sending command to the LMAC is equivalent to sending a
+ * regular UMAC command with the LMAC passtrough or the LMAC
+ * wrapper UMAC command IDs.
+ */
+int iwm_hal_send_host_cmd(struct iwm_priv *iwm,
+			  struct iwm_udma_wifi_cmd *udma_cmd,
+			  struct iwm_umac_cmd *umac_cmd,
+			  struct iwm_lmac_cmd *lmac_cmd,
+			  const void *payload, u16 payload_size)
+{
+	struct iwm_wifi_cmd *cmd;
+	struct iwm_lmac_hdr *hdr;
+	int lmac_hdr_len = 0;
+	int ret;
+
+	cmd = kzalloc(sizeof(struct iwm_wifi_cmd), GFP_KERNEL);
+	if (!cmd) {
+		IWM_ERR(iwm, "Couldn't alloc memory for wifi hal cmd\n");
+		return -ENOMEM;
+	}
+
+	iwm_wifi_cmd_init(iwm, cmd, udma_cmd, umac_cmd, lmac_cmd, payload_size);
+
+	if (lmac_cmd) {
+		hdr = (struct iwm_lmac_hdr *)(cmd->buf.start);
+
+		iwm_build_lmac_hdr(iwm, hdr, &cmd->lmac_cmd);
+		lmac_hdr_len = sizeof(struct iwm_lmac_hdr);
+	}
+
+	memcpy(cmd->buf.payload, payload, payload_size);
+	cmd->buf.len = le16_to_cpu(umac_cmd->count);
+
+	ret = iwm_send_udma_wifi_cmd(iwm, cmd);
+
+	/* We free the cmd if we're not expecting any response */
+	if (!umac_cmd->resp)
+		kfree(cmd);
+	return ret;
+}
+
+/*
+ * iwm_hal_send_umac_cmd(): This is a special case for
+ * iwm_hal_send_host_cmd() to send direct UMAC cmd (without
+ * LMAC involved).
+ */
+int iwm_hal_send_umac_cmd(struct iwm_priv *iwm,
+			  struct iwm_udma_wifi_cmd *udma_cmd,
+			  struct iwm_umac_cmd *umac_cmd,
+			  const void *payload, u16 payload_size)
+{
+	return iwm_hal_send_host_cmd(iwm, udma_cmd, umac_cmd, NULL,
+				     payload, payload_size);
+}
diff --git a/drivers/net/wireless/iwmc3200wifi/hal.h b/drivers/net/wireless/iwmc3200wifi/hal.h
new file mode 100644
index 0000000..0adfdc8
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/hal.h
@@ -0,0 +1,236 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ *
+ * Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ */
+
+#ifndef _IWM_HAL_H_
+#define _IWM_HAL_H_
+
+#include "umac.h"
+
+#define GET_VAL8(s, name)	((s >> name##_POS) & name##_SEED)
+#define GET_VAL16(s, name)	((le16_to_cpu(s) >> name##_POS) & name##_SEED)
+#define GET_VAL32(s, name)	((le32_to_cpu(s) >> name##_POS) & name##_SEED)
+
+#define SET_VAL8(s, name, val)						  \
+do {									  \
+	s = (s & ~(name##_SEED << name##_POS)) |			  \
+	    ((val & name##_SEED) << name##_POS);			  \
+} while (0)
+
+#define SET_VAL16(s, name, val)						  \
+do {									  \
+	s = cpu_to_le16((le16_to_cpu(s) & ~(name##_SEED << name##_POS)) | \
+			((val & name##_SEED) << name##_POS));		  \
+} while (0)
+
+#define SET_VAL32(s, name, val)						  \
+do {									  \
+	s = cpu_to_le32((le32_to_cpu(s) & ~(name##_SEED << name##_POS)) | \
+			((val & name##_SEED) << name##_POS));		  \
+} while (0)
+
+
+#define UDMA_UMAC_INIT	{	.eop = 1,				  \
+				.credit_group = 0x4,			  \
+				.ra_tid = UMAC_HDI_ACT_TBL_IDX_HOST_CMD,  \
+				.lmac_offset = 0 }
+#define UDMA_LMAC_INIT	{	.eop = 1,				  \
+				.credit_group = 0x4,			  \
+				.ra_tid = UMAC_HDI_ACT_TBL_IDX_HOST_CMD,  \
+				.lmac_offset = 4 }
+
+
+/* UDMA IN OP CODE -- cmd bits [3:0] */
+#define UDMA_IN_OPCODE_MASK			0xF
+
+#define UDMA_IN_OPCODE_GENERAL_RESP		0x0
+#define UDMA_IN_OPCODE_READ_RESP		0x1
+#define UDMA_IN_OPCODE_WRITE_RESP		0x2
+#define UDMA_IN_OPCODE_PERS_WRITE_RESP		0x5
+#define UDMA_IN_OPCODE_PERS_READ_RESP		0x6
+#define UDMA_IN_OPCODE_RD_MDFY_WR_RESP		0x7
+#define UDMA_IN_OPCODE_EP_MNGMT_MSG		0x8
+#define UDMA_IN_OPCODE_CRDT_CHNG_MSG		0x9
+#define UDMA_IN_OPCODE_CNTRL_DATABASE_MSG	0xA
+#define UDMA_IN_OPCODE_SW_MSG			0xB
+#define UDMA_IN_OPCODE_WIFI			0xF
+#define UDMA_IN_OPCODE_WIFI_LMAC		0x1F
+#define UDMA_IN_OPCODE_WIFI_UMAC		0x2F
+
+/* HW API: udma_hdi_nonwifi API (OUT and IN) */
+
+/* iwm_udma_nonwifi_cmd request response -- bits [9:9] */
+#define UDMA_HDI_OUT_NW_CMD_RESP_POS		9
+#define UDMA_HDI_OUT_NW_CMD_RESP_SEED		0x1
+
+/* iwm_udma_nonwifi_cmd handle by HW -- bits [11:11] */
+#define UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW_POS	11
+#define UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW_SEED	0x1
+
+/* iwm_udma_nonwifi_cmd sequence-number -- bits [12:15] */
+#define UDMA_HDI_OUT_NW_CMD_SEQ_NUM_POS		12
+#define UDMA_HDI_OUT_NW_CMD_SEQ_NUM_SEED	0xF
+
+/* UDMA IN Non-WIFI HW sequence number -- bits [12:15] */
+#define UDMA_IN_NW_HW_SEQ_NUM_POS		12
+#define UDMA_IN_NW_HW_SEQ_NUM_SEED		0xF
+
+/* UDMA IN Non-WIFI HW signature -- bits [16:31] */
+#define UDMA_IN_NW_HW_SIG_POS			16
+#define UDMA_IN_NW_HW_SIG_SEED			0xFFFF
+
+/* fixed signature */
+#define UDMA_IN_NW_HW_SIG			0xCBBC
+
+/* UDMA IN Non-WIFI HW block length -- bits [32:35] */
+#define UDMA_IN_NW_HW_LENGTH_SEED		0xF
+#define UDMA_IN_NW_HW_LENGTH_POS		32
+
+/* End of HW API: udma_hdi_nonwifi API (OUT and IN) */
+
+#define IWM_SDIO_FW_MAX_CHUNK_SIZE	2032
+#define IWM_MAX_WIFI_HEADERS_SIZE	32
+#define IWM_MAX_NONWIFI_HEADERS_SIZE	16
+#define IWM_MAX_NONWIFI_CMD_BUFF_SIZE	(IWM_SDIO_FW_MAX_CHUNK_SIZE - \
+					 IWM_MAX_NONWIFI_HEADERS_SIZE)
+#define IWM_MAX_WIFI_CMD_BUFF_SIZE	(IWM_SDIO_FW_MAX_CHUNK_SIZE - \
+					 IWM_MAX_WIFI_HEADERS_SIZE)
+
+#define IWM_HAL_CONCATENATE_BUF_SIZE	8192
+
+struct iwm_wifi_cmd_buff {
+	u16 len;
+	u8 *start;
+	u8 hdr[IWM_MAX_WIFI_HEADERS_SIZE];
+	u8 payload[IWM_MAX_WIFI_CMD_BUFF_SIZE];
+};
+
+struct iwm_nonwifi_cmd_buff {
+	u16 len;
+	u8 *start;
+	u8 hdr[IWM_MAX_NONWIFI_HEADERS_SIZE];
+	u8 payload[IWM_MAX_NONWIFI_CMD_BUFF_SIZE];
+};
+
+struct iwm_udma_nonwifi_cmd {
+	u8 opcode;
+	u8 eop;
+	u8 resp;
+	u8 handle_by_hw;
+	__le32 addr;
+	__le32 op1_sz;
+	__le32 op2;
+	__le16 seq_num;
+};
+
+struct iwm_udma_wifi_cmd {
+	__le16 count;
+	u8 eop;
+	u8 credit_group;
+	u8 ra_tid;
+	u8 lmac_offset;
+};
+
+struct iwm_umac_cmd {
+	u8 id;
+	__le16 count;
+	u8 resp;
+	__le16 seq_num;
+	u8 color;
+};
+
+struct iwm_lmac_cmd {
+	u8 id;
+	__le16 count;
+	u8 resp;
+	__le16 seq_num;
+};
+
+struct iwm_nonwifi_cmd {
+	u16 seq_num;
+	bool resp_received;
+	struct list_head pending;
+	struct iwm_udma_nonwifi_cmd udma_cmd;
+	struct iwm_umac_cmd umac_cmd;
+	struct iwm_lmac_cmd lmac_cmd;
+	struct iwm_nonwifi_cmd_buff buf;
+	u32 flags;
+};
+
+struct iwm_wifi_cmd {
+	u16 seq_num;
+	struct list_head pending;
+	struct iwm_udma_wifi_cmd udma_cmd;
+	struct iwm_umac_cmd umac_cmd;
+	struct iwm_lmac_cmd lmac_cmd;
+	struct iwm_wifi_cmd_buff buf;
+	u32 flags;
+};
+
+void iwm_cmd_flush(struct iwm_priv *iwm);
+
+struct iwm_wifi_cmd *iwm_get_pending_wifi_cmd(struct iwm_priv *iwm,
+					      u16 seq_num);
+struct iwm_nonwifi_cmd *iwm_get_pending_nonwifi_cmd(struct iwm_priv *iwm,
+						    u8 seq_num, u8 cmd_opcode);
+
+
+int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
+			    struct iwm_udma_nonwifi_cmd *ucmd,
+			    const void *payload);
+
+int iwm_hal_send_host_cmd(struct iwm_priv *iwm,
+			  struct iwm_udma_wifi_cmd *udma_cmd,
+			  struct iwm_umac_cmd *umac_cmd,
+			  struct iwm_lmac_cmd *lmac_cmd,
+			  const void *payload, u16 payload_size);
+
+int iwm_hal_send_umac_cmd(struct iwm_priv *iwm,
+			  struct iwm_udma_wifi_cmd *udma_cmd,
+			  struct iwm_umac_cmd *umac_cmd,
+			  const void *payload, u16 payload_size);
+
+u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm);
+
+void iwm_udma_wifi_hdr_set_eop(struct iwm_priv *iwm, u8 *buf, u8 eop);
+void iwm_build_udma_wifi_hdr(struct iwm_priv *iwm,
+			     struct iwm_udma_out_wifi_hdr *hdr,
+			     struct iwm_udma_wifi_cmd *cmd);
+void iwm_build_umac_hdr(struct iwm_priv *iwm,
+			struct iwm_umac_fw_cmd_hdr *hdr,
+			struct iwm_umac_cmd *cmd);
+#endif /* _IWM_HAL_H_ */
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
new file mode 100644
index 0000000..3b29681
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h
@@ -0,0 +1,350 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ *
+ * Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ */
+
+#ifndef __IWM_H__
+#define __IWM_H__
+
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <net/cfg80211.h>
+
+#include "debug.h"
+#include "hal.h"
+#include "umac.h"
+#include "lmac.h"
+#include "eeprom.h"
+
+#define IWM_COPYRIGHT "Copyright(c) 2009 Intel Corporation"
+#define IWM_AUTHOR "<ilw@linux.intel.com>"
+
+#define CONFIG_IWM_B0_HW_SUPPORT	1
+
+#define IWM_SRC_LMAC	UMAC_HDI_IN_SOURCE_FHRX
+#define IWM_SRC_UDMA	UMAC_HDI_IN_SOURCE_UDMA
+#define IWM_SRC_UMAC	UMAC_HDI_IN_SOURCE_FW
+#define IWM_SRC_NUM	3
+
+#define IWM_POWER_INDEX_MIN	0
+#define IWM_POWER_INDEX_MAX	5
+#define IWM_POWER_INDEX_DEFAULT	3
+
+struct iwm_conf {
+	u32 sdio_ior_timeout;
+	unsigned long init_calib_map;
+	unsigned long periodic_calib_map;
+	bool reset_on_fatal_err;
+	bool auto_connect;
+	bool wimax_not_present;
+	bool enable_qos;
+	u32 mode;
+
+	u32 power_index;
+	u32 frag_threshold;
+	u32 rts_threshold;
+	bool cts_to_self;
+
+	u32 assoc_timeout;
+	u32 roam_timeout;
+	u32 wireless_mode;
+	u32 coexist_mode;
+
+	u8 ibss_band;
+	u8 ibss_channel;
+
+	u8 mac_addr[ETH_ALEN];
+#ifdef CONFIG_IWM_B0_HW_SUPPORT
+	bool hw_b0;
+#endif
+};
+
+enum {
+	COEX_MODE_SA = 1,
+	COEX_MODE_XOR,
+	COEX_MODE_CM,
+	COEX_MODE_MAX,
+};
+
+struct iwm_if_ops;
+struct iwm_wifi_cmd;
+
+struct pool_entry {
+	int id;		/* group id */
+	int sid;	/* super group id */
+	int min_pages;	/* min capacity in pages */
+	int max_pages;	/* max capacity in pages */
+	int alloc_pages;	/* allocated # of pages. incresed by driver */
+	int total_freed_pages;	/* total freed # of pages. incresed by UMAC */
+};
+
+struct spool_entry {
+	int id;
+	int max_pages;
+	int alloc_pages;
+};
+
+struct iwm_tx_credit {
+	spinlock_t lock;
+	int pool_nr;
+	unsigned long full_pools_map; /* bitmap for # of filled tx pools */
+	struct pool_entry pools[IWM_MACS_OUT_GROUPS];
+	struct spool_entry spools[IWM_MACS_OUT_SGROUPS];
+};
+
+struct iwm_notif {
+	struct list_head pending;
+	u32 cmd_id;
+	void *cmd;
+	u8 src;
+	void *buf;
+	unsigned long buf_size;
+};
+
+struct iwm_sta_info {
+	u8 addr[ETH_ALEN];
+	bool valid;
+	bool qos;
+	u8 color;
+};
+
+struct iwm_tx_info {
+	u8 sta;
+	u8 color;
+	u8 tid;
+};
+
+struct iwm_rx_info {
+	unsigned long rx_size;
+	unsigned long rx_buf_size;
+};
+
+#define IWM_NUM_KEYS 4
+
+struct iwm_umac_key_hdr {
+	u8 mac[ETH_ALEN];
+	u8 key_idx;
+	u8 multicast; /* BCast encrypt & BCast decrypt of frames FROM mac */
+} __attribute__ ((packed));
+
+struct iwm_key {
+	struct iwm_umac_key_hdr hdr;
+	u8 in_use;
+	u8 alg;
+	u32 flags;
+	u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE];
+	u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE];
+	u8 key_len;
+	u8 key[32];
+};
+
+#define IWM_RX_ID_HASH  0xff
+#define IWM_RX_ID_GET_HASH(id) ((id) % IWM_RX_ID_HASH)
+
+#define IWM_STA_TABLE_NUM	16
+#define IWM_TX_LIST_SIZE	64
+#define IWM_RX_LIST_SIZE        256
+
+#define IWM_SCAN_ID_MAX 0xff
+
+#define IWM_STATUS_READY		0
+#define IWM_STATUS_SCANNING		1
+#define IWM_STATUS_SCAN_ABORTING	2
+#define IWM_STATUS_ASSOCIATING		3
+#define IWM_STATUS_ASSOCIATED		4
+
+#define IWM_RADIO_RFKILL_OFF		0
+#define IWM_RADIO_RFKILL_HW		1
+#define IWM_RADIO_RFKILL_SW		2
+
+struct iwm_tx_queue {
+	int id;
+	struct sk_buff_head queue;
+	struct workqueue_struct *wq;
+	struct work_struct worker;
+	u8 concat_buf[IWM_HAL_CONCATENATE_BUF_SIZE];
+	int concat_count;
+	u8 *concat_ptr;
+};
+
+/* Queues 0 ~ 3 for AC data, 5 for iPAN */
+#define IWM_TX_QUEUES		5
+#define IWM_TX_DATA_QUEUES	4
+#define IWM_TX_CMD_QUEUE	4
+
+struct iwm_bss_info {
+	struct list_head node;
+	struct cfg80211_bss *cfg_bss;
+	struct iwm_umac_notif_bss_info *bss;
+};
+
+typedef int (*iwm_handler)(struct iwm_priv *priv, u8 *buf,
+			   unsigned long buf_size, struct iwm_wifi_cmd *cmd);
+
+#define IWM_WATCHDOG_PERIOD	(6 * HZ)
+
+struct iwm_priv {
+	struct wireless_dev *wdev;
+	struct iwm_if_ops *bus_ops;
+
+	struct iwm_conf conf;
+
+	unsigned long status;
+	unsigned long radio;
+
+	struct list_head pending_notif;
+	wait_queue_head_t notif_queue;
+
+	wait_queue_head_t nonwifi_queue;
+
+	unsigned long calib_done_map;
+	struct {
+		u8 *buf;
+		u32 size;
+	} calib_res[CALIBRATION_CMD_NUM];
+
+	struct iwm_umac_profile *umac_profile;
+	bool umac_profile_active;
+
+	u8 bssid[ETH_ALEN];
+	u8 channel;
+	u16 rate;
+
+	struct iwm_sta_info sta_table[IWM_STA_TABLE_NUM];
+	struct list_head bss_list;
+
+	void (*nonwifi_rx_handlers[UMAC_HDI_IN_OPCODE_NONWIFI_MAX])
+	(struct iwm_priv *priv, u8 *buf, unsigned long buf_size);
+
+	const iwm_handler *umac_handlers;
+	const iwm_handler *lmac_handlers;
+	DECLARE_BITMAP(lmac_handler_map, LMAC_COMMAND_ID_NUM);
+	DECLARE_BITMAP(umac_handler_map, LMAC_COMMAND_ID_NUM);
+	DECLARE_BITMAP(udma_handler_map, LMAC_COMMAND_ID_NUM);
+
+	struct list_head wifi_pending_cmd;
+	struct list_head nonwifi_pending_cmd;
+	u16 wifi_seq_num;
+	u8 nonwifi_seq_num;
+	spinlock_t cmd_lock;
+
+	u32 core_enabled;
+
+	u8 scan_id;
+	struct cfg80211_scan_request *scan_request;
+
+	struct sk_buff_head rx_list;
+	struct list_head rx_tickets;
+	struct list_head rx_packets[IWM_RX_ID_HASH];
+	struct workqueue_struct *rx_wq;
+	struct work_struct rx_worker;
+
+	struct iwm_tx_credit tx_credit;
+	struct iwm_tx_queue txq[IWM_TX_QUEUES];
+
+	struct iwm_key keys[IWM_NUM_KEYS];
+	struct iwm_key *default_key;
+
+	wait_queue_head_t mlme_queue;
+
+	struct iw_statistics wstats;
+	struct delayed_work stats_request;
+
+	struct iwm_debugfs dbg;
+
+	u8 *eeprom;
+	struct timer_list watchdog;
+	struct work_struct reset_worker;
+	struct rfkill *rfkill;
+
+	char private[0] __attribute__((__aligned__(NETDEV_ALIGN)));
+};
+
+static inline void *iwm_private(struct iwm_priv *iwm)
+{
+	BUG_ON(!iwm);
+	return &iwm->private;
+}
+
+#define hw_to_iwm(h) (h->iwm)
+#define iwm_to_dev(i) (wiphy_dev(i->wdev->wiphy))
+#define iwm_to_wiphy(i) (i->wdev->wiphy)
+#define wiphy_to_iwm(w) (struct iwm_priv *)(wiphy_priv(w))
+#define iwm_to_wdev(i) (i->wdev)
+#define wdev_to_iwm(w) (struct iwm_priv *)(wdev_priv(w))
+#define iwm_to_ndev(i) (i->wdev->netdev)
+#define ndev_to_iwm(n) (wdev_to_iwm(n->ieee80211_ptr))
+#define skb_to_rx_info(s) ((struct iwm_rx_info *)(s->cb))
+#define skb_to_tx_info(s) ((struct iwm_tx_info *)s->cb)
+
+extern const struct iw_handler_def iwm_iw_handler_def;
+
+void *iwm_if_alloc(int sizeof_bus, struct device *dev,
+		   struct iwm_if_ops *if_ops);
+void iwm_if_free(struct iwm_priv *iwm);
+int iwm_mode_to_nl80211_iftype(int mode);
+int iwm_priv_init(struct iwm_priv *iwm);
+void iwm_reset(struct iwm_priv *iwm);
+void iwm_tx_credit_init_pools(struct iwm_priv *iwm,
+			      struct iwm_umac_notif_alive *alive);
+int iwm_tx_credit_alloc(struct iwm_priv *iwm, int id, int nb);
+int iwm_notif_send(struct iwm_priv *iwm, struct iwm_wifi_cmd *cmd,
+		   u8 cmd_id, u8 source, u8 *buf, unsigned long buf_size);
+int iwm_notif_handle(struct iwm_priv *iwm, u32 cmd, u8 source, long timeout);
+void iwm_init_default_profile(struct iwm_priv *iwm,
+			      struct iwm_umac_profile *profile);
+void iwm_link_on(struct iwm_priv *iwm);
+void iwm_link_off(struct iwm_priv *iwm);
+int iwm_up(struct iwm_priv *iwm);
+int iwm_down(struct iwm_priv *iwm);
+
+/* TX API */
+void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages);
+void iwm_tx_worker(struct work_struct *work);
+int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
+
+/* RX API */
+void iwm_rx_setup_handlers(struct iwm_priv *iwm);
+int iwm_rx_handle(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size);
+int iwm_rx_handle_resp(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size,
+		       struct iwm_wifi_cmd *cmd);
+void iwm_rx_free(struct iwm_priv *iwm);
+
+/* RF Kill API */
+int iwm_rfkill_init(struct iwm_priv *iwm);
+void iwm_rfkill_exit(struct iwm_priv *iwm);
+
+#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h
new file mode 100644
index 0000000..db2e5ee
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/lmac.h
@@ -0,0 +1,457 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ *
+ * Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ */
+
+#ifndef __IWM_LMAC_H__
+#define __IWM_LMAC_H__
+
+struct iwm_lmac_hdr {
+	u8 id;
+	u8 flags;
+	__le16 seq_num;
+} __attribute__ ((packed));
+
+/* LMAC commands */
+#define CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK  0x1
+
+struct iwm_lmac_cal_cfg_elt {
+	__le32 enable; /* 1 means LMAC needs to do something */
+	__le32 start;  /* 1 to start calibration, 0 to stop */
+	__le32 send_res; /* 1 for sending back results */
+	__le32 apply_res; /* 1 for applying calibration results to HW */
+	__le32 reserved;
+} __attribute__ ((packed));
+
+struct iwm_lmac_cal_cfg_status {
+	struct iwm_lmac_cal_cfg_elt init;
+	struct iwm_lmac_cal_cfg_elt periodic;
+	__le32 flags; /* CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK */
+} __attribute__ ((packed));
+
+struct iwm_lmac_cal_cfg_cmd {
+	struct iwm_lmac_cal_cfg_status ucode_cfg;
+	struct iwm_lmac_cal_cfg_status driver_cfg;
+	__le32 reserved;
+} __attribute__ ((packed));
+
+struct iwm_lmac_cal_cfg_resp {
+	__le32 status;
+} __attribute__ ((packed));
+
+#define IWM_CARD_STATE_SW_HW_ENABLED	0x00
+#define IWM_CARD_STATE_HW_DISABLED	0x01
+#define IWM_CARD_STATE_SW_DISABLED	0x02
+#define IWM_CARD_STATE_CTKILL_DISABLED	0x04
+#define IWM_CARD_STATE_IS_RXON		0x10
+
+struct iwm_lmac_card_state {
+	__le32 flags;
+} __attribute__ ((packed));
+
+/**
+ * COEX_PRIORITY_TABLE_CMD
+ *
+ * Priority entry for each state
+ * Will keep two tables, for STA and WIPAN
+ */
+enum {
+	/* UN-ASSOCIATION PART */
+	COEX_UNASSOC_IDLE = 0,
+	COEX_UNASSOC_MANUAL_SCAN,
+	COEX_UNASSOC_AUTO_SCAN,
+
+	/* CALIBRATION */
+	COEX_CALIBRATION,
+	COEX_PERIODIC_CALIBRATION,
+
+	/* CONNECTION */
+	COEX_CONNECTION_ESTAB,
+
+	/* ASSOCIATION PART */
+	COEX_ASSOCIATED_IDLE,
+	COEX_ASSOC_MANUAL_SCAN,
+	COEX_ASSOC_AUTO_SCAN,
+	COEX_ASSOC_ACTIVE_LEVEL,
+
+	/* RF ON/OFF */
+	COEX_RF_ON,
+	COEX_RF_OFF,
+	COEX_STAND_ALONE_DEBUG,
+
+	/* IPNN */
+	COEX_IPAN_ASSOC_LEVEL,
+
+	/* RESERVED */
+	COEX_RSRVD1,
+	COEX_RSRVD2,
+
+	COEX_EVENTS_NUM
+};
+
+#define COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK	0x1
+#define COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK	0x2
+#define COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK	0x4
+
+struct coex_event {
+	u8 req_prio;
+	u8 win_med_prio;
+	u8 reserved;
+	u8 flags;
+} __attribute__ ((packed));
+
+#define COEX_FLAGS_STA_TABLE_VALID_MSK		0x1
+#define COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK	0x4
+#define COEX_FLAGS_ASSOC_WAKEUP_UMASK_MSK	0x8
+#define COEX_FLAGS_COEX_ENABLE_MSK		0x80
+
+struct iwm_coex_prio_table_cmd {
+	u8 flags;
+	u8 reserved[3];
+	struct coex_event sta_prio[COEX_EVENTS_NUM];
+} __attribute__ ((packed));
+
+/* Coexistence definitions
+ *
+ * Constants to fill in the Priorities' Tables
+ * RP - Requested Priority
+ * WP - Win Medium Priority: priority assigned when the contention has been won
+ * FLAGS - Combination of COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK and
+ * 	   COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK
+ */
+
+#define COEX_UNASSOC_IDLE_FLAGS		0
+#define COEX_UNASSOC_MANUAL_SCAN_FLAGS	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \
+					 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK)
+#define COEX_UNASSOC_AUTO_SCAN_FLAGS	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \
+					 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK)
+#define COEX_CALIBRATION_FLAGS		(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \
+					 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK)
+#define COEX_PERIODIC_CALIBRATION_FLAGS	0
+/* COEX_CONNECTION_ESTAB: we need DELAY_MEDIUM_FREE_NTFY to let WiMAX
+ * disconnect from network. */
+#define COEX_CONNECTION_ESTAB_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \
+				     COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \
+				     COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK)
+#define COEX_ASSOCIATED_IDLE_FLAGS	0
+#define COEX_ASSOC_MANUAL_SCAN_FLAGS	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \
+					 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK)
+#define COEX_ASSOC_AUTO_SCAN_FLAGS	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \
+					 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK)
+#define COEX_ASSOC_ACTIVE_LEVEL_FLAGS	0
+#define COEX_RF_ON_FLAGS		0
+#define COEX_RF_OFF_FLAGS		0
+#define COEX_STAND_ALONE_DEBUG_FLAGS	(COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \
+					 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK)
+#define COEX_IPAN_ASSOC_LEVEL_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \
+				     COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \
+				     COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK)
+#define COEX_RSRVD1_FLAGS		0
+#define COEX_RSRVD2_FLAGS		0
+/* XOR_RF_ON is the event wrapping all radio ownership. We need
+ * DELAY_MEDIUM_FREE_NTFY to let WiMAX disconnect from network. */
+#define COEX_XOR_RF_ON_FLAGS	    (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \
+				     COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \
+				     COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK)
+
+/* LMAC OP CODES */
+#define REPLY_PAD			0x0
+#define REPLY_ALIVE			0x1
+#define REPLY_ERROR			0x2
+#define REPLY_ECHO			0x3
+#define REPLY_HALT			0x6
+
+/* RXON state commands */
+#define REPLY_RX_ON			0x10
+#define REPLY_RX_ON_ASSOC		0x11
+#define REPLY_RX_OFF			0x12
+#define REPLY_QOS_PARAM			0x13
+#define REPLY_RX_ON_TIMING		0x14
+#define REPLY_INTERNAL_QOS_PARAM	0x15
+#define REPLY_RX_INT_TIMEOUT_CNFG	0x16
+#define REPLY_NULL			0x17
+
+/* Multi-Station support */
+#define REPLY_ADD_STA			0x18
+#define REPLY_REMOVE_STA		0x19
+#define REPLY_RESET_ALL_STA		0x1a
+
+/* RX, TX */
+#define REPLY_ALM_RX			0x1b
+#define REPLY_TX			0x1c
+#define REPLY_TXFIFO_FLUSH		0x1e
+
+/* MISC commands */
+#define REPLY_MGMT_MCAST_KEY		0x1f
+#define REPLY_WEPKEY			0x20
+#define REPLY_INIT_IV			0x21
+#define REPLY_WRITE_MIB			0x22
+#define REPLY_READ_MIB			0x23
+#define REPLY_RADIO_FE			0x24
+#define REPLY_TXFIFO_CFG		0x25
+#define REPLY_WRITE_READ		0x26
+#define REPLY_INSTALL_SEC_KEY		0x27
+
+
+#define REPLY_RATE_SCALE		0x47
+#define REPLY_LEDS_CMD			0x48
+#define REPLY_TX_LINK_QUALITY_CMD	0x4e
+#define REPLY_ANA_MIB_OVERRIDE_CMD	0x4f
+#define REPLY_WRITE2REG_CMD		0x50
+
+/* winfi-wifi coexistence */
+#define COEX_PRIORITY_TABLE_CMD		0x5a
+#define COEX_MEDIUM_NOTIFICATION	0x5b
+#define COEX_EVENT_CMD			0x5c
+
+/* more Protocol and Protocol-test commands */
+#define REPLY_MAX_SLEEP_TIME_CMD	0x61
+#define CALIBRATION_CFG_CMD		0x65
+#define CALIBRATION_RES_NOTIFICATION	0x66
+#define CALIBRATION_COMPLETE_NOTIFICATION	0x67
+
+/* Measurements */
+#define REPLY_QUIET_CMD			0x71
+#define REPLY_CHANNEL_SWITCH		0x72
+#define CHANNEL_SWITCH_NOTIFICATION	0x73
+
+#define REPLY_SPECTRUM_MEASUREMENT_CMD	0x74
+#define SPECTRUM_MEASURE_NOTIFICATION	0x75
+#define REPLY_MEASUREMENT_ABORT_CMD	0x76
+
+/* Power Management */
+#define POWER_TABLE_CMD			0x77
+#define SAVE_RESTORE_ADRESS_CMD		0x78
+#define REPLY_WATERMARK_CMD		0x79
+#define PM_DEBUG_STATISTIC_NOTIFIC	0x7B
+#define PD_FLUSH_N_NOTIFICATION		0x7C
+
+/* Scan commands and notifications */
+#define REPLY_SCAN_REQUEST_CMD		0x80
+#define REPLY_SCAN_ABORT_CMD		0x81
+#define SCAN_START_NOTIFICATION		0x82
+#define SCAN_RESULTS_NOTIFICATION	0x83
+#define SCAN_COMPLETE_NOTIFICATION	0x84
+
+/* Continuous TX commands */
+#define REPLY_CONT_TX_CMD		0x85
+#define END_OF_CONT_TX_NOTIFICATION	0x86
+
+/* Timer/Eeprom commands */
+#define TIMER_CMD			0x87
+#define EEPROM_WRITE_CMD		0x88
+
+/* PAPD commands */
+#define FEEDBACK_REQUEST_NOTIFICATION	0x8b
+#define REPLY_CW_CMD			0x8c
+
+/* IBSS/AP commands Continue */
+#define BEACON_NOTIFICATION		0x90
+#define REPLY_TX_BEACON			0x91
+#define REPLY_REQUEST_ATIM		0x93
+#define WHO_IS_AWAKE_NOTIFICATION	0x94
+#define TX_PWR_DBM_LIMIT_CMD		0x95
+#define QUIET_NOTIFICATION		0x96
+#define TX_PWR_TABLE_CMD		0x97
+#define TX_ANT_CONFIGURATION_CMD	0x98
+#define MEASURE_ABORT_NOTIFICATION	0x99
+#define REPLY_CALIBRATION_TUNE		0x9a
+
+/* bt config command */
+#define REPLY_BT_CONFIG			0x9b
+#define REPLY_STATISTICS_CMD		0x9c
+#define STATISTICS_NOTIFICATION		0x9d
+
+/* RF-KILL commands and notifications */
+#define REPLY_CARD_STATE_CMD		0xa0
+#define CARD_STATE_NOTIFICATION		0xa1
+
+/* Missed beacons notification */
+#define MISSED_BEACONS_NOTIFICATION	0xa2
+#define MISSED_BEACONS_NOTIFICATION_TH_CMD	0xa3
+
+#define REPLY_CT_KILL_CONFIG_CMD	0xa4
+
+/* HD commands and notifications */
+#define REPLY_HD_PARAMS_CMD		0xa6
+#define HD_PARAMS_NOTIFICATION		0xa7
+#define SENSITIVITY_CMD			0xa8
+#define U_APSD_PARAMS_CMD		0xa9
+#define NOISY_PLATFORM_CMD		0xaa
+#define ILLEGAL_CMD			0xac
+#define REPLY_PHY_CALIBRATION_CMD	0xb0
+#define REPLAY_RX_GAIN_CALIB_CMD	0xb1
+
+/* WiPAN commands */
+#define REPLY_WIPAN_PARAMS_CMD		0xb2
+#define REPLY_WIPAN_RX_ON_CMD		0xb3
+#define REPLY_WIPAN_RX_ON_TIMING	0xb4
+#define REPLY_WIPAN_TX_PWR_TABLE_CMD	0xb5
+#define REPLY_WIPAN_RXON_ASSOC_CMD	0xb6
+#define REPLY_WIPAN_QOS_PARAM		0xb7
+#define WIPAN_REPLY_WEPKEY		0xb8
+
+/* BeamForming commands */
+#define BEAMFORMER_CFG_CMD		0xba
+#define BEAMFORMEE_NOTIFICATION		0xbb
+
+/* TGn new Commands */
+#define REPLY_RX_PHY_CMD		0xc0
+#define REPLY_RX_MPDU_CMD		0xc1
+#define REPLY_MULTICAST_HASH		0xc2
+#define REPLY_KDR_RX			0xc3
+#define REPLY_RX_DSP_EXT_INFO		0xc4
+#define REPLY_COMPRESSED_BA		0xc5
+
+/* PNC commands */
+#define PNC_CONFIG_CMD			0xc8
+#define PNC_UPDATE_TABLE_CMD		0xc9
+#define XVT_GENERAL_CTRL_CMD		0xca
+#define REPLY_LEGACY_RADIO_FE		0xdd
+
+/* WoWLAN commands */
+#define WOWLAN_PATTERNS			0xe0
+#define WOWLAN_WAKEUP_FILTER		0xe1
+#define WOWLAN_TSC_RSC_PARAM		0xe2
+#define WOWLAN_TKIP_PARAM		0xe3
+#define WOWLAN_KEK_KCK_MATERIAL		0xe4
+#define WOWLAN_GET_STATUSES		0xe5
+#define WOWLAN_TX_POWER_PER_DB		0xe6
+#define REPLY_WOWLAN_GET_STATUSES       WOWLAN_GET_STATUSES
+
+#define REPLY_DEBUG_CMD			0xf0
+#define REPLY_DSP_DEBUG_CMD		0xf1
+#define REPLY_DEBUG_MONITOR_CMD		0xf2
+#define REPLY_DEBUG_XVT_CMD		0xf3
+#define REPLY_DEBUG_DC_CALIB		0xf4
+#define REPLY_DYNAMIC_BP		0xf5
+
+/* General purpose Commands */
+#define REPLY_GP1_CMD			0xfa
+#define REPLY_GP2_CMD			0xfb
+#define REPLY_GP3_CMD			0xfc
+#define REPLY_GP4_CMD			0xfd
+#define REPLY_REPLAY_WRAPPER		0xfe
+#define REPLY_FRAME_DURATION_CALC_CMD	0xff
+
+#define LMAC_COMMAND_ID_MAX		0xff
+#define LMAC_COMMAND_ID_NUM		(LMAC_COMMAND_ID_MAX + 1)
+
+
+/* Calibration */
+
+enum {
+	PHY_CALIBRATE_DC_CMD			= 0,
+	PHY_CALIBRATE_LO_CMD			= 1,
+	PHY_CALIBRATE_RX_BB_CMD			= 2,
+	PHY_CALIBRATE_TX_IQ_CMD			= 3,
+	PHY_CALIBRATE_RX_IQ_CMD			= 4,
+	PHY_CALIBRATION_NOISE_CMD		= 5,
+	PHY_CALIBRATE_AGC_TABLE_CMD		= 6,
+	PHY_CALIBRATE_CRYSTAL_FRQ_CMD		= 7,
+	PHY_CALIBRATE_OPCODES_NUM,
+	SHILOH_PHY_CALIBRATE_DC_CMD		= 8,
+	SHILOH_PHY_CALIBRATE_LO_CMD		= 9,
+	SHILOH_PHY_CALIBRATE_RX_BB_CMD		= 10,
+	SHILOH_PHY_CALIBRATE_TX_IQ_CMD		= 11,
+	SHILOH_PHY_CALIBRATE_RX_IQ_CMD		= 12,
+	SHILOH_PHY_CALIBRATION_NOISE_CMD	= 13,
+	SHILOH_PHY_CALIBRATE_AGC_TABLE_CMD	= 14,
+	SHILOH_PHY_CALIBRATE_CRYSTAL_FRQ_CMD	= 15,
+	SHILOH_PHY_CALIBRATE_BASE_BAND_CMD	= 16,
+	SHILOH_PHY_CALIBRATE_TXIQ_PERIODIC_CMD	= 17,
+	CALIBRATION_CMD_NUM,
+};
+
+struct iwm_lmac_calib_hdr {
+	u8 opcode;
+	u8 first_grp;
+	u8 grp_num;
+	u8 all_data_valid;
+} __attribute__ ((packed));
+
+#define IWM_LMAC_CALIB_FREQ_GROUPS_NR	7
+#define IWM_CALIB_FREQ_GROUPS_NR	5
+#define IWM_CALIB_DC_MODES_NR		12
+
+struct iwm_calib_rxiq_entry {
+	u16 ptam_postdist_ars;
+	u16 ptam_postdist_arc;
+} __attribute__ ((packed));
+
+struct iwm_calib_rxiq_group {
+	struct iwm_calib_rxiq_entry mode[IWM_CALIB_DC_MODES_NR];
+} __attribute__ ((packed));
+
+struct iwm_lmac_calib_rxiq {
+	struct iwm_calib_rxiq_group group[IWM_LMAC_CALIB_FREQ_GROUPS_NR];
+} __attribute__ ((packed));
+
+struct iwm_calib_rxiq {
+	struct iwm_lmac_calib_hdr hdr;
+	struct iwm_calib_rxiq_group group[IWM_CALIB_FREQ_GROUPS_NR];
+} __attribute__ ((packed));
+
+#define LMAC_STA_ID_SEED	0x0f
+#define LMAC_STA_ID_POS		0
+
+#define LMAC_STA_COLOR_SEED	0x7
+#define LMAC_STA_COLOR_POS	4
+
+struct iwm_lmac_power_report {
+	u8 pa_status;
+	u8 pa_integ_res_A[3];
+	u8 pa_integ_res_B[3];
+	u8 pa_integ_res_C[3];
+} __attribute__ ((packed));
+
+struct iwm_lmac_tx_resp {
+	u8 frame_cnt; /* 1-no aggregation, greater then 1 - aggregation */
+	u8 bt_kill_cnt;
+	__le16 retry_cnt;
+	__le32 initial_tx_rate;
+	__le16 wireless_media_time;
+	struct iwm_lmac_power_report power_report;
+	__le32 tfd_info;
+	__le16 seq_ctl;
+	__le16 byte_cnt;
+	u8 tlc_rate_info;
+	u8 ra_tid;
+	__le16 frame_ctl;
+	__le32 status;
+} __attribute__ ((packed));
+
+#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c
new file mode 100644
index 0000000..6a2640f
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/main.c
@@ -0,0 +1,680 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ *
+ * Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/ieee80211.h>
+#include <linux/wireless.h>
+
+#include "iwm.h"
+#include "debug.h"
+#include "bus.h"
+#include "umac.h"
+#include "commands.h"
+#include "hal.h"
+#include "fw.h"
+#include "rx.h"
+
+static struct iwm_conf def_iwm_conf = {
+
+	.sdio_ior_timeout	= 5000,
+	.init_calib_map		= BIT(PHY_CALIBRATE_DC_CMD)	|
+				  BIT(PHY_CALIBRATE_LO_CMD)	|
+				  BIT(PHY_CALIBRATE_TX_IQ_CMD)	|
+				  BIT(PHY_CALIBRATE_RX_IQ_CMD),
+	.periodic_calib_map	= BIT(PHY_CALIBRATE_DC_CMD)	|
+				  BIT(PHY_CALIBRATE_LO_CMD)	|
+				  BIT(PHY_CALIBRATE_TX_IQ_CMD)	|
+				  BIT(PHY_CALIBRATE_RX_IQ_CMD)	|
+				  BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD),
+	.reset_on_fatal_err	= 1,
+	.auto_connect		= 1,
+	.wimax_not_present	= 0,
+	.enable_qos		= 1,
+	.mode			= UMAC_MODE_BSS,
+
+	/* UMAC configuration */
+	.power_index		= 0,
+	.frag_threshold		= IEEE80211_MAX_FRAG_THRESHOLD,
+	.rts_threshold		= IEEE80211_MAX_RTS_THRESHOLD,
+	.cts_to_self		= 0,
+
+	.assoc_timeout		= 2,
+	.roam_timeout		= 10,
+	.wireless_mode		= WIRELESS_MODE_11A | WIRELESS_MODE_11G,
+	.coexist_mode		= COEX_MODE_CM,
+
+	/* IBSS */
+	.ibss_band		= UMAC_BAND_2GHZ,
+	.ibss_channel		= 1,
+
+	.mac_addr		= {0x00, 0x02, 0xb3, 0x01, 0x02, 0x03},
+};
+
+static int modparam_reset;
+module_param_named(reset, modparam_reset, bool, 0644);
+MODULE_PARM_DESC(reset, "reset on firmware errors (default 0 [not reset])");
+
+int iwm_mode_to_nl80211_iftype(int mode)
+{
+	switch (mode) {
+	case UMAC_MODE_BSS:
+		return NL80211_IFTYPE_STATION;
+	case UMAC_MODE_IBSS:
+		return NL80211_IFTYPE_ADHOC;
+	default:
+		return NL80211_IFTYPE_UNSPECIFIED;
+	}
+
+	return 0;
+}
+
+static void iwm_statistics_request(struct work_struct *work)
+{
+	struct iwm_priv *iwm =
+		container_of(work, struct iwm_priv, stats_request.work);
+
+	iwm_send_umac_stats_req(iwm, 0);
+}
+
+static void iwm_reset_worker(struct work_struct *work)
+{
+	struct iwm_priv *iwm;
+	struct iwm_umac_profile *profile = NULL;
+	int uninitialized_var(ret), retry = 0;
+
+	iwm = container_of(work, struct iwm_priv, reset_worker);
+
+	if (iwm->umac_profile_active) {
+		profile = kmalloc(sizeof(struct iwm_umac_profile), GFP_KERNEL);
+		if (profile)
+			memcpy(profile, iwm->umac_profile, sizeof(*profile));
+		else
+			IWM_ERR(iwm, "Couldn't alloc memory for profile\n");
+	}
+
+	iwm_down(iwm);
+
+	while (retry++ < 3) {
+		ret = iwm_up(iwm);
+		if (!ret)
+			break;
+
+		schedule_timeout_uninterruptible(10 * HZ);
+	}
+
+	if (ret) {
+		IWM_WARN(iwm, "iwm_up() failed: %d\n", ret);
+
+		kfree(profile);
+		return;
+	}
+
+	if (profile) {
+		IWM_DBG_MLME(iwm, DBG, "Resend UMAC profile\n");
+		memcpy(iwm->umac_profile, profile, sizeof(*profile));
+		iwm_send_mlme_profile(iwm);
+		kfree(profile);
+	}
+}
+
+static void iwm_watchdog(unsigned long data)
+{
+	struct iwm_priv *iwm = (struct iwm_priv *)data;
+
+	IWM_WARN(iwm, "Watchdog expired: UMAC stalls!\n");
+
+	if (modparam_reset)
+		schedule_work(&iwm->reset_worker);
+}
+
+int iwm_priv_init(struct iwm_priv *iwm)
+{
+	int i;
+	char name[32];
+
+	iwm->status = 0;
+	INIT_LIST_HEAD(&iwm->pending_notif);
+	init_waitqueue_head(&iwm->notif_queue);
+	init_waitqueue_head(&iwm->nonwifi_queue);
+	init_waitqueue_head(&iwm->mlme_queue);
+	memcpy(&iwm->conf, &def_iwm_conf, sizeof(struct iwm_conf));
+	spin_lock_init(&iwm->tx_credit.lock);
+	INIT_LIST_HEAD(&iwm->wifi_pending_cmd);
+	INIT_LIST_HEAD(&iwm->nonwifi_pending_cmd);
+	iwm->wifi_seq_num = UMAC_WIFI_SEQ_NUM_BASE;
+	iwm->nonwifi_seq_num = UMAC_NONWIFI_SEQ_NUM_BASE;
+	spin_lock_init(&iwm->cmd_lock);
+	iwm->scan_id = 1;
+	INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request);
+	INIT_WORK(&iwm->reset_worker, iwm_reset_worker);
+	INIT_LIST_HEAD(&iwm->bss_list);
+
+	skb_queue_head_init(&iwm->rx_list);
+	INIT_LIST_HEAD(&iwm->rx_tickets);
+	for (i = 0; i < IWM_RX_ID_HASH; i++)
+		INIT_LIST_HEAD(&iwm->rx_packets[i]);
+
+	INIT_WORK(&iwm->rx_worker, iwm_rx_worker);
+
+	iwm->rx_wq = create_singlethread_workqueue(KBUILD_MODNAME "_rx");
+	if (!iwm->rx_wq)
+		return -EAGAIN;
+
+	for (i = 0; i < IWM_TX_QUEUES; i++) {
+		INIT_WORK(&iwm->txq[i].worker, iwm_tx_worker);
+		snprintf(name, 32, KBUILD_MODNAME "_tx_%d", i);
+		iwm->txq[i].id = i;
+		iwm->txq[i].wq = create_singlethread_workqueue(name);
+		if (!iwm->txq[i].wq)
+			return -EAGAIN;
+
+		skb_queue_head_init(&iwm->txq[i].queue);
+	}
+
+	for (i = 0; i < IWM_NUM_KEYS; i++)
+		memset(&iwm->keys[i], 0, sizeof(struct iwm_key));
+
+	iwm->default_key = NULL;
+
+	init_timer(&iwm->watchdog);
+	iwm->watchdog.function = iwm_watchdog;
+	iwm->watchdog.data = (unsigned long)iwm;
+
+	return 0;
+}
+
+/*
+ * We reset all the structures, and we reset the UMAC.
+ * After calling this routine, you're expected to reload
+ * the firmware.
+ */
+void iwm_reset(struct iwm_priv *iwm)
+{
+	struct iwm_notif *notif, *next;
+
+	if (test_bit(IWM_STATUS_READY, &iwm->status))
+		iwm_target_reset(iwm);
+
+	iwm->status = 0;
+	iwm->scan_id = 1;
+
+	list_for_each_entry_safe(notif, next, &iwm->pending_notif, pending) {
+		list_del(&notif->pending);
+		kfree(notif->buf);
+		kfree(notif);
+	}
+
+	iwm_cmd_flush(iwm);
+
+	flush_workqueue(iwm->rx_wq);
+
+	iwm_link_off(iwm);
+}
+
+/*
+ * Notification code:
+ *
+ * We're faced with the following issue: Any host command can
+ * have an answer or not, and if there's an answer to expect,
+ * it can be treated synchronously or asynchronously.
+ * To work around the synchronous answer case, we implemented
+ * our notification mechanism.
+ * When a code path needs to wait for a command response
+ * synchronously, it calls notif_handle(), which waits for the
+ * right notification to show up, and then process it. Before
+ * starting to wait, it registered as a waiter for this specific
+ * answer (by toggling a bit in on of the handler_map), so that
+ * the rx code knows that it needs to send a notification to the
+ * waiting processes. It does so by calling iwm_notif_send(),
+ * which adds the notification to the pending notifications list,
+ * and then wakes the waiting processes up.
+ */
+int iwm_notif_send(struct iwm_priv *iwm, struct iwm_wifi_cmd *cmd,
+		   u8 cmd_id, u8 source, u8 *buf, unsigned long buf_size)
+{
+	struct iwm_notif *notif;
+
+	notif = kzalloc(sizeof(struct iwm_notif), GFP_KERNEL);
+	if (!notif) {
+		IWM_ERR(iwm, "Couldn't alloc memory for notification\n");
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&notif->pending);
+	notif->cmd = cmd;
+	notif->cmd_id = cmd_id;
+	notif->src = source;
+	notif->buf = kzalloc(buf_size, GFP_KERNEL);
+	if (!notif->buf) {
+		IWM_ERR(iwm, "Couldn't alloc notification buffer\n");
+		kfree(notif);
+		return -ENOMEM;
+	}
+	notif->buf_size = buf_size;
+	memcpy(notif->buf, buf, buf_size);
+	list_add_tail(&notif->pending, &iwm->pending_notif);
+
+	wake_up_interruptible(&iwm->notif_queue);
+
+	return 0;
+}
+
+static struct iwm_notif *iwm_notif_find(struct iwm_priv *iwm, u32 cmd,
+					u8 source)
+{
+	struct iwm_notif *notif, *next;
+
+	list_for_each_entry_safe(notif, next, &iwm->pending_notif, pending) {
+		if ((notif->cmd_id == cmd) && (notif->src == source)) {
+			list_del(&notif->pending);
+			return notif;
+		}
+	}
+
+	return NULL;
+}
+
+static struct iwm_notif *iwm_notif_wait(struct iwm_priv *iwm, u32 cmd,
+					u8 source, long timeout)
+{
+	int ret;
+	struct iwm_notif *notif;
+	unsigned long *map = NULL;
+
+	switch (source) {
+	case IWM_SRC_LMAC:
+		map = &iwm->lmac_handler_map[0];
+		break;
+	case IWM_SRC_UMAC:
+		map = &iwm->umac_handler_map[0];
+		break;
+	case IWM_SRC_UDMA:
+		map = &iwm->udma_handler_map[0];
+		break;
+	}
+
+	set_bit(cmd, map);
+
+	ret = wait_event_interruptible_timeout(iwm->notif_queue,
+			 ((notif = iwm_notif_find(iwm, cmd, source)) != NULL),
+					       timeout);
+	clear_bit(cmd, map);
+
+	if (!ret)
+		return NULL;
+
+	return notif;
+}
+
+int iwm_notif_handle(struct iwm_priv *iwm, u32 cmd, u8 source, long timeout)
+{
+	int ret;
+	struct iwm_notif *notif;
+
+	notif = iwm_notif_wait(iwm, cmd, source, timeout);
+	if (!notif)
+		return -ETIME;
+
+	ret = iwm_rx_handle_resp(iwm, notif->buf, notif->buf_size, notif->cmd);
+	kfree(notif->buf);
+	kfree(notif);
+
+	return ret;
+}
+
+static int iwm_config_boot_params(struct iwm_priv *iwm)
+{
+	struct iwm_udma_nonwifi_cmd target_cmd;
+	int ret;
+
+	/* check Wimax is off and config debug monitor */
+	if (iwm->conf.wimax_not_present) {
+		u32 data1 = 0x1f;
+		u32 addr1 = 0x606BE258;
+
+		u32 data2_set = 0x0;
+		u32 data2_clr = 0x1;
+		u32 addr2 = 0x606BE100;
+
+		u32 data3 = 0x1;
+		u32 addr3 = 0x606BEC00;
+
+		target_cmd.resp = 0;
+		target_cmd.handle_by_hw = 0;
+		target_cmd.eop = 1;
+
+		target_cmd.opcode = UMAC_HDI_OUT_OPCODE_WRITE;
+		target_cmd.addr = cpu_to_le32(addr1);
+		target_cmd.op1_sz = cpu_to_le32(sizeof(u32));
+		target_cmd.op2 = 0;
+
+		ret = iwm_hal_send_target_cmd(iwm, &target_cmd, &data1);
+		if (ret < 0) {
+			IWM_ERR(iwm, "iwm_hal_send_target_cmd failed\n");
+			return ret;
+		}
+
+		target_cmd.opcode = UMAC_HDI_OUT_OPCODE_READ_MODIFY_WRITE;
+		target_cmd.addr = cpu_to_le32(addr2);
+		target_cmd.op1_sz = cpu_to_le32(data2_set);
+		target_cmd.op2 = cpu_to_le32(data2_clr);
+
+		ret = iwm_hal_send_target_cmd(iwm, &target_cmd, &data1);
+		if (ret < 0) {
+			IWM_ERR(iwm, "iwm_hal_send_target_cmd failed\n");
+			return ret;
+		}
+
+		target_cmd.opcode = UMAC_HDI_OUT_OPCODE_WRITE;
+		target_cmd.addr = cpu_to_le32(addr3);
+		target_cmd.op1_sz = cpu_to_le32(sizeof(u32));
+		target_cmd.op2 = 0;
+
+		ret = iwm_hal_send_target_cmd(iwm, &target_cmd, &data3);
+		if (ret < 0) {
+			IWM_ERR(iwm, "iwm_hal_send_target_cmd failed\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+void iwm_init_default_profile(struct iwm_priv *iwm,
+			      struct iwm_umac_profile *profile)
+{
+	memset(profile, 0, sizeof(struct iwm_umac_profile));
+
+	profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN;
+	profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
+	profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_NONE;
+	profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_NONE;
+
+	if (iwm->conf.enable_qos)
+		profile->flags |= cpu_to_le16(UMAC_PROFILE_QOS_ALLOWED);
+
+	profile->wireless_mode = iwm->conf.wireless_mode;
+	profile->mode = cpu_to_le32(iwm->conf.mode);
+
+	profile->ibss.atim = 0;
+	profile->ibss.beacon_interval = 100;
+	profile->ibss.join_only = 0;
+	profile->ibss.band = iwm->conf.ibss_band;
+	profile->ibss.channel = iwm->conf.ibss_channel;
+}
+
+void iwm_link_on(struct iwm_priv *iwm)
+{
+	netif_carrier_on(iwm_to_ndev(iwm));
+	netif_tx_wake_all_queues(iwm_to_ndev(iwm));
+
+	iwm_send_umac_stats_req(iwm, 0);
+}
+
+void iwm_link_off(struct iwm_priv *iwm)
+{
+	struct iw_statistics *wstats = &iwm->wstats;
+	int i;
+
+	netif_tx_stop_all_queues(iwm_to_ndev(iwm));
+	netif_carrier_off(iwm_to_ndev(iwm));
+
+	for (i = 0; i < IWM_TX_QUEUES; i++) {
+		skb_queue_purge(&iwm->txq[i].queue);
+
+		iwm->txq[i].concat_count = 0;
+		iwm->txq[i].concat_ptr = iwm->txq[i].concat_buf;
+
+		flush_workqueue(iwm->txq[i].wq);
+	}
+
+	iwm_rx_free(iwm);
+
+	cancel_delayed_work(&iwm->stats_request);
+	memset(wstats, 0, sizeof(struct iw_statistics));
+	wstats->qual.updated = IW_QUAL_ALL_INVALID;
+
+	del_timer_sync(&iwm->watchdog);
+}
+
+static void iwm_bss_list_clean(struct iwm_priv *iwm)
+{
+	struct iwm_bss_info *bss, *next;
+
+	list_for_each_entry_safe(bss, next, &iwm->bss_list, node) {
+		list_del(&bss->node);
+		kfree(bss->bss);
+		kfree(bss);
+	}
+}
+
+static int iwm_channels_init(struct iwm_priv *iwm)
+{
+	int ret;
+
+#ifdef CONFIG_IWM_B0_HW_SUPPORT
+	if (iwm->conf.hw_b0) {
+		IWM_INFO(iwm, "Workaround EEPROM channels for B0 hardware\n");
+		return 0;
+	}
+#endif
+
+	ret = iwm_send_umac_channel_list(iwm);
+	if (ret) {
+		IWM_ERR(iwm, "Send channel list failed\n");
+		return ret;
+	}
+
+	ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST,
+			       IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT);
+	if (ret) {
+		IWM_ERR(iwm, "Didn't get a channel list notification\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+int iwm_up(struct iwm_priv *iwm)
+{
+	int ret;
+	struct iwm_notif *notif_reboot, *notif_ack = NULL;
+
+	ret = iwm_bus_enable(iwm);
+	if (ret) {
+		IWM_ERR(iwm, "Couldn't enable function\n");
+		return ret;
+	}
+
+	iwm_rx_setup_handlers(iwm);
+
+	/* Wait for initial BARKER_REBOOT from hardware */
+	notif_reboot = iwm_notif_wait(iwm, IWM_BARKER_REBOOT_NOTIFICATION,
+				      IWM_SRC_UDMA, 2 * HZ);
+	if (!notif_reboot) {
+		IWM_ERR(iwm, "Wait for REBOOT_BARKER timeout\n");
+		goto err_disable;
+	}
+
+	/* We send the barker back */
+	ret = iwm_bus_send_chunk(iwm, notif_reboot->buf, 16);
+	if (ret) {
+		IWM_ERR(iwm, "REBOOT barker response failed\n");
+		kfree(notif_reboot);
+		goto err_disable;
+	}
+
+	kfree(notif_reboot->buf);
+	kfree(notif_reboot);
+
+	/* Wait for ACK_BARKER from hardware */
+	notif_ack = iwm_notif_wait(iwm, IWM_ACK_BARKER_NOTIFICATION,
+				   IWM_SRC_UDMA, 2 * HZ);
+	if (!notif_ack) {
+		IWM_ERR(iwm, "Wait for ACK_BARKER timeout\n");
+		goto err_disable;
+	}
+
+	kfree(notif_ack->buf);
+	kfree(notif_ack);
+
+	/* We start to config static boot parameters */
+	ret = iwm_config_boot_params(iwm);
+	if (ret) {
+		IWM_ERR(iwm, "Config boot parameters failed\n");
+		goto err_disable;
+	}
+
+	ret = iwm_read_mac(iwm, iwm_to_ndev(iwm)->dev_addr);
+	if (ret) {
+		IWM_ERR(iwm, "MAC reading failed\n");
+		goto err_disable;
+	}
+
+	/* We can load the FWs */
+	ret = iwm_load_fw(iwm);
+	if (ret) {
+		IWM_ERR(iwm, "FW loading failed\n");
+		goto err_disable;
+	}
+
+	/* We configure the UMAC and enable the wifi module */
+	ret = iwm_send_umac_config(iwm,
+			cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_CORE_EN) |
+			cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_LINK_EN) |
+			cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_MLME_EN));
+	if (ret) {
+		IWM_ERR(iwm, "UMAC config failed\n");
+		goto err_fw;
+	}
+
+	ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS,
+			       IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT);
+	if (ret) {
+		IWM_ERR(iwm, "Didn't get a wifi core status notification\n");
+		goto err_fw;
+	}
+
+	if (iwm->core_enabled != (UMAC_NTFY_WIFI_CORE_STATUS_LINK_EN |
+				  UMAC_NTFY_WIFI_CORE_STATUS_MLME_EN)) {
+		IWM_DBG_BOOT(iwm, DBG, "Not all cores enabled:0x%x\n",
+			     iwm->core_enabled);
+		ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS,
+			       IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT);
+		if (ret) {
+			IWM_ERR(iwm, "Didn't get a core status notification\n");
+			goto err_fw;
+		}
+
+		if (iwm->core_enabled != (UMAC_NTFY_WIFI_CORE_STATUS_LINK_EN |
+					  UMAC_NTFY_WIFI_CORE_STATUS_MLME_EN)) {
+			IWM_ERR(iwm, "Not all cores enabled: 0x%x\n",
+				iwm->core_enabled);
+			goto err_fw;
+		} else {
+			IWM_INFO(iwm, "All cores enabled\n");
+		}
+	}
+
+	iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile),
+				    GFP_KERNEL);
+	if (!iwm->umac_profile) {
+		IWM_ERR(iwm, "Couldn't alloc memory for profile\n");
+		goto err_fw;
+	}
+
+	iwm_init_default_profile(iwm, iwm->umac_profile);
+
+	ret = iwm_channels_init(iwm);
+	if (ret < 0) {
+		IWM_ERR(iwm, "Couldn't init channels\n");
+		goto err_profile;
+	}
+
+	/* Set the READY bit to indicate interface is brought up successfully */
+	set_bit(IWM_STATUS_READY, &iwm->status);
+
+	return 0;
+
+ err_profile:
+	kfree(iwm->umac_profile);
+	iwm->umac_profile = NULL;
+
+ err_fw:
+	iwm_eeprom_exit(iwm);
+
+ err_disable:
+	ret = iwm_bus_disable(iwm);
+	if (ret < 0)
+		IWM_ERR(iwm, "Couldn't disable function\n");
+
+	return -EIO;
+}
+
+int iwm_down(struct iwm_priv *iwm)
+{
+	int ret;
+
+	/* The interface is already down */
+	if (!test_bit(IWM_STATUS_READY, &iwm->status))
+		return 0;
+
+	if (iwm->scan_request) {
+		cfg80211_scan_done(iwm->scan_request, true);
+		iwm->scan_request = NULL;
+	}
+
+	clear_bit(IWM_STATUS_READY, &iwm->status);
+
+	iwm_eeprom_exit(iwm);
+	kfree(iwm->umac_profile);
+	iwm->umac_profile = NULL;
+	iwm_bss_list_clean(iwm);
+
+	iwm->default_key = NULL;
+	iwm->core_enabled = 0;
+
+	ret = iwm_bus_disable(iwm);
+	if (ret < 0) {
+		IWM_ERR(iwm, "Couldn't disable function\n");
+		return ret;
+	}
+
+	return 0;
+}
diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c
new file mode 100644
index 0000000..eec7201
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/netdev.c
@@ -0,0 +1,172 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+/*
+ * This is the netdev related hooks for iwm.
+ *
+ * Some interesting code paths:
+ *
+ * iwm_open() (Called at netdev interface bringup time)
+ *  -> iwm_up() (main.c)
+ *      -> iwm_bus_enable()
+ *          -> if_sdio_enable() (In case of an SDIO bus)
+ *              -> sdio_enable_func()
+ *      -> iwm_notif_wait(BARKER_REBOOT) (wait for reboot barker)
+ *      -> iwm_notif_wait(ACK_BARKER) (wait for ACK barker)
+ *      -> iwm_load_fw() (fw.c)
+ *          -> iwm_load_umac()
+ *          -> iwm_load_lmac() (Calibration LMAC)
+ *          -> iwm_load_lmac() (Operational LMAC)
+ *      -> iwm_send_umac_config()
+ *
+ * iwm_stop() (Called at netdev interface bringdown time)
+ *  -> iwm_down()
+ *      -> iwm_bus_disable()
+ *          -> if_sdio_disable() (In case of an SDIO bus)
+ *              -> sdio_disable_func()
+ */
+#include <linux/netdevice.h>
+
+#include "iwm.h"
+#include "cfg80211.h"
+#include "debug.h"
+
+static int iwm_open(struct net_device *ndev)
+{
+	struct iwm_priv *iwm = ndev_to_iwm(ndev);
+	int ret = 0;
+
+	if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio))
+		ret = iwm_up(iwm);
+
+	return ret;
+}
+
+static int iwm_stop(struct net_device *ndev)
+{
+	struct iwm_priv *iwm = ndev_to_iwm(ndev);
+	int ret = 0;
+
+	if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio))
+		ret = iwm_down(iwm);
+
+	return ret;
+}
+
+/*
+ * iwm AC to queue mapping
+ *
+ * AC_VO -> queue 3
+ * AC_VI -> queue 2
+ * AC_BE -> queue 1
+ * AC_BK -> queue 0
+ */
+static const u16 iwm_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
+
+static u16 iwm_select_queue(struct net_device *dev, struct sk_buff *skb)
+{
+	skb->priority = cfg80211_classify8021d(skb);
+
+	return iwm_1d_to_queue[skb->priority];
+}
+
+static const struct net_device_ops iwm_netdev_ops = {
+	.ndo_open		= iwm_open,
+	.ndo_stop		= iwm_stop,
+	.ndo_start_xmit		= iwm_xmit_frame,
+	.ndo_select_queue	= iwm_select_queue,
+};
+
+void *iwm_if_alloc(int sizeof_bus, struct device *dev,
+		   struct iwm_if_ops *if_ops)
+{
+	struct net_device *ndev;
+	struct wireless_dev *wdev;
+	struct iwm_priv *iwm;
+	int ret = 0;
+
+	wdev = iwm_wdev_alloc(sizeof_bus, dev);
+	if (!wdev) {
+		dev_err(dev, "no memory for wireless device instance\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	iwm = wdev_to_iwm(wdev);
+	iwm->bus_ops = if_ops;
+	iwm->wdev = wdev;
+	iwm_priv_init(iwm);
+	wdev->iftype = iwm_mode_to_nl80211_iftype(iwm->conf.mode);
+
+	ndev = alloc_netdev_mq(0, "wlan%d", ether_setup,
+			       IWM_TX_QUEUES);
+	if (!ndev) {
+		dev_err(dev, "no memory for network device instance\n");
+		goto out_wdev;
+	}
+
+	ndev->netdev_ops = &iwm_netdev_ops;
+	ndev->wireless_handlers = &iwm_iw_handler_def;
+	ndev->ieee80211_ptr = wdev;
+	SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
+	ret = register_netdev(ndev);
+	if (ret < 0) {
+		dev_err(dev, "Failed to register netdev: %d\n", ret);
+		goto out_ndev;
+	}
+
+	wdev->netdev = ndev;
+
+	ret = iwm_rfkill_init(iwm);
+	if (ret) {
+		dev_err(dev, "Failed to init rfkill\n");
+		goto out_rfkill;
+	}
+
+	return iwm;
+
+ out_rfkill:
+	unregister_netdev(ndev);
+
+ out_ndev:
+	free_netdev(ndev);
+
+ out_wdev:
+	iwm_wdev_free(iwm);
+	return ERR_PTR(ret);
+}
+
+void iwm_if_free(struct iwm_priv *iwm)
+{
+	int i;
+
+	if (!iwm_to_ndev(iwm))
+		return;
+
+	iwm_rfkill_exit(iwm);
+	unregister_netdev(iwm_to_ndev(iwm));
+	free_netdev(iwm_to_ndev(iwm));
+	iwm_wdev_free(iwm);
+	destroy_workqueue(iwm->rx_wq);
+	for (i = 0; i < IWM_TX_QUEUES; i++)
+		destroy_workqueue(iwm->txq[i].wq);
+}
diff --git a/drivers/net/wireless/iwmc3200wifi/rfkill.c b/drivers/net/wireless/iwmc3200wifi/rfkill.c
new file mode 100644
index 0000000..4ca8b49
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/rfkill.c
@@ -0,0 +1,88 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/rfkill.h>
+
+#include "iwm.h"
+
+static int iwm_rfkill_soft_toggle(void *data, enum rfkill_state state)
+{
+	struct iwm_priv *iwm = data;
+
+	switch (state) {
+	case RFKILL_STATE_UNBLOCKED:
+		if (test_bit(IWM_RADIO_RFKILL_HW, &iwm->radio))
+			return -EBUSY;
+
+		if (test_and_clear_bit(IWM_RADIO_RFKILL_SW, &iwm->radio) &&
+		    (iwm_to_ndev(iwm)->flags & IFF_UP))
+			iwm_up(iwm);
+
+		break;
+	case RFKILL_STATE_SOFT_BLOCKED:
+		if (!test_and_set_bit(IWM_RADIO_RFKILL_SW, &iwm->radio))
+			iwm_down(iwm);
+
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+int iwm_rfkill_init(struct iwm_priv *iwm)
+{
+	int ret;
+
+	iwm->rfkill = rfkill_allocate(iwm_to_dev(iwm), RFKILL_TYPE_WLAN);
+	if (!iwm->rfkill) {
+		IWM_ERR(iwm, "Unable to allocate rfkill device\n");
+		return -ENOMEM;
+	}
+
+	iwm->rfkill->name = KBUILD_MODNAME;
+	iwm->rfkill->data = iwm;
+	iwm->rfkill->state = RFKILL_STATE_UNBLOCKED;
+	iwm->rfkill->toggle_radio = iwm_rfkill_soft_toggle;
+
+	ret = rfkill_register(iwm->rfkill);
+	if (ret) {
+		IWM_ERR(iwm, "Failed to register rfkill device\n");
+		goto fail;
+	}
+
+	return 0;
+ fail:
+	rfkill_free(iwm->rfkill);
+	return ret;
+}
+
+void iwm_rfkill_exit(struct iwm_priv *iwm)
+{
+	if (iwm->rfkill)
+		rfkill_unregister(iwm->rfkill);
+
+	rfkill_free(iwm->rfkill);
+	iwm->rfkill = NULL;
+}
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
new file mode 100644
index 0000000..d73cf96
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -0,0 +1,1431 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ *
+ * Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <linux/ieee80211.h>
+#include <linux/if_arp.h>
+#include <linux/list.h>
+#include <net/iw_handler.h>
+
+#include "iwm.h"
+#include "debug.h"
+#include "hal.h"
+#include "umac.h"
+#include "lmac.h"
+#include "commands.h"
+#include "rx.h"
+#include "cfg80211.h"
+#include "eeprom.h"
+
+static int iwm_rx_check_udma_hdr(struct iwm_udma_in_hdr *hdr)
+{
+	if ((le32_to_cpu(hdr->cmd) == UMAC_PAD_TERMINAL) ||
+	    (le32_to_cpu(hdr->size) == UMAC_PAD_TERMINAL))
+		return -EINVAL;
+
+	return 0;
+}
+
+static inline int iwm_rx_resp_size(struct iwm_udma_in_hdr *hdr)
+{
+	return ALIGN(le32_to_cpu(hdr->size) + sizeof(struct iwm_udma_in_hdr),
+		     16);
+}
+
+/*
+ * Notification handlers:
+ *
+ * For every possible notification we can receive from the
+ * target, we have a handler.
+ * When we get a target notification, and there is no one
+ * waiting for it, it's just processed through the rx code
+ * path:
+ *
+ * iwm_rx_handle()
+ *  -> iwm_rx_handle_umac()
+ *      -> iwm_rx_handle_wifi()
+ *          -> iwm_rx_handle_resp()
+ *              -> iwm_ntf_*()
+ *
+ *      OR
+ *
+ *      -> iwm_rx_handle_non_wifi()
+ *
+ * If there are processes waiting for this notification, then
+ * iwm_rx_handle_wifi() just wakes those processes up and they
+ * grab the pending notification.
+ */
+static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf,
+			 unsigned long buf_size, struct iwm_wifi_cmd *cmd)
+{
+	struct iwm_umac_notif_error *error;
+	struct iwm_fw_error_hdr *fw_err;
+
+	error = (struct iwm_umac_notif_error *)buf;
+	fw_err = &error->err;
+
+
+	IWM_ERR(iwm, "%cMAC FW ERROR:\n",
+	 (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U');
+	IWM_ERR(iwm, "\tCategory:    %d\n", le32_to_cpu(fw_err->category));
+	IWM_ERR(iwm, "\tStatus:      0x%x\n", le32_to_cpu(fw_err->status));
+	IWM_ERR(iwm, "\tPC:          0x%x\n", le32_to_cpu(fw_err->pc));
+	IWM_ERR(iwm, "\tblink1:      %d\n", le32_to_cpu(fw_err->blink1));
+	IWM_ERR(iwm, "\tblink2:      %d\n", le32_to_cpu(fw_err->blink2));
+	IWM_ERR(iwm, "\tilink1:      %d\n", le32_to_cpu(fw_err->ilink1));
+	IWM_ERR(iwm, "\tilink2:      %d\n", le32_to_cpu(fw_err->ilink2));
+	IWM_ERR(iwm, "\tData1:       0x%x\n", le32_to_cpu(fw_err->data1));
+	IWM_ERR(iwm, "\tData2:       0x%x\n", le32_to_cpu(fw_err->data2));
+	IWM_ERR(iwm, "\tLine number: %d\n", le32_to_cpu(fw_err->line_num));
+	IWM_ERR(iwm, "\tUMAC status: 0x%x\n", le32_to_cpu(fw_err->umac_status));
+	IWM_ERR(iwm, "\tLMAC status: 0x%x\n", le32_to_cpu(fw_err->lmac_status));
+	IWM_ERR(iwm, "\tSDIO status: 0x%x\n", le32_to_cpu(fw_err->sdio_status));
+
+	return 0;
+}
+
+static int iwm_ntf_umac_alive(struct iwm_priv *iwm, u8 *buf,
+			      unsigned long buf_size, struct iwm_wifi_cmd *cmd)
+{
+	struct iwm_umac_notif_alive *alive_resp =
+			(struct iwm_umac_notif_alive *)(buf);
+	u16 status = le16_to_cpu(alive_resp->status);
+
+	if (status == UMAC_NTFY_ALIVE_STATUS_ERR) {
+		IWM_ERR(iwm, "Receive error UMAC_ALIVE\n");
+		return -EIO;
+	}
+
+	iwm_tx_credit_init_pools(iwm, alive_resp);
+
+	return 0;
+}
+
+static int iwm_ntf_init_complete(struct iwm_priv *iwm, u8 *buf,
+				 unsigned long buf_size,
+				 struct iwm_wifi_cmd *cmd)
+{
+	struct iwm_umac_notif_init_complete *init_complete =
+			(struct iwm_umac_notif_init_complete *)(buf);
+	u16 status = le16_to_cpu(init_complete->status);
+
+	if (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR) {
+		IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is on (radio off)\n");
+		set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
+	} else {
+		IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is off (radio on)\n");
+		clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
+	}
+
+	return 0;
+}
+
+static int iwm_ntf_tx_credit_update(struct iwm_priv *iwm, u8 *buf,
+				    unsigned long buf_size,
+				    struct iwm_wifi_cmd *cmd)
+{
+	int pool_nr, total_freed_pages;
+	unsigned long pool_map;
+	int i, id;
+	struct iwm_umac_notif_page_dealloc *dealloc =
+			(struct iwm_umac_notif_page_dealloc *)buf;
+
+	pool_nr = GET_VAL32(dealloc->changes, UMAC_DEALLOC_NTFY_CHANGES_CNT);
+	pool_map = GET_VAL32(dealloc->changes, UMAC_DEALLOC_NTFY_CHANGES_MSK);
+
+	IWM_DBG_TX(iwm, DBG, "UMAC dealloc notification: pool nr %d, "
+		   "update map 0x%lx\n", pool_nr, pool_map);
+
+	spin_lock(&iwm->tx_credit.lock);
+
+	for (i = 0; i < pool_nr; i++) {
+		id = GET_VAL32(dealloc->grp_info[i],
+			       UMAC_DEALLOC_NTFY_GROUP_NUM);
+		if (test_bit(id, &pool_map)) {
+			total_freed_pages = GET_VAL32(dealloc->grp_info[i],
+					      UMAC_DEALLOC_NTFY_PAGE_CNT);
+			iwm_tx_credit_inc(iwm, id, total_freed_pages);
+		}
+	}
+
+	spin_unlock(&iwm->tx_credit.lock);
+
+	return 0;
+}
+
+static int iwm_ntf_umac_reset(struct iwm_priv *iwm, u8 *buf,
+			      unsigned long buf_size, struct iwm_wifi_cmd *cmd)
+{
+	IWM_DBG_NTF(iwm, DBG, "UMAC RESET done\n");
+
+	return 0;
+}
+
+static int iwm_ntf_lmac_version(struct iwm_priv *iwm, u8 *buf,
+				unsigned long buf_size,
+				struct iwm_wifi_cmd *cmd)
+{
+	IWM_DBG_NTF(iwm, INFO, "LMAC Version: %x.%x\n", buf[9], buf[8]);
+
+	return 0;
+}
+
+static int iwm_ntf_tx(struct iwm_priv *iwm, u8 *buf,
+		      unsigned long buf_size, struct iwm_wifi_cmd *cmd)
+{
+	struct iwm_lmac_tx_resp *tx_resp;
+	struct iwm_umac_wifi_in_hdr *hdr;
+
+	tx_resp = (struct iwm_lmac_tx_resp *)
+		(buf + sizeof(struct iwm_umac_wifi_in_hdr));
+	hdr = (struct iwm_umac_wifi_in_hdr *)buf;
+
+	IWM_DBG_NTF(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size);
+
+	IWM_DBG_NTF(iwm, DBG, "Seqnum: %d\n",
+		    le16_to_cpu(hdr->sw_hdr.cmd.seq_num));
+	IWM_DBG_NTF(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt);
+	IWM_DBG_NTF(iwm, DBG, "\tRetry cnt: %d\n",
+		    le16_to_cpu(tx_resp->retry_cnt));
+	IWM_DBG_NTF(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl));
+	IWM_DBG_NTF(iwm, DBG, "\tByte cnt: %d\n",
+		    le16_to_cpu(tx_resp->byte_cnt));
+	IWM_DBG_NTF(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status));
+
+	return 0;
+}
+
+
+static int iwm_ntf_calib_res(struct iwm_priv *iwm, u8 *buf,
+			     unsigned long buf_size, struct iwm_wifi_cmd *cmd)
+{
+	u8 opcode;
+	u8 *calib_buf;
+	struct iwm_lmac_calib_hdr *hdr = (struct iwm_lmac_calib_hdr *)
+				(buf + sizeof(struct iwm_umac_wifi_in_hdr));
+
+	opcode = hdr->opcode;
+
+	BUG_ON(opcode >= CALIBRATION_CMD_NUM ||
+	       opcode < PHY_CALIBRATE_OPCODES_NUM);
+
+	IWM_DBG_NTF(iwm, DBG, "Store calibration result for opcode: %d\n",
+		    opcode);
+
+	buf_size -= sizeof(struct iwm_umac_wifi_in_hdr);
+	calib_buf = iwm->calib_res[opcode].buf;
+
+	if (!calib_buf || (iwm->calib_res[opcode].size < buf_size)) {
+		kfree(calib_buf);
+		calib_buf = kzalloc(buf_size, GFP_KERNEL);
+		if (!calib_buf) {
+			IWM_ERR(iwm, "Memory allocation failed: calib_res\n");
+			return -ENOMEM;
+		}
+		iwm->calib_res[opcode].buf = calib_buf;
+		iwm->calib_res[opcode].size = buf_size;
+	}
+
+	memcpy(calib_buf, hdr, buf_size);
+	set_bit(opcode - PHY_CALIBRATE_OPCODES_NUM, &iwm->calib_done_map);
+
+	return 0;
+}
+
+static int iwm_ntf_calib_complete(struct iwm_priv *iwm, u8 *buf,
+				  unsigned long buf_size,
+				  struct iwm_wifi_cmd *cmd)
+{
+	IWM_DBG_NTF(iwm, DBG, "Calibration completed\n");
+
+	return 0;
+}
+
+static int iwm_ntf_calib_cfg(struct iwm_priv *iwm, u8 *buf,
+			     unsigned long buf_size, struct iwm_wifi_cmd *cmd)
+{
+	struct iwm_lmac_cal_cfg_resp *cal_resp;
+
+	cal_resp = (struct iwm_lmac_cal_cfg_resp *)
+			(buf + sizeof(struct iwm_umac_wifi_in_hdr));
+
+	IWM_DBG_NTF(iwm, DBG, "Calibration CFG command status: %d\n",
+		    le32_to_cpu(cal_resp->status));
+
+	return 0;
+}
+
+static int iwm_ntf_wifi_status(struct iwm_priv *iwm, u8 *buf,
+			       unsigned long buf_size, struct iwm_wifi_cmd *cmd)
+{
+	struct iwm_umac_notif_wifi_status *status =
+		(struct iwm_umac_notif_wifi_status *)buf;
+
+	iwm->core_enabled |= le16_to_cpu(status->status);
+
+	return 0;
+}
+
+static struct iwm_rx_ticket_node *
+iwm_rx_ticket_node_alloc(struct iwm_priv *iwm, struct iwm_rx_ticket *ticket)
+{
+	struct iwm_rx_ticket_node *ticket_node;
+
+	ticket_node = kzalloc(sizeof(struct iwm_rx_ticket_node), GFP_KERNEL);
+	if (!ticket_node) {
+		IWM_ERR(iwm, "Couldn't allocate ticket node\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	ticket_node->ticket = kzalloc(sizeof(struct iwm_rx_ticket), GFP_KERNEL);
+	if (!ticket_node->ticket) {
+		IWM_ERR(iwm, "Couldn't allocate RX ticket\n");
+		kfree(ticket_node);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	memcpy(ticket_node->ticket, ticket, sizeof(struct iwm_rx_ticket));
+	INIT_LIST_HEAD(&ticket_node->node);
+
+	return ticket_node;
+}
+
+static void iwm_rx_ticket_node_free(struct iwm_rx_ticket_node *ticket_node)
+{
+	kfree(ticket_node->ticket);
+	kfree(ticket_node);
+}
+
+static struct iwm_rx_packet *iwm_rx_packet_get(struct iwm_priv *iwm, u16 id)
+{
+	u8 id_hash = IWM_RX_ID_GET_HASH(id);
+	struct list_head *packet_list;
+	struct iwm_rx_packet *packet, *next;
+
+	packet_list = &iwm->rx_packets[id_hash];
+
+	list_for_each_entry_safe(packet, next, packet_list, node)
+		if (packet->id == id)
+			return packet;
+
+	return NULL;
+}
+
+static struct iwm_rx_packet *iwm_rx_packet_alloc(struct iwm_priv *iwm, u8 *buf,
+						 u32 size, u16 id)
+{
+	struct iwm_rx_packet *packet;
+
+	packet = kzalloc(sizeof(struct iwm_rx_packet), GFP_KERNEL);
+	if (!packet) {
+		IWM_ERR(iwm, "Couldn't allocate packet\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	packet->skb = dev_alloc_skb(size);
+	if (!packet->skb) {
+		IWM_ERR(iwm, "Couldn't allocate packet SKB\n");
+		kfree(packet);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	packet->pkt_size = size;
+
+	skb_put(packet->skb, size);
+	memcpy(packet->skb->data, buf, size);
+	INIT_LIST_HEAD(&packet->node);
+	packet->id = id;
+
+	return packet;
+}
+
+void iwm_rx_free(struct iwm_priv *iwm)
+{
+	struct iwm_rx_ticket_node *ticket, *nt;
+	struct iwm_rx_packet *packet, *np;
+	int i;
+
+	list_for_each_entry_safe(ticket, nt, &iwm->rx_tickets, node) {
+		list_del(&ticket->node);
+		iwm_rx_ticket_node_free(ticket);
+	}
+
+	for (i = 0; i < IWM_RX_ID_HASH; i++) {
+		list_for_each_entry_safe(packet, np, &iwm->rx_packets[i],
+					 node) {
+			list_del(&packet->node);
+			kfree_skb(packet->skb);
+			kfree(packet);
+		}
+	}
+}
+
+static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf,
+			     unsigned long buf_size, struct iwm_wifi_cmd *cmd)
+{
+	struct iwm_umac_notif_rx_ticket *ntf_rx_ticket =
+		(struct iwm_umac_notif_rx_ticket *)buf;
+	struct iwm_rx_ticket *ticket =
+		(struct iwm_rx_ticket *)ntf_rx_ticket->tickets;
+	int i, schedule_rx = 0;
+
+	for (i = 0; i < ntf_rx_ticket->num_tickets; i++) {
+		struct iwm_rx_ticket_node *ticket_node;
+
+		switch (le16_to_cpu(ticket->action)) {
+		case IWM_RX_TICKET_RELEASE:
+		case IWM_RX_TICKET_DROP:
+			/* We can push the packet to the stack */
+			ticket_node = iwm_rx_ticket_node_alloc(iwm, ticket);
+			if (IS_ERR(ticket_node))
+				return PTR_ERR(ticket_node);
+
+			IWM_DBG_NTF(iwm, DBG, "TICKET RELEASE(%d)\n",
+				    ticket->id);
+			list_add_tail(&ticket_node->node, &iwm->rx_tickets);
+
+			/*
+			 * We received an Rx ticket, most likely there's
+			 * a packet pending for it, it's not worth going
+			 * through the packet hash list to double check.
+			 * Let's just fire the rx worker..
+			 */
+			schedule_rx = 1;
+
+			break;
+
+		default:
+			IWM_ERR(iwm, "Invalid RX ticket action: 0x%x\n",
+				ticket->action);
+		}
+
+		ticket++;
+	}
+
+	if (schedule_rx)
+		queue_work(iwm->rx_wq, &iwm->rx_worker);
+
+	return 0;
+}
+
+static int iwm_ntf_rx_packet(struct iwm_priv *iwm, u8 *buf,
+			     unsigned long buf_size, struct iwm_wifi_cmd *cmd)
+{
+	struct iwm_umac_wifi_in_hdr *wifi_hdr;
+	struct iwm_rx_packet *packet;
+	u16 id, buf_offset;
+	u32 packet_size;
+
+	IWM_DBG_NTF(iwm, DBG, "\n");
+
+	wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf;
+	id = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num);
+	buf_offset = sizeof(struct iwm_umac_wifi_in_hdr);
+	packet_size = buf_size - sizeof(struct iwm_umac_wifi_in_hdr);
+
+	IWM_DBG_NTF(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n",
+		    wifi_hdr->sw_hdr.cmd.cmd, id, packet_size);
+	IWM_DBG_RX(iwm, DBG, "Packet id: %d\n", id);
+	IWM_HEXDUMP(iwm, DBG, RX, "PACKET: ", buf + buf_offset, packet_size);
+
+	packet = iwm_rx_packet_alloc(iwm, buf + buf_offset, packet_size, id);
+	if (IS_ERR(packet))
+		return PTR_ERR(packet);
+
+	list_add_tail(&packet->node, &iwm->rx_packets[IWM_RX_ID_GET_HASH(id)]);
+
+	/* We might (unlikely) have received the packet _after_ the ticket */
+	queue_work(iwm->rx_wq, &iwm->rx_worker);
+
+	return 0;
+}
+
+/* MLME handlers */
+static int iwm_mlme_assoc_start(struct iwm_priv *iwm, u8 *buf,
+				unsigned long buf_size,
+				struct iwm_wifi_cmd *cmd)
+{
+	struct iwm_umac_notif_assoc_start *start;
+
+	start = (struct iwm_umac_notif_assoc_start *)buf;
+
+	set_bit(IWM_STATUS_ASSOCIATING, &iwm->status);
+
+	IWM_DBG_MLME(iwm, INFO, "Association with %pM Started, reason: %d\n",
+		     start->bssid, le32_to_cpu(start->roam_reason));
+
+	wake_up_interruptible(&iwm->mlme_queue);
+
+	return 0;
+}
+
+static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
+				   unsigned long buf_size,
+				   struct iwm_wifi_cmd *cmd)
+{
+	struct iwm_umac_notif_assoc_complete *complete =
+		(struct iwm_umac_notif_assoc_complete *)buf;
+	union iwreq_data wrqu;
+
+	IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n",
+		     complete->bssid, complete->status);
+
+	memset(&wrqu, 0, sizeof(wrqu));
+
+	clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status);
+
+	switch (le32_to_cpu(complete->status)) {
+	case UMAC_ASSOC_COMPLETE_SUCCESS:
+		set_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
+		memcpy(iwm->bssid, complete->bssid, ETH_ALEN);
+		iwm->channel = complete->channel;
+
+		iwm_link_on(iwm);
+
+		memcpy(wrqu.ap_addr.sa_data, complete->bssid, ETH_ALEN);
+		break;
+	case UMAC_ASSOC_COMPLETE_FAILURE:
+		clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
+		memset(iwm->bssid, 0, ETH_ALEN);
+		iwm->channel = 0;
+
+		iwm_link_off(iwm);
+	default:
+		break;
+	}
+
+	if (iwm->conf.mode == UMAC_MODE_IBSS) {
+		cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL);
+		return 0;
+	}
+
+	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+	wireless_send_event(iwm_to_ndev(iwm), SIOCGIWAP, &wrqu, NULL);
+
+	return 0;
+}
+
+static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf,
+				       unsigned long buf_size,
+				       struct iwm_wifi_cmd *cmd)
+{
+	struct iwm_umac_notif_profile_invalidate *invalid;
+
+	invalid = (struct iwm_umac_notif_profile_invalidate *)buf;
+
+	IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n",
+		     le32_to_cpu(invalid->reason));
+
+	clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status);
+	clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
+
+	iwm->umac_profile_active = 0;
+	memset(iwm->bssid, 0, ETH_ALEN);
+	iwm->channel = 0;
+
+	iwm_link_off(iwm);
+
+	wake_up_interruptible(&iwm->mlme_queue);
+
+	return 0;
+}
+
+static int iwm_mlme_scan_complete(struct iwm_priv *iwm, u8 *buf,
+				  unsigned long buf_size,
+				  struct iwm_wifi_cmd *cmd)
+{
+	int ret;
+	struct iwm_umac_notif_scan_complete *scan_complete =
+		(struct iwm_umac_notif_scan_complete *)buf;
+	u32 result = le32_to_cpu(scan_complete->result);
+
+	IWM_DBG_MLME(iwm, INFO, "type:0x%x result:0x%x seq:%d\n",
+		     le32_to_cpu(scan_complete->type),
+		     le32_to_cpu(scan_complete->result),
+		     scan_complete->seq_num);
+
+	if (!test_and_clear_bit(IWM_STATUS_SCANNING, &iwm->status)) {
+		IWM_ERR(iwm, "Scan complete while device not scanning\n");
+		return -EIO;
+	}
+	if (!iwm->scan_request)
+		return 0;
+
+	ret = iwm_cfg80211_inform_bss(iwm);
+
+	cfg80211_scan_done(iwm->scan_request,
+			   (result & UMAC_SCAN_RESULT_ABORTED) ? 1 : !!ret);
+	iwm->scan_request = NULL;
+
+	return ret;
+}
+
+static int iwm_mlme_update_sta_table(struct iwm_priv *iwm, u8 *buf,
+				     unsigned long buf_size,
+				     struct iwm_wifi_cmd *cmd)
+{
+	struct iwm_umac_notif_sta_info *umac_sta =
+			(struct iwm_umac_notif_sta_info *)buf;
+	struct iwm_sta_info *sta;
+	int i;
+
+	switch (le32_to_cpu(umac_sta->opcode)) {
+	case UMAC_OPCODE_ADD_MODIFY:
+		sta = &iwm->sta_table[GET_VAL8(umac_sta->sta_id, LMAC_STA_ID)];
+
+		IWM_DBG_MLME(iwm, INFO, "%s STA: ID = %d, Color = %d, "
+			     "addr = %pM, qos = %d\n",
+			     sta->valid ? "Modify" : "Add",
+			     GET_VAL8(umac_sta->sta_id, LMAC_STA_ID),
+			     GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR),
+			     umac_sta->mac_addr,
+			     umac_sta->flags & UMAC_STA_FLAG_QOS);
+
+		sta->valid = 1;
+		sta->qos = umac_sta->flags & UMAC_STA_FLAG_QOS;
+		sta->color = GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR);
+		memcpy(sta->addr, umac_sta->mac_addr, ETH_ALEN);
+		break;
+	case UMAC_OPCODE_REMOVE:
+		IWM_DBG_MLME(iwm, INFO, "Remove STA: ID = %d, Color = %d, "
+			     "addr = %pM\n",
+			     GET_VAL8(umac_sta->sta_id, LMAC_STA_ID),
+			     GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR),
+			     umac_sta->mac_addr);
+
+		sta = &iwm->sta_table[GET_VAL8(umac_sta->sta_id, LMAC_STA_ID)];
+
+		if (!memcmp(sta->addr, umac_sta->mac_addr, ETH_ALEN))
+			sta->valid = 0;
+
+		break;
+	case UMAC_OPCODE_CLEAR_ALL:
+		for (i = 0; i < IWM_STA_TABLE_NUM; i++)
+			iwm->sta_table[i].valid = 0;
+
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf,
+				     unsigned long buf_size,
+				     struct iwm_wifi_cmd *cmd)
+{
+	struct wiphy *wiphy = iwm_to_wiphy(iwm);
+	struct ieee80211_mgmt *mgmt;
+	struct iwm_umac_notif_bss_info *umac_bss =
+			(struct iwm_umac_notif_bss_info *)buf;
+	struct ieee80211_channel *channel;
+	struct ieee80211_supported_band *band;
+	struct iwm_bss_info *bss, *next;
+	s32 signal;
+	int freq;
+	u16 frame_len = le16_to_cpu(umac_bss->frame_len);
+	size_t bss_len = sizeof(struct iwm_umac_notif_bss_info) + frame_len;
+
+	mgmt = (struct ieee80211_mgmt *)(umac_bss->frame_buf);
+
+	IWM_DBG_MLME(iwm, DBG, "New BSS info entry: %pM\n", mgmt->bssid);
+	IWM_DBG_MLME(iwm, DBG, "\tType: 0x%x\n", le32_to_cpu(umac_bss->type));
+	IWM_DBG_MLME(iwm, DBG, "\tTimestamp: %d\n",
+		     le32_to_cpu(umac_bss->timestamp));
+	IWM_DBG_MLME(iwm, DBG, "\tTable Index: %d\n",
+		     le16_to_cpu(umac_bss->table_idx));
+	IWM_DBG_MLME(iwm, DBG, "\tBand: %d\n", umac_bss->band);
+	IWM_DBG_MLME(iwm, DBG, "\tChannel: %d\n", umac_bss->channel);
+	IWM_DBG_MLME(iwm, DBG, "\tRSSI: %d\n", umac_bss->rssi);
+	IWM_DBG_MLME(iwm, DBG, "\tFrame Length: %d\n", frame_len);
+
+	list_for_each_entry_safe(bss, next, &iwm->bss_list, node)
+		if (bss->bss->table_idx == umac_bss->table_idx)
+			break;
+
+	if (&bss->node != &iwm->bss_list) {
+		/* Remove the old BSS entry, we will add it back later. */
+		list_del(&bss->node);
+		kfree(bss->bss);
+	} else {
+		/* New BSS entry */
+
+		bss = kzalloc(sizeof(struct iwm_bss_info), GFP_KERNEL);
+		if (!bss) {
+			IWM_ERR(iwm, "Couldn't allocate bss_info\n");
+			return -ENOMEM;
+		}
+	}
+
+	bss->bss = kzalloc(bss_len, GFP_KERNEL);
+	if (!bss) {
+		kfree(bss);
+		IWM_ERR(iwm, "Couldn't allocate bss\n");
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&bss->node);
+	memcpy(bss->bss, umac_bss, bss_len);
+
+	if (umac_bss->band == UMAC_BAND_2GHZ)
+		band = wiphy->bands[IEEE80211_BAND_2GHZ];
+	else if (umac_bss->band == UMAC_BAND_5GHZ)
+		band = wiphy->bands[IEEE80211_BAND_5GHZ];
+	else {
+		IWM_ERR(iwm, "Invalid band: %d\n", umac_bss->band);
+		goto err;
+	}
+
+	freq = ieee80211_channel_to_frequency(umac_bss->channel);
+	channel = ieee80211_get_channel(wiphy, freq);
+	signal = umac_bss->rssi * 100;
+
+	bss->cfg_bss = cfg80211_inform_bss_frame(wiphy, channel,
+						 mgmt, frame_len,
+						 signal, GFP_KERNEL);
+	if (!bss->cfg_bss)
+		goto err;
+
+	list_add_tail(&bss->node, &iwm->bss_list);
+
+	return 0;
+ err:
+	kfree(bss->bss);
+	kfree(bss);
+
+	return -EINVAL;
+}
+
+static int iwm_mlme_remove_bss(struct iwm_priv *iwm, u8 *buf,
+			       unsigned long buf_size, struct iwm_wifi_cmd *cmd)
+{
+	struct iwm_umac_notif_bss_removed *bss_rm =
+		(struct iwm_umac_notif_bss_removed *)buf;
+	struct iwm_bss_info *bss, *next;
+	u16 table_idx;
+	int i;
+
+	for (i = 0; i < le32_to_cpu(bss_rm->count); i++) {
+		table_idx = (le16_to_cpu(bss_rm->entries[i])
+			     & IWM_BSS_REMOVE_INDEX_MSK);
+		list_for_each_entry_safe(bss, next, &iwm->bss_list, node)
+			if (bss->bss->table_idx == cpu_to_le16(table_idx)) {
+				struct ieee80211_mgmt *mgmt;
+
+				mgmt = (struct ieee80211_mgmt *)
+					(bss->bss->frame_buf);
+				IWM_DBG_MLME(iwm, ERR,
+					     "BSS removed: %pM\n",
+					     mgmt->bssid);
+				list_del(&bss->node);
+				kfree(bss->bss);
+				kfree(bss);
+			}
+	}
+
+	return 0;
+}
+
+static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf,
+			      unsigned long buf_size, struct iwm_wifi_cmd *cmd)
+{
+	struct iwm_umac_notif_mgt_frame *mgt_frame =
+	(struct iwm_umac_notif_mgt_frame *)buf;
+	struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame;
+	u8 *ie;
+	unsigned int event;
+	union iwreq_data wrqu;
+
+	IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame,
+		    le16_to_cpu(mgt_frame->len));
+
+	if (ieee80211_is_assoc_req(mgt->frame_control)) {
+		ie = mgt->u.assoc_req.variable;;
+		event = IWEVASSOCREQIE;
+	} else if (ieee80211_is_reassoc_req(mgt->frame_control)) {
+		ie = mgt->u.reassoc_req.variable;;
+		event = IWEVASSOCREQIE;
+	} else if (ieee80211_is_assoc_resp(mgt->frame_control)) {
+		ie = mgt->u.assoc_resp.variable;;
+		event = IWEVASSOCRESPIE;
+	} else if (ieee80211_is_reassoc_resp(mgt->frame_control)) {
+		ie = mgt->u.reassoc_resp.variable;;
+		event = IWEVASSOCRESPIE;
+	} else {
+		IWM_ERR(iwm, "Unsupported management frame");
+		return 0;
+	}
+
+	wrqu.data.length = le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+
+	IWM_HEXDUMP(iwm, DBG, MLME, "EVT: ", ie, wrqu.data.length);
+	wireless_send_event(iwm_to_ndev(iwm), event, &wrqu, ie);
+
+	return 0;
+}
+
+static int iwm_ntf_mlme(struct iwm_priv *iwm, u8 *buf,
+			unsigned long buf_size, struct iwm_wifi_cmd *cmd)
+{
+	struct iwm_umac_notif_wifi_if *notif =
+		(struct iwm_umac_notif_wifi_if *)buf;
+
+	switch (notif->status) {
+	case WIFI_IF_NTFY_ASSOC_START:
+		return iwm_mlme_assoc_start(iwm, buf, buf_size, cmd);
+	case WIFI_IF_NTFY_ASSOC_COMPLETE:
+		return iwm_mlme_assoc_complete(iwm, buf, buf_size, cmd);
+	case WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE:
+		return iwm_mlme_profile_invalidate(iwm, buf, buf_size, cmd);
+	case WIFI_IF_NTFY_CONNECTION_TERMINATED:
+		IWM_DBG_MLME(iwm, DBG, "Connection terminated\n");
+		break;
+	case WIFI_IF_NTFY_SCAN_COMPLETE:
+		return iwm_mlme_scan_complete(iwm, buf, buf_size, cmd);
+	case WIFI_IF_NTFY_STA_TABLE_CHANGE:
+		return iwm_mlme_update_sta_table(iwm, buf, buf_size, cmd);
+	case WIFI_IF_NTFY_EXTENDED_IE_REQUIRED:
+		IWM_DBG_MLME(iwm, DBG, "Extended IE required\n");
+		break;
+	case WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED:
+		return iwm_mlme_update_bss_table(iwm, buf, buf_size, cmd);
+	case WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED:
+		return iwm_mlme_remove_bss(iwm, buf, buf_size, cmd);
+		break;
+	case WIFI_IF_NTFY_MGMT_FRAME:
+		return iwm_mlme_mgt_frame(iwm, buf, buf_size, cmd);
+	case WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_START:
+	case WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_COMPLETE:
+	case WIFI_DBG_IF_NTFY_SCAN_CHANNEL_START:
+	case WIFI_DBG_IF_NTFY_SCAN_CHANNEL_RESULT:
+	case WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_START:
+	case WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_COMPLETE:
+	case WIFI_DBG_IF_NTFY_CNCT_ATC_START:
+	case WIFI_DBG_IF_NTFY_COEX_NOTIFICATION:
+	case WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP:
+	case WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP:
+		IWM_DBG_MLME(iwm, DBG, "MLME debug notification: 0x%x\n",
+			     notif->status);
+		break;
+	default:
+		IWM_ERR(iwm, "Unhandled notification: 0x%x\n", notif->status);
+		break;
+	}
+
+	return 0;
+}
+
+#define IWM_STATS_UPDATE_INTERVAL		(2 * HZ)
+
+static int iwm_ntf_statistics(struct iwm_priv *iwm, u8 *buf,
+			      unsigned long buf_size, struct iwm_wifi_cmd *cmd)
+{
+	struct iwm_umac_notif_stats *stats = (struct iwm_umac_notif_stats *)buf;
+	struct iw_statistics *wstats = &iwm->wstats;
+	u16 max_rate = 0;
+	int i;
+
+	IWM_DBG_MLME(iwm, DBG, "Statistics notification received\n");
+
+	if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
+		for (i = 0; i < UMAC_NTF_RATE_SAMPLE_NR; i++) {
+			max_rate = max_t(u16, max_rate,
+					 max(le16_to_cpu(stats->tx_rate[i]),
+					     le16_to_cpu(stats->rx_rate[i])));
+		}
+		/* UMAC passes rate info multiplies by 2 */
+		iwm->rate = max_rate >> 1;
+	}
+
+	wstats->status = 0;
+
+	wstats->discard.nwid = le32_to_cpu(stats->rx_drop_other_bssid);
+	wstats->discard.code = le32_to_cpu(stats->rx_drop_decode);
+	wstats->discard.fragment = le32_to_cpu(stats->rx_drop_reassembly);
+	wstats->discard.retries = le32_to_cpu(stats->tx_drop_max_retry);
+
+	wstats->miss.beacon = le32_to_cpu(stats->missed_beacons);
+
+	/* according to cfg80211 */
+	if (stats->rssi_dbm < -110)
+		wstats->qual.qual = 0;
+	else if (stats->rssi_dbm > -40)
+		wstats->qual.qual = 70;
+	else
+		wstats->qual.qual = stats->rssi_dbm + 110;
+
+	wstats->qual.level = stats->rssi_dbm;
+	wstats->qual.noise = stats->noise_dbm;
+	wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+
+	schedule_delayed_work(&iwm->stats_request, IWM_STATS_UPDATE_INTERVAL);
+
+	mod_timer(&iwm->watchdog, round_jiffies(jiffies + IWM_WATCHDOG_PERIOD));
+
+	return 0;
+}
+
+static int iwm_ntf_eeprom_proxy(struct iwm_priv *iwm, u8 *buf,
+				unsigned long buf_size,
+				struct iwm_wifi_cmd *cmd)
+{
+	struct iwm_umac_cmd_eeprom_proxy *eeprom_proxy =
+		(struct iwm_umac_cmd_eeprom_proxy *)
+		(buf + sizeof(struct iwm_umac_wifi_in_hdr));
+	struct iwm_umac_cmd_eeprom_proxy_hdr *hdr = &eeprom_proxy->hdr;
+	u32 hdr_offset = le32_to_cpu(hdr->offset);
+	u32 hdr_len = le32_to_cpu(hdr->len);
+	u32 hdr_type = le32_to_cpu(hdr->type);
+
+	IWM_DBG_NTF(iwm, DBG, "type: 0x%x, len: %d, offset: 0x%x\n",
+		    hdr_type, hdr_len, hdr_offset);
+
+	if ((hdr_offset + hdr_len) > IWM_EEPROM_LEN)
+		return -EINVAL;
+
+#ifdef CONFIG_IWM_B0_HW_SUPPORT
+	if (hdr_offset == IWM_EEPROM_SKU_CAP_OFF) {
+		if (eeprom_proxy->buf[0] == 0xff)
+			iwm->conf.hw_b0 = 1;
+	}
+#endif
+
+	switch (hdr_type) {
+	case IWM_UMAC_CMD_EEPROM_TYPE_READ:
+		memcpy(iwm->eeprom + hdr_offset, eeprom_proxy->buf, hdr_len);
+		break;
+	case IWM_UMAC_CMD_EEPROM_TYPE_WRITE:
+	default:
+		return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+static int iwm_ntf_channel_info_list(struct iwm_priv *iwm, u8 *buf,
+				     unsigned long buf_size,
+				     struct iwm_wifi_cmd *cmd)
+{
+	struct iwm_umac_cmd_get_channel_list *ch_list =
+			(struct iwm_umac_cmd_get_channel_list *)
+			(buf + sizeof(struct iwm_umac_wifi_in_hdr));
+	struct wiphy *wiphy = iwm_to_wiphy(iwm);
+	struct ieee80211_supported_band *band;
+	int i;
+
+	band = wiphy->bands[IEEE80211_BAND_2GHZ];
+
+	for (i = 0; i < band->n_channels; i++) {
+		unsigned long ch_mask_0 =
+			le32_to_cpu(ch_list->ch[0].channels_mask);
+		unsigned long ch_mask_2 =
+			le32_to_cpu(ch_list->ch[2].channels_mask);
+
+		if (!test_bit(i, &ch_mask_0))
+			band->channels[i].flags |= IEEE80211_CHAN_DISABLED;
+
+		if (!test_bit(i, &ch_mask_2))
+			band->channels[i].flags |= IEEE80211_CHAN_NO_IBSS;
+	}
+
+	band = wiphy->bands[IEEE80211_BAND_5GHZ];
+
+	for (i = 0; i < min(band->n_channels, 32); i++) {
+		unsigned long ch_mask_1 =
+			le32_to_cpu(ch_list->ch[1].channels_mask);
+		unsigned long ch_mask_3 =
+			le32_to_cpu(ch_list->ch[3].channels_mask);
+
+		if (!test_bit(i, &ch_mask_1))
+			band->channels[i].flags |= IEEE80211_CHAN_DISABLED;
+
+		if (!test_bit(i, &ch_mask_3))
+			band->channels[i].flags |= IEEE80211_CHAN_NO_IBSS;
+	}
+
+	return 0;
+}
+
+static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
+				   unsigned long buf_size,
+				   struct iwm_wifi_cmd *cmd)
+{
+	struct iwm_umac_wifi_if *hdr =
+			(struct iwm_umac_wifi_if *)cmd->buf.payload;
+
+	IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: "
+		    "oid is %d\n", hdr->oid);
+
+	switch (hdr->oid) {
+	case UMAC_WIFI_IF_CMD_SET_PROFILE:
+		iwm->umac_profile_active = 1;
+		wake_up_interruptible(&iwm->mlme_queue);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
+			      unsigned long buf_size, struct iwm_wifi_cmd *cmd)
+{
+	struct iwm_lmac_card_state *state = (struct iwm_lmac_card_state *)
+				(buf + sizeof(struct iwm_umac_wifi_in_hdr));
+	u32 flags = le32_to_cpu(state->flags);
+
+	IWM_INFO(iwm, "HW RF Kill %s, CT Kill %s\n",
+		 flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF",
+		 flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF");
+
+	if (flags & IWM_CARD_STATE_HW_DISABLED)
+		set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
+	else
+		clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
+
+	return 0;
+}
+
+static int iwm_rx_handle_wifi(struct iwm_priv *iwm, u8 *buf,
+			      unsigned long buf_size)
+{
+	struct iwm_umac_wifi_in_hdr *wifi_hdr;
+	struct iwm_wifi_cmd *cmd;
+	u8 source, cmd_id;
+	u16 seq_num;
+	u32 count;
+	u8 resp;
+
+	wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf;
+	cmd_id = wifi_hdr->sw_hdr.cmd.cmd;
+
+	source = GET_VAL32(wifi_hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE);
+	if (source >= IWM_SRC_NUM) {
+		IWM_CRIT(iwm, "invalid source %d\n", source);
+		return -EINVAL;
+	}
+
+	count = (GET_VAL32(wifi_hdr->sw_hdr.meta_data, UMAC_FW_CMD_BYTE_COUNT));
+	count += sizeof(struct iwm_umac_wifi_in_hdr) -
+		 sizeof(struct iwm_dev_cmd_hdr);
+	if (count > buf_size) {
+		IWM_CRIT(iwm, "count %d, buf size:%ld\n", count, buf_size);
+		return -EINVAL;
+	}
+
+	resp = GET_VAL32(wifi_hdr->sw_hdr.meta_data, UMAC_FW_CMD_STATUS);
+
+	seq_num = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num);
+
+	IWM_DBG_RX(iwm, DBG, "CMD:0x%x, source: 0x%x, seqnum: %d\n",
+		   cmd_id, source, seq_num);
+
+	/*
+	 * If this is a response to a previously sent command, there must
+	 * be a pending command for this sequence number.
+	 */
+	cmd = iwm_get_pending_wifi_cmd(iwm, seq_num);
+
+	/* Notify the caller only for sync commands. */
+	switch (source) {
+	case UMAC_HDI_IN_SOURCE_FHRX:
+		if (iwm->lmac_handlers[cmd_id] &&
+		    test_bit(cmd_id, &iwm->lmac_handler_map[0]))
+			return iwm_notif_send(iwm, cmd, cmd_id, source,
+					      buf, count);
+		break;
+	case UMAC_HDI_IN_SOURCE_FW:
+		if (iwm->umac_handlers[cmd_id] &&
+		    test_bit(cmd_id, &iwm->umac_handler_map[0]))
+			return iwm_notif_send(iwm, cmd, cmd_id, source,
+					      buf, count);
+		break;
+	case UMAC_HDI_IN_SOURCE_UDMA:
+		break;
+	}
+
+	return iwm_rx_handle_resp(iwm, buf, count, cmd);
+}
+
+int iwm_rx_handle_resp(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size,
+		       struct iwm_wifi_cmd *cmd)
+{
+	u8 source, cmd_id;
+	struct iwm_umac_wifi_in_hdr *wifi_hdr;
+	int ret = 0;
+
+	wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf;
+	cmd_id = wifi_hdr->sw_hdr.cmd.cmd;
+
+	source = GET_VAL32(wifi_hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE);
+
+	IWM_DBG_RX(iwm, DBG, "CMD:0x%x, source: 0x%x\n", cmd_id, source);
+
+	switch (source) {
+	case UMAC_HDI_IN_SOURCE_FHRX:
+		if (iwm->lmac_handlers[cmd_id])
+			ret = iwm->lmac_handlers[cmd_id]
+					(iwm, buf, buf_size, cmd);
+		break;
+	case UMAC_HDI_IN_SOURCE_FW:
+		if (iwm->umac_handlers[cmd_id])
+			ret = iwm->umac_handlers[cmd_id]
+					(iwm, buf, buf_size, cmd);
+		break;
+	case UMAC_HDI_IN_SOURCE_UDMA:
+		ret = -EINVAL;
+		break;
+	}
+
+	kfree(cmd);
+
+	return ret;
+}
+
+static int iwm_rx_handle_nonwifi(struct iwm_priv *iwm, u8 *buf,
+				 unsigned long buf_size)
+{
+	u8 seq_num;
+	struct iwm_udma_in_hdr *hdr = (struct iwm_udma_in_hdr *)buf;
+	struct iwm_nonwifi_cmd *cmd, *next;
+
+	seq_num = GET_VAL32(hdr->cmd, UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM);
+
+	/*
+	 * We received a non wifi answer.
+	 * Let's check if there's a pending command for it, and if so
+	 * replace the command payload with the buffer, and then wake the
+	 * callers up.
+	 * That means we only support synchronised non wifi command response
+	 * schemes.
+	 */
+	list_for_each_entry_safe(cmd, next, &iwm->nonwifi_pending_cmd, pending)
+		if (cmd->seq_num == seq_num) {
+			cmd->resp_received = 1;
+			cmd->buf.len = buf_size;
+			memcpy(cmd->buf.hdr, buf, buf_size);
+			wake_up_interruptible(&iwm->nonwifi_queue);
+		}
+
+	return 0;
+}
+
+static int iwm_rx_handle_umac(struct iwm_priv *iwm, u8 *buf,
+			      unsigned long buf_size)
+{
+	int ret = 0;
+	u8 op_code;
+	unsigned long buf_offset = 0;
+	struct iwm_udma_in_hdr *hdr;
+
+	/*
+	 * To allow for a more efficient bus usage, UMAC
+	 * messages are encapsulated into UDMA ones. This
+	 * way we can have several UMAC messages in one bus
+	 * transfer.
+	 * A UDMA frame size is always aligned on 16 bytes,
+	 * and a UDMA frame must not start with a UMAC_PAD_TERMINAL
+	 * word. This is how we parse a bus frame into several
+	 * UDMA ones.
+	 */
+	while (buf_offset < buf_size) {
+
+		hdr = (struct iwm_udma_in_hdr *)(buf + buf_offset);
+
+		if (iwm_rx_check_udma_hdr(hdr) < 0) {
+			IWM_DBG_RX(iwm, DBG, "End of frame\n");
+			break;
+		}
+
+		op_code = GET_VAL32(hdr->cmd, UMAC_HDI_IN_CMD_OPCODE);
+
+		IWM_DBG_RX(iwm, DBG, "Op code: 0x%x\n", op_code);
+
+		if (op_code == UMAC_HDI_IN_OPCODE_WIFI) {
+			ret |= iwm_rx_handle_wifi(iwm, buf + buf_offset,
+						  buf_size - buf_offset);
+		} else if (op_code < UMAC_HDI_IN_OPCODE_NONWIFI_MAX) {
+			if (GET_VAL32(hdr->cmd,
+				      UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG) !=
+			    UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG) {
+				IWM_ERR(iwm, "Incorrect hw signature\n");
+				return -EINVAL;
+			}
+			ret |= iwm_rx_handle_nonwifi(iwm, buf + buf_offset,
+						     buf_size - buf_offset);
+		} else {
+			IWM_ERR(iwm, "Invalid RX opcode: 0x%x\n", op_code);
+			ret |= -EINVAL;
+		}
+
+		buf_offset += iwm_rx_resp_size(hdr);
+	}
+
+	return ret;
+}
+
+int iwm_rx_handle(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size)
+{
+	struct iwm_udma_in_hdr *hdr;
+
+	hdr = (struct iwm_udma_in_hdr *)buf;
+
+	switch (le32_to_cpu(hdr->cmd)) {
+	case UMAC_REBOOT_BARKER:
+		return iwm_notif_send(iwm, NULL, IWM_BARKER_REBOOT_NOTIFICATION,
+				      IWM_SRC_UDMA, buf, buf_size);
+	case UMAC_ACK_BARKER:
+		return iwm_notif_send(iwm, NULL, IWM_ACK_BARKER_NOTIFICATION,
+				      IWM_SRC_UDMA, NULL, 0);
+	default:
+		IWM_DBG_RX(iwm, DBG, "Received cmd: 0x%x\n", hdr->cmd);
+		return iwm_rx_handle_umac(iwm, buf, buf_size);
+	}
+
+	return 0;
+}
+
+static const iwm_handler iwm_umac_handlers[] =
+{
+	[UMAC_NOTIFY_OPCODE_ERROR]		= iwm_ntf_error,
+	[UMAC_NOTIFY_OPCODE_ALIVE]		= iwm_ntf_umac_alive,
+	[UMAC_NOTIFY_OPCODE_INIT_COMPLETE]	= iwm_ntf_init_complete,
+	[UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS]	= iwm_ntf_wifi_status,
+	[UMAC_NOTIFY_OPCODE_WIFI_IF_WRAPPER]	= iwm_ntf_mlme,
+	[UMAC_NOTIFY_OPCODE_PAGE_DEALLOC]	= iwm_ntf_tx_credit_update,
+	[UMAC_NOTIFY_OPCODE_RX_TICKET]		= iwm_ntf_rx_ticket,
+	[UMAC_CMD_OPCODE_RESET]			= iwm_ntf_umac_reset,
+	[UMAC_NOTIFY_OPCODE_STATS]		= iwm_ntf_statistics,
+	[UMAC_CMD_OPCODE_EEPROM_PROXY]		= iwm_ntf_eeprom_proxy,
+	[UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST]	= iwm_ntf_channel_info_list,
+	[REPLY_RX_MPDU_CMD]			= iwm_ntf_rx_packet,
+	[UMAC_CMD_OPCODE_WIFI_IF_WRAPPER]	= iwm_ntf_wifi_if_wrapper,
+};
+
+static const iwm_handler iwm_lmac_handlers[] =
+{
+	[REPLY_TX]				= iwm_ntf_tx,
+	[REPLY_ALIVE]				= iwm_ntf_lmac_version,
+	[CALIBRATION_RES_NOTIFICATION]		= iwm_ntf_calib_res,
+	[CALIBRATION_COMPLETE_NOTIFICATION]	= iwm_ntf_calib_complete,
+	[CALIBRATION_CFG_CMD]			= iwm_ntf_calib_cfg,
+	[REPLY_RX_MPDU_CMD]			= iwm_ntf_rx_packet,
+	[CARD_STATE_NOTIFICATION]		= iwm_ntf_card_state,
+};
+
+void iwm_rx_setup_handlers(struct iwm_priv *iwm)
+{
+	iwm->umac_handlers = (iwm_handler *) iwm_umac_handlers;
+	iwm->lmac_handlers = (iwm_handler *) iwm_lmac_handlers;
+}
+
+static void iwm_remove_iv(struct sk_buff *skb, u32 hdr_total_len)
+{
+	struct ieee80211_hdr *hdr;
+	unsigned int hdr_len;
+
+	hdr = (struct ieee80211_hdr *)skb->data;
+
+	if (!ieee80211_has_protected(hdr->frame_control))
+		return;
+
+	hdr_len = ieee80211_hdrlen(hdr->frame_control);
+	if (hdr_total_len <= hdr_len)
+		return;
+
+	memmove(skb->data + (hdr_total_len - hdr_len), skb->data, hdr_len);
+	skb_pull(skb, (hdr_total_len - hdr_len));
+}
+
+static void iwm_rx_adjust_packet(struct iwm_priv *iwm,
+				 struct iwm_rx_packet *packet,
+				 struct iwm_rx_ticket_node *ticket_node)
+{
+	u32 payload_offset = 0, payload_len;
+	struct iwm_rx_ticket *ticket = ticket_node->ticket;
+	struct iwm_rx_mpdu_hdr *mpdu_hdr;
+	struct ieee80211_hdr *hdr;
+
+	mpdu_hdr = (struct iwm_rx_mpdu_hdr *)packet->skb->data;
+	payload_offset += sizeof(struct iwm_rx_mpdu_hdr);
+	/* Padding is 0 or 2 bytes */
+	payload_len = le16_to_cpu(mpdu_hdr->len) +
+		(le16_to_cpu(ticket->flags) & IWM_RX_TICKET_PAD_SIZE_MSK);
+	payload_len -= ticket->tail_len;
+
+	IWM_DBG_RX(iwm, DBG, "Packet adjusted, len:%d, offset:%d, "
+		   "ticket offset:%d ticket tail len:%d\n",
+		   payload_len, payload_offset, ticket->payload_offset,
+		   ticket->tail_len);
+
+	IWM_HEXDUMP(iwm, DBG, RX, "RAW: ", packet->skb->data, packet->skb->len);
+
+	skb_pull(packet->skb, payload_offset);
+	skb_trim(packet->skb, payload_len);
+
+	iwm_remove_iv(packet->skb, ticket->payload_offset);
+
+	hdr = (struct ieee80211_hdr *) packet->skb->data;
+	if (ieee80211_is_data_qos(hdr->frame_control)) {
+		/* UMAC handed QOS_DATA frame with 2 padding bytes appended
+		 * to the qos_ctl field in IEEE 802.11 headers. */
+		memmove(packet->skb->data + IEEE80211_QOS_CTL_LEN + 2,
+			packet->skb->data,
+			ieee80211_hdrlen(hdr->frame_control) -
+			IEEE80211_QOS_CTL_LEN);
+		hdr = (struct ieee80211_hdr *) skb_pull(packet->skb,
+				IEEE80211_QOS_CTL_LEN + 2);
+		hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
+	}
+
+	IWM_HEXDUMP(iwm, DBG, RX, "ADJUSTED: ",
+		    packet->skb->data, packet->skb->len);
+}
+
+static void classify8023(struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+
+	if (ieee80211_is_data_qos(hdr->frame_control)) {
+		u8 *qc = ieee80211_get_qos_ctl(hdr);
+		/* frame has qos control */
+		skb->priority = *qc & IEEE80211_QOS_CTL_TID_MASK;
+	} else {
+		skb->priority = 0;
+	}
+}
+
+static void iwm_rx_process_packet(struct iwm_priv *iwm,
+				  struct iwm_rx_packet *packet,
+				  struct iwm_rx_ticket_node *ticket_node)
+{
+	int ret;
+	struct sk_buff *skb = packet->skb;
+	struct wireless_dev *wdev = iwm_to_wdev(iwm);
+	struct net_device *ndev = iwm_to_ndev(iwm);
+
+	IWM_DBG_RX(iwm, DBG, "Processing packet ID %d\n", packet->id);
+
+	switch (le16_to_cpu(ticket_node->ticket->action)) {
+	case IWM_RX_TICKET_RELEASE:
+		IWM_DBG_RX(iwm, DBG, "RELEASE packet\n");
+		classify8023(skb);
+		iwm_rx_adjust_packet(iwm, packet, ticket_node);
+		ret = ieee80211_data_to_8023(skb, ndev->dev_addr, wdev->iftype);
+		if (ret < 0) {
+			IWM_DBG_RX(iwm, DBG, "Couldn't convert 802.11 header - "
+				   "%d\n", ret);
+			break;
+		}
+
+		IWM_HEXDUMP(iwm, DBG, RX, "802.3: ", skb->data, skb->len);
+
+		skb->dev = iwm_to_ndev(iwm);
+		skb->protocol = eth_type_trans(skb, ndev);
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+		memset(skb->cb, 0, sizeof(skb->cb));
+
+		ndev->stats.rx_packets++;
+		ndev->stats.rx_bytes += skb->len;
+
+		if (netif_rx(skb) == NET_RX_DROP) {
+			IWM_ERR(iwm, "Packet dropped\n");
+			ndev->stats.rx_dropped++;
+		}
+		break;
+	case IWM_RX_TICKET_DROP:
+		IWM_DBG_RX(iwm, DBG, "DROP packet\n");
+		kfree_skb(packet->skb);
+		break;
+	default:
+		IWM_ERR(iwm, "Unknow ticket action: %d\n",
+			le16_to_cpu(ticket_node->ticket->action));
+		kfree_skb(packet->skb);
+	}
+
+	kfree(packet);
+	iwm_rx_ticket_node_free(ticket_node);
+}
+
+/*
+ * Rx data processing:
+ *
+ * We're receiving Rx packet from the LMAC, and Rx ticket from
+ * the UMAC.
+ * To forward a target data packet upstream (i.e. to the
+ * kernel network stack), we must have received an Rx ticket
+ * that tells us we're allowed to release this packet (ticket
+ * action is IWM_RX_TICKET_RELEASE). The Rx ticket also indicates,
+ * among other things, where valid data actually starts in the Rx
+ * packet.
+ */
+void iwm_rx_worker(struct work_struct *work)
+{
+	struct iwm_priv *iwm;
+	struct iwm_rx_ticket_node *ticket, *next;
+
+	iwm = container_of(work, struct iwm_priv, rx_worker);
+
+	/*
+	 * We go through the tickets list and if there is a pending
+	 * packet for it, we push it upstream.
+	 * We stop whenever a ticket is missing its packet, as we're
+	 * supposed to send the packets in order.
+	 */
+	list_for_each_entry_safe(ticket, next, &iwm->rx_tickets, node) {
+		struct iwm_rx_packet *packet =
+			iwm_rx_packet_get(iwm, le16_to_cpu(ticket->ticket->id));
+
+		if (!packet) {
+			IWM_DBG_RX(iwm, DBG, "Skip rx_work: Wait for ticket %d "
+				   "to be handled first\n",
+				   le16_to_cpu(ticket->ticket->id));
+			return;
+		}
+
+		list_del(&ticket->node);
+		list_del(&packet->node);
+		iwm_rx_process_packet(iwm, packet, ticket);
+	}
+}
+
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.h b/drivers/net/wireless/iwmc3200wifi/rx.h
new file mode 100644
index 0000000..da0db91
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/rx.h
@@ -0,0 +1,60 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ *
+ * Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ */
+
+#ifndef __IWM_RX_H__
+#define __IWM_RX_H__
+
+#include <linux/skbuff.h>
+
+#include "umac.h"
+
+struct iwm_rx_ticket_node {
+	struct list_head node;
+	struct iwm_rx_ticket *ticket;
+};
+
+struct iwm_rx_packet {
+	struct list_head node;
+	u16 id;
+	struct sk_buff *skb;
+	unsigned long pkt_size;
+};
+
+void iwm_rx_worker(struct work_struct *work);
+
+#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c
new file mode 100644
index 0000000..edc0a00
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/sdio.c
@@ -0,0 +1,516 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ *
+ * Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ */
+
+/*
+ * This is the SDIO bus specific hooks for iwm.
+ * It also is the module's entry point.
+ *
+ * Interesting code paths:
+ * iwm_sdio_probe() (Called by an SDIO bus scan)
+ *  -> iwm_if_alloc() (netdev.c)
+ *      -> iwm_wdev_alloc() (cfg80211.c, allocates and register our wiphy)
+ *          -> wiphy_new()
+ *          -> wiphy_register()
+ *      -> alloc_netdev_mq()
+ *      -> register_netdev()
+ *
+ * iwm_sdio_remove()
+ *  -> iwm_if_free() (netdev.c)
+ *      -> unregister_netdev()
+ *      -> iwm_wdev_free() (cfg80211.c)
+ *          -> wiphy_unregister()
+ *          -> wiphy_free()
+ *
+ * iwm_sdio_isr() (called in process context from the SDIO core code)
+ *  -> queue_work(.., isr_worker)
+ *      -- [async] --> iwm_sdio_isr_worker()
+ *                      -> iwm_rx_handle()
+ */
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/debugfs.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "iwm.h"
+#include "debug.h"
+#include "bus.h"
+#include "sdio.h"
+
+static void iwm_sdio_isr_worker(struct work_struct *work)
+{
+	struct iwm_sdio_priv *hw;
+	struct iwm_priv *iwm;
+	struct iwm_rx_info *rx_info;
+	struct sk_buff *skb;
+	u8 *rx_buf;
+	unsigned long rx_size;
+
+	hw = container_of(work, struct iwm_sdio_priv, isr_worker);
+	iwm = hw_to_iwm(hw);
+
+	while (!skb_queue_empty(&iwm->rx_list)) {
+		skb = skb_dequeue(&iwm->rx_list);
+		rx_info = skb_to_rx_info(skb);
+		rx_size = rx_info->rx_size;
+		rx_buf = skb->data;
+
+		IWM_HEXDUMP(iwm, DBG, SDIO, "RX: ", rx_buf, rx_size);
+		if (iwm_rx_handle(iwm, rx_buf, rx_size) < 0)
+			IWM_WARN(iwm, "RX error\n");
+
+		kfree_skb(skb);
+	}
+}
+
+static void iwm_sdio_isr(struct sdio_func *func)
+{
+	struct iwm_priv *iwm;
+	struct iwm_sdio_priv *hw;
+	struct iwm_rx_info *rx_info;
+	struct sk_buff *skb;
+	unsigned long buf_size, read_size;
+	int ret;
+	u8 val;
+
+	hw = sdio_get_drvdata(func);
+	iwm = hw_to_iwm(hw);
+
+	buf_size = hw->blk_size;
+
+	/* We're checking the status */
+	val = sdio_readb(func, IWM_SDIO_INTR_STATUS_ADDR, &ret);
+	if (val == 0 || ret < 0) {
+		IWM_ERR(iwm, "Wrong INTR_STATUS\n");
+		return;
+	}
+
+	/* See if we have free buffers */
+	if (skb_queue_len(&iwm->rx_list) > IWM_RX_LIST_SIZE) {
+		IWM_ERR(iwm, "No buffer for more Rx frames\n");
+		return;
+	}
+
+	/* We first read the transaction size */
+	read_size = sdio_readb(func, IWM_SDIO_INTR_GET_SIZE_ADDR + 1, &ret);
+	read_size = read_size << 8;
+
+	if (ret < 0) {
+		IWM_ERR(iwm, "Couldn't read the xfer size\n");
+		return;
+	}
+
+	/* We need to clear the INT register */
+	sdio_writeb(func, 1, IWM_SDIO_INTR_CLEAR_ADDR, &ret);
+	if (ret < 0) {
+		IWM_ERR(iwm, "Couldn't clear the INT register\n");
+		return;
+	}
+
+	while (buf_size < read_size)
+		buf_size <<= 1;
+
+	skb = dev_alloc_skb(buf_size);
+	if (!skb) {
+		IWM_ERR(iwm, "Couldn't alloc RX skb\n");
+		return;
+	}
+	rx_info = skb_to_rx_info(skb);
+	rx_info->rx_size = read_size;
+	rx_info->rx_buf_size = buf_size;
+
+	/* Now we can read the actual buffer */
+	ret = sdio_memcpy_fromio(func, skb_put(skb, read_size),
+				 IWM_SDIO_DATA_ADDR, read_size);
+
+	/* The skb is put on a driver's specific Rx SKB list */
+	skb_queue_tail(&iwm->rx_list, skb);
+
+	/* We can now schedule the actual worker */
+	queue_work(hw->isr_wq, &hw->isr_worker);
+}
+
+static void iwm_sdio_rx_free(struct iwm_sdio_priv *hw)
+{
+	struct iwm_priv *iwm = hw_to_iwm(hw);
+
+	flush_workqueue(hw->isr_wq);
+
+	skb_queue_purge(&iwm->rx_list);
+}
+
+/* Bus ops */
+static int if_sdio_enable(struct iwm_priv *iwm)
+{
+	struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm);
+	int ret;
+
+	sdio_claim_host(hw->func);
+
+	ret = sdio_enable_func(hw->func);
+	if (ret) {
+		IWM_ERR(iwm, "Couldn't enable the device: is TOP driver "
+			"loaded and functional?\n");
+		goto release_host;
+	}
+
+	iwm_reset(iwm);
+
+	ret = sdio_claim_irq(hw->func, iwm_sdio_isr);
+	if (ret) {
+		IWM_ERR(iwm, "Failed to claim irq: %d\n", ret);
+		goto release_host;
+	}
+
+	sdio_writeb(hw->func, 1, IWM_SDIO_INTR_ENABLE_ADDR, &ret);
+	if (ret < 0) {
+		IWM_ERR(iwm, "Couldn't enable INTR: %d\n", ret);
+		goto release_irq;
+	}
+
+	sdio_release_host(hw->func);
+
+	IWM_DBG_SDIO(iwm, INFO, "IWM SDIO enable\n");
+
+	return 0;
+
+ release_irq:
+	sdio_release_irq(hw->func);
+ release_host:
+	sdio_release_host(hw->func);
+
+	return ret;
+}
+
+static int if_sdio_disable(struct iwm_priv *iwm)
+{
+	struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm);
+	int ret;
+
+	iwm_reset(iwm);
+
+	sdio_claim_host(hw->func);
+	sdio_writeb(hw->func, 0, IWM_SDIO_INTR_ENABLE_ADDR, &ret);
+	if (ret < 0)
+		IWM_WARN(iwm, "Couldn't disable INTR: %d\n", ret);
+
+	sdio_release_irq(hw->func);
+	sdio_disable_func(hw->func);
+	sdio_release_host(hw->func);
+
+	iwm_sdio_rx_free(hw);
+
+	IWM_DBG_SDIO(iwm, INFO, "IWM SDIO disable\n");
+
+	return 0;
+}
+
+static int if_sdio_send_chunk(struct iwm_priv *iwm, u8 *buf, int count)
+{
+	struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm);
+	int aligned_count = ALIGN(count, hw->blk_size);
+	int ret;
+
+	if ((unsigned long)buf & 0x3) {
+		IWM_ERR(iwm, "buf <%p> is not dword aligned\n", buf);
+		/* TODO: Is this a hardware limitation? use get_unligned */
+		return -EINVAL;
+	}
+
+	sdio_claim_host(hw->func);
+	ret = sdio_memcpy_toio(hw->func, IWM_SDIO_DATA_ADDR, buf,
+			       aligned_count);
+	sdio_release_host(hw->func);
+
+	return ret;
+}
+
+/* debugfs hooks */
+static int iwm_debugfs_sdio_open(struct inode *inode, struct file *filp)
+{
+	filp->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t iwm_debugfs_sdio_read(struct file *filp, char __user *buffer,
+				     size_t count, loff_t *ppos)
+{
+	struct iwm_priv *iwm = filp->private_data;
+	struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm);
+	char *buf;
+	u8 cccr;
+	int buf_len = 4096, ret;
+	size_t len = 0;
+
+	if (*ppos != 0)
+		return 0;
+	if (count < sizeof(buf))
+		return -ENOSPC;
+
+	buf = kzalloc(buf_len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	sdio_claim_host(hw->func);
+
+	cccr =  sdio_f0_readb(hw->func, SDIO_CCCR_IOEx, &ret);
+	if (ret) {
+		IWM_ERR(iwm, "Could not read SDIO_CCCR_IOEx\n");
+		goto err;
+	}
+	len += snprintf(buf + len, buf_len - len, "CCCR_IOEx:  0x%x\n", cccr);
+
+	cccr =  sdio_f0_readb(hw->func, SDIO_CCCR_IORx, &ret);
+	if (ret) {
+		IWM_ERR(iwm, "Could not read SDIO_CCCR_IORx\n");
+		goto err;
+	}
+	len += snprintf(buf + len, buf_len - len, "CCCR_IORx:  0x%x\n", cccr);
+
+
+	cccr =  sdio_f0_readb(hw->func, SDIO_CCCR_IENx, &ret);
+	if (ret) {
+		IWM_ERR(iwm, "Could not read SDIO_CCCR_IENx\n");
+		goto err;
+	}
+	len += snprintf(buf + len, buf_len - len, "CCCR_IENx:  0x%x\n", cccr);
+
+
+	cccr =  sdio_f0_readb(hw->func, SDIO_CCCR_INTx, &ret);
+	if (ret) {
+		IWM_ERR(iwm, "Could not read SDIO_CCCR_INTx\n");
+		goto err;
+	}
+	len += snprintf(buf + len, buf_len - len, "CCCR_INTx:  0x%x\n", cccr);
+
+
+	cccr =  sdio_f0_readb(hw->func, SDIO_CCCR_ABORT, &ret);
+	if (ret) {
+		IWM_ERR(iwm, "Could not read SDIO_CCCR_ABORTx\n");
+		goto err;
+	}
+	len += snprintf(buf + len, buf_len - len, "CCCR_ABORT: 0x%x\n", cccr);
+
+	cccr =  sdio_f0_readb(hw->func, SDIO_CCCR_IF, &ret);
+	if (ret) {
+		IWM_ERR(iwm, "Could not read SDIO_CCCR_IF\n");
+		goto err;
+	}
+	len += snprintf(buf + len, buf_len - len, "CCCR_IF:    0x%x\n", cccr);
+
+
+	cccr =  sdio_f0_readb(hw->func, SDIO_CCCR_CAPS, &ret);
+	if (ret) {
+		IWM_ERR(iwm, "Could not read SDIO_CCCR_CAPS\n");
+		goto err;
+	}
+	len += snprintf(buf + len, buf_len - len, "CCCR_CAPS:  0x%x\n", cccr);
+
+	cccr =  sdio_f0_readb(hw->func, SDIO_CCCR_CIS, &ret);
+	if (ret) {
+		IWM_ERR(iwm, "Could not read SDIO_CCCR_CIS\n");
+		goto err;
+	}
+	len += snprintf(buf + len, buf_len - len, "CCCR_CIS:   0x%x\n", cccr);
+
+	ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len);
+err:
+	sdio_release_host(hw->func);
+
+	kfree(buf);
+
+	return ret;
+}
+
+static const struct file_operations iwm_debugfs_sdio_fops = {
+	.owner =	THIS_MODULE,
+	.open =		iwm_debugfs_sdio_open,
+	.read =		iwm_debugfs_sdio_read,
+};
+
+static int if_sdio_debugfs_init(struct iwm_priv *iwm, struct dentry *parent_dir)
+{
+	int result;
+	struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm);
+
+	hw->cccr_dentry = debugfs_create_file("cccr", 0200,
+					      parent_dir, iwm,
+					      &iwm_debugfs_sdio_fops);
+	result = PTR_ERR(hw->cccr_dentry);
+	if (IS_ERR(hw->cccr_dentry) && (result != -ENODEV)) {
+		IWM_ERR(iwm, "Couldn't create CCCR entry: %d\n", result);
+		return result;
+	}
+
+	return 0;
+}
+
+static void if_sdio_debugfs_exit(struct iwm_priv *iwm)
+{
+	struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm);
+
+	debugfs_remove(hw->cccr_dentry);
+}
+
+static struct iwm_if_ops if_sdio_ops = {
+	.enable = if_sdio_enable,
+	.disable = if_sdio_disable,
+	.send_chunk = if_sdio_send_chunk,
+	.debugfs_init = if_sdio_debugfs_init,
+	.debugfs_exit = if_sdio_debugfs_exit,
+	.umac_name = "iwmc3200wifi-umac-sdio.bin",
+	.calib_lmac_name = "iwmc3200wifi-lmac-calib-sdio.bin",
+	.lmac_name = "iwmc3200wifi-lmac-sdio.bin",
+};
+
+static int iwm_sdio_probe(struct sdio_func *func,
+			  const struct sdio_device_id *id)
+{
+	struct iwm_priv *iwm;
+	struct iwm_sdio_priv *hw;
+	struct device *dev = &func->dev;
+	int ret;
+
+	/* check if TOP has already initialized the card */
+	sdio_claim_host(func);
+	ret = sdio_enable_func(func);
+	if (ret) {
+		dev_err(dev, "wait for TOP to enable the device\n");
+		sdio_release_host(func);
+		return ret;
+	}
+
+	ret = sdio_set_block_size(func, IWM_SDIO_BLK_SIZE);
+
+	sdio_disable_func(func);
+	sdio_release_host(func);
+
+	if (ret < 0) {
+		dev_err(dev, "Failed to set block size: %d\n", ret);
+		return ret;
+	}
+
+	iwm = iwm_if_alloc(sizeof(struct iwm_sdio_priv), dev, &if_sdio_ops);
+	if (IS_ERR(iwm)) {
+		dev_err(dev, "allocate SDIO interface failed\n");
+		return PTR_ERR(iwm);
+	}
+
+	hw = iwm_private(iwm);
+	hw->iwm = iwm;
+
+	ret = iwm_debugfs_init(iwm);
+	if (ret < 0) {
+		IWM_ERR(iwm, "Debugfs registration failed\n");
+		goto if_free;
+	}
+
+	sdio_set_drvdata(func, hw);
+
+	hw->func = func;
+	hw->blk_size = IWM_SDIO_BLK_SIZE;
+
+	hw->isr_wq = create_singlethread_workqueue(KBUILD_MODNAME "_sdio");
+	if (!hw->isr_wq) {
+		ret = -ENOMEM;
+		goto debugfs_exit;
+	}
+
+	INIT_WORK(&hw->isr_worker, iwm_sdio_isr_worker);
+
+	dev_info(dev, "IWM SDIO probe\n");
+
+	return 0;
+
+ debugfs_exit:
+	iwm_debugfs_exit(iwm);
+ if_free:
+	iwm_if_free(iwm);
+	return ret;
+}
+
+static void iwm_sdio_remove(struct sdio_func *func)
+{
+	struct iwm_sdio_priv *hw = sdio_get_drvdata(func);
+	struct iwm_priv *iwm = hw_to_iwm(hw);
+	struct device *dev = &func->dev;
+
+	iwm_debugfs_exit(iwm);
+	iwm_if_free(iwm);
+	destroy_workqueue(hw->isr_wq);
+
+	sdio_set_drvdata(func, NULL);
+
+	dev_info(dev, "IWM SDIO remove\n");
+
+	return;
+}
+
+static const struct sdio_device_id iwm_sdio_ids[] = {
+	{ SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, SDIO_DEVICE_ID_IWM) },
+	{ /* end: all zeroes */	},
+};
+MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids);
+
+static struct sdio_driver iwm_sdio_driver = {
+	.name		= "iwm_sdio",
+	.id_table	= iwm_sdio_ids,
+	.probe		= iwm_sdio_probe,
+	.remove		= iwm_sdio_remove,
+};
+
+static int __init iwm_sdio_init_module(void)
+{
+	int ret;
+
+	ret = sdio_register_driver(&iwm_sdio_driver);
+
+	return ret;
+}
+
+static void __exit iwm_sdio_exit_module(void)
+{
+	sdio_unregister_driver(&iwm_sdio_driver);
+}
+
+module_init(iwm_sdio_init_module);
+module_exit(iwm_sdio_exit_module);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(IWM_COPYRIGHT " " IWM_AUTHOR);
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.h b/drivers/net/wireless/iwmc3200wifi/sdio.h
new file mode 100644
index 0000000..b3c156b
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/sdio.h
@@ -0,0 +1,67 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ *
+ * Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ */
+
+#ifndef __IWM_SDIO_H__
+#define __IWM_SDIO_H__
+
+#define SDIO_VENDOR_ID_INTEL 0x89
+#define SDIO_DEVICE_ID_IWM   0x1403
+
+#define IWM_SDIO_DATA_ADDR           0x0
+#define IWM_SDIO_INTR_ENABLE_ADDR    0x14
+#define IWM_SDIO_INTR_STATUS_ADDR    0x13
+#define IWM_SDIO_INTR_CLEAR_ADDR     0x13
+#define IWM_SDIO_INTR_GET_SIZE_ADDR  0x2C
+
+#define IWM_SDIO_BLK_SIZE       256
+
+#define iwm_to_if_sdio(i) (struct iwm_sdio_priv *)(iwm->private)
+
+struct iwm_sdio_priv {
+	struct sdio_func *func;
+	struct iwm_priv *iwm;
+
+	struct workqueue_struct *isr_wq;
+	struct work_struct isr_worker;
+
+	struct dentry *cccr_dentry;
+
+	unsigned int blk_size;
+};
+
+#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/tx.c b/drivers/net/wireless/iwmc3200wifi/tx.c
new file mode 100644
index 0000000..e3b4f79
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/tx.c
@@ -0,0 +1,492 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ *
+ * Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ */
+
+/*
+ * iwm Tx theory of operation:
+ *
+ * 1) We receive a 802.3 frame from the stack
+ * 2) We convert it to a 802.11 frame [iwm_xmit_frame]
+ * 3) We queue it to its corresponding tx queue [iwm_xmit_frame]
+ * 4) We schedule the tx worker. There is one worker per tx
+ *    queue. [iwm_xmit_frame]
+ * 5) The tx worker is scheduled
+ * 6) We go through every queued skb on the tx queue, and for each
+ *    and every one of them: [iwm_tx_worker]
+ *    a) We check if we have enough Tx credits (see below for a Tx
+ *       credits description) for the frame length. [iwm_tx_worker]
+ *    b) If we do, we aggregate the Tx frame into a UDMA one, by
+ *       concatenating one REPLY_TX command per Tx frame. [iwm_tx_worker]
+ *    c) When we run out of credits, or when we reach the maximum
+ *       concatenation size, we actually send the concatenated UDMA
+ *       frame. [iwm_tx_worker]
+ *
+ * When we run out of Tx credits, the skbs are filling the tx queue,
+ * and eventually we will stop the netdev queue. [iwm_tx_worker]
+ * The tx queue is emptied as we're getting new tx credits, by
+ * scheduling the tx_worker. [iwm_tx_credit_inc]
+ * The netdev queue is started again when we have enough tx credits,
+ * and when our tx queue has some reasonable amout of space available
+ * (i.e. half of the max size). [iwm_tx_worker]
+ */
+
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/ieee80211.h>
+
+#include "iwm.h"
+#include "debug.h"
+#include "commands.h"
+#include "hal.h"
+#include "umac.h"
+#include "bus.h"
+
+#define IWM_UMAC_PAGE_ALLOC_WRAP 0xffff
+
+#define BYTES_TO_PAGES(n)	 (1 + ((n) >> ilog2(IWM_UMAC_PAGE_SIZE)) - \
+				 (((n) & (IWM_UMAC_PAGE_SIZE - 1)) == 0))
+
+#define pool_id_to_queue(id)	 ((id < IWM_TX_CMD_QUEUE) ? id : id - 1)
+#define queue_to_pool_id(q)	 ((q < IWM_TX_CMD_QUEUE) ? q : q + 1)
+
+/* require to hold tx_credit lock */
+static int iwm_tx_credit_get(struct iwm_tx_credit *tx_credit, int id)
+{
+	struct pool_entry *pool = &tx_credit->pools[id];
+	struct spool_entry *spool = &tx_credit->spools[pool->sid];
+	int spool_pages;
+
+	/* number of pages can be taken from spool by this pool */
+	spool_pages = spool->max_pages - spool->alloc_pages +
+		      max(pool->min_pages - pool->alloc_pages, 0);
+
+	return min(pool->max_pages - pool->alloc_pages, spool_pages);
+}
+
+static bool iwm_tx_credit_ok(struct iwm_priv *iwm, int id, int nb)
+{
+	u32 npages = BYTES_TO_PAGES(nb);
+
+	if (npages <= iwm_tx_credit_get(&iwm->tx_credit, id))
+		return 1;
+
+	set_bit(id, &iwm->tx_credit.full_pools_map);
+
+	IWM_DBG_TX(iwm, DBG, "LINK: stop txq[%d], available credit: %d\n",
+		   pool_id_to_queue(id),
+		   iwm_tx_credit_get(&iwm->tx_credit, id));
+
+	return 0;
+}
+
+void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages)
+{
+	struct pool_entry *pool;
+	struct spool_entry *spool;
+	int freed_pages;
+	int queue;
+
+	BUG_ON(id >= IWM_MACS_OUT_GROUPS);
+
+	pool = &iwm->tx_credit.pools[id];
+	spool = &iwm->tx_credit.spools[pool->sid];
+
+	freed_pages = total_freed_pages - pool->total_freed_pages;
+	IWM_DBG_TX(iwm, DBG, "Free %d pages for pool[%d]\n", freed_pages, id);
+
+	if (!freed_pages) {
+		IWM_DBG_TX(iwm, DBG, "No pages are freed by UMAC\n");
+		return;
+	} else if (freed_pages < 0)
+		freed_pages += IWM_UMAC_PAGE_ALLOC_WRAP + 1;
+
+	if (pool->alloc_pages > pool->min_pages) {
+		int spool_pages = pool->alloc_pages - pool->min_pages;
+		spool_pages = min(spool_pages, freed_pages);
+		spool->alloc_pages -= spool_pages;
+	}
+
+	pool->alloc_pages -= freed_pages;
+	pool->total_freed_pages = total_freed_pages;
+
+	IWM_DBG_TX(iwm, DBG, "Pool[%d] pages alloc: %d, total_freed: %d, "
+		   "Spool[%d] pages alloc: %d\n", id, pool->alloc_pages,
+		   pool->total_freed_pages, pool->sid, spool->alloc_pages);
+
+	if (test_bit(id, &iwm->tx_credit.full_pools_map) &&
+	    (pool->alloc_pages < pool->max_pages / 2)) {
+		clear_bit(id, &iwm->tx_credit.full_pools_map);
+
+		queue = pool_id_to_queue(id);
+
+		IWM_DBG_TX(iwm, DBG, "LINK: start txq[%d], available "
+			   "credit: %d\n", queue,
+			   iwm_tx_credit_get(&iwm->tx_credit, id));
+		queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker);
+	}
+}
+
+static void iwm_tx_credit_dec(struct iwm_priv *iwm, int id, int alloc_pages)
+{
+	struct pool_entry *pool;
+	struct spool_entry *spool;
+	int spool_pages;
+
+	IWM_DBG_TX(iwm, DBG, "Allocate %d pages for pool[%d]\n",
+		   alloc_pages, id);
+
+	BUG_ON(id >= IWM_MACS_OUT_GROUPS);
+
+	pool = &iwm->tx_credit.pools[id];
+	spool = &iwm->tx_credit.spools[pool->sid];
+
+	spool_pages = pool->alloc_pages + alloc_pages - pool->min_pages;
+
+	if (pool->alloc_pages >= pool->min_pages)
+		spool->alloc_pages += alloc_pages;
+	else if (spool_pages > 0)
+		spool->alloc_pages += spool_pages;
+
+	pool->alloc_pages += alloc_pages;
+
+	IWM_DBG_TX(iwm, DBG, "Pool[%d] pages alloc: %d, total_freed: %d, "
+		   "Spool[%d] pages alloc: %d\n", id, pool->alloc_pages,
+		   pool->total_freed_pages, pool->sid, spool->alloc_pages);
+}
+
+int iwm_tx_credit_alloc(struct iwm_priv *iwm, int id, int nb)
+{
+	u32 npages = BYTES_TO_PAGES(nb);
+	int ret = 0;
+
+	spin_lock(&iwm->tx_credit.lock);
+
+	if (!iwm_tx_credit_ok(iwm, id, nb)) {
+		IWM_DBG_TX(iwm, DBG, "No credit avaliable for pool[%d]\n", id);
+		ret = -ENOSPC;
+		goto out;
+	}
+
+	iwm_tx_credit_dec(iwm, id, npages);
+
+ out:
+	spin_unlock(&iwm->tx_credit.lock);
+	return ret;
+}
+
+/*
+ * Since we're on an SDIO or USB bus, we are not sharing memory
+ * for storing to be transmitted frames. The host needs to push
+ * them upstream. As a consequence there needs to be a way for
+ * the target to let us know if it can actually take more TX frames
+ * or not. This is what Tx credits are for.
+ *
+ * For each Tx HW queue, we have a Tx pool, and then we have one
+ * unique super pool (spool), which is actually a global pool of
+ * all the UMAC pages.
+ * For each Tx pool we have a min_pages, a max_pages fields, and a
+ * alloc_pages fields. The alloc_pages tracks the number of pages
+ * currently allocated from the tx pool.
+ * Here are the rules to check if given a tx frame we have enough
+ * tx credits for it:
+ * 1) We translate the frame length into a number of UMAC pages.
+ *    Let's call them n_pages.
+ * 2) For the corresponding tx pool, we check if n_pages +
+ *    pool->alloc_pages is higher than pool->min_pages. min_pages
+ *    represent a set of pre-allocated pages on the tx pool. If
+ *    that's the case, then we need to allocate those pages from
+ *    the spool. We can do so until we reach spool->max_pages.
+ * 3) Each tx pool is not allowed to allocate more than pool->max_pages
+ *    from the spool, so once we're over min_pages, we can allocate
+ *    pages from the spool, but not more than max_pages.
+ *
+ * When the tx code path needs to send a tx frame, it checks first
+ * if it has enough tx credits, following those rules. [iwm_tx_credit_get]
+ * If it does, it then updates the pool and spool counters and
+ * then send the frame. [iwm_tx_credit_alloc and iwm_tx_credit_dec]
+ * On the other side, when the UMAC is done transmitting frames, it
+ * will send a credit update notification to the host. This is when
+ * the pool and spool counters gets to be decreased. [iwm_tx_credit_inc,
+ * called from rx.c:iwm_ntf_tx_credit_update]
+ *
+ */
+void iwm_tx_credit_init_pools(struct iwm_priv *iwm,
+			      struct iwm_umac_notif_alive *alive)
+{
+	int i, sid, pool_pages;
+
+	spin_lock(&iwm->tx_credit.lock);
+
+	iwm->tx_credit.pool_nr = le16_to_cpu(alive->page_grp_count);
+	iwm->tx_credit.full_pools_map = 0;
+	memset(&iwm->tx_credit.spools[0], 0, sizeof(struct spool_entry));
+
+	IWM_DBG_TX(iwm, DBG, "Pools number is %d\n", iwm->tx_credit.pool_nr);
+
+	for (i = 0; i < iwm->tx_credit.pool_nr; i++) {
+		__le32 page_grp_state = alive->page_grp_state[i];
+
+		iwm->tx_credit.pools[i].id = GET_VAL32(page_grp_state,
+				UMAC_ALIVE_PAGE_STS_GRP_NUM);
+		iwm->tx_credit.pools[i].sid = GET_VAL32(page_grp_state,
+				UMAC_ALIVE_PAGE_STS_SGRP_NUM);
+		iwm->tx_credit.pools[i].min_pages = GET_VAL32(page_grp_state,
+				UMAC_ALIVE_PAGE_STS_GRP_MIN_SIZE);
+		iwm->tx_credit.pools[i].max_pages = GET_VAL32(page_grp_state,
+				UMAC_ALIVE_PAGE_STS_GRP_MAX_SIZE);
+		iwm->tx_credit.pools[i].alloc_pages = 0;
+		iwm->tx_credit.pools[i].total_freed_pages = 0;
+
+		sid = iwm->tx_credit.pools[i].sid;
+		pool_pages = iwm->tx_credit.pools[i].min_pages;
+
+		if (iwm->tx_credit.spools[sid].max_pages == 0) {
+			iwm->tx_credit.spools[sid].id = sid;
+			iwm->tx_credit.spools[sid].max_pages =
+				GET_VAL32(page_grp_state,
+					  UMAC_ALIVE_PAGE_STS_SGRP_MAX_SIZE);
+			iwm->tx_credit.spools[sid].alloc_pages = 0;
+		}
+
+		iwm->tx_credit.spools[sid].alloc_pages += pool_pages;
+
+		IWM_DBG_TX(iwm, DBG, "Pool idx: %d, id: %d, sid: %d, capacity "
+			   "min: %d, max: %d, pool alloc: %d, total_free: %d, "
+			   "super poll alloc: %d\n",
+			   i, iwm->tx_credit.pools[i].id,
+			   iwm->tx_credit.pools[i].sid,
+			   iwm->tx_credit.pools[i].min_pages,
+			   iwm->tx_credit.pools[i].max_pages,
+			   iwm->tx_credit.pools[i].alloc_pages,
+			   iwm->tx_credit.pools[i].total_freed_pages,
+			   iwm->tx_credit.spools[sid].alloc_pages);
+	}
+
+	spin_unlock(&iwm->tx_credit.lock);
+}
+
+#define IWM_UDMA_HDR_LEN	sizeof(struct iwm_umac_wifi_out_hdr)
+
+static int iwm_tx_build_packet(struct iwm_priv *iwm, struct sk_buff *skb,
+			       int pool_id, u8 *buf)
+{
+	struct iwm_umac_wifi_out_hdr *hdr = (struct iwm_umac_wifi_out_hdr *)buf;
+	struct iwm_udma_wifi_cmd udma_cmd;
+	struct iwm_umac_cmd umac_cmd;
+	struct iwm_tx_info *tx_info = skb_to_tx_info(skb);
+
+	udma_cmd.count = cpu_to_le16(skb->len +
+				     sizeof(struct iwm_umac_fw_cmd_hdr));
+	/* set EOP to 0 here. iwm_udma_wifi_hdr_set_eop() will be
+	 * called later to set EOP for the last packet. */
+	udma_cmd.eop = 0;
+	udma_cmd.credit_group = pool_id;
+	udma_cmd.ra_tid = tx_info->sta << 4 | tx_info->tid;
+	udma_cmd.lmac_offset = 0;
+
+	umac_cmd.id = REPLY_TX;
+	umac_cmd.count = cpu_to_le16(skb->len);
+	umac_cmd.color = tx_info->color;
+	umac_cmd.resp = 0;
+	umac_cmd.seq_num = cpu_to_le16(iwm_alloc_wifi_cmd_seq(iwm));
+
+	iwm_build_udma_wifi_hdr(iwm, &hdr->hw_hdr, &udma_cmd);
+	iwm_build_umac_hdr(iwm, &hdr->sw_hdr, &umac_cmd);
+
+	memcpy(buf + sizeof(*hdr), skb->data, skb->len);
+
+	return 0;
+}
+
+static int iwm_tx_send_concat_packets(struct iwm_priv *iwm,
+				      struct iwm_tx_queue *txq)
+{
+	int ret;
+
+	if (!txq->concat_count)
+		return 0;
+
+	IWM_DBG_TX(iwm, DBG, "Send concatenated Tx: queue %d, %d bytes\n",
+		   txq->id, txq->concat_count);
+
+	/* mark EOP for the last packet */
+	iwm_udma_wifi_hdr_set_eop(iwm, txq->concat_ptr, 1);
+
+	ret = iwm_bus_send_chunk(iwm, txq->concat_buf, txq->concat_count);
+
+	txq->concat_count = 0;
+	txq->concat_ptr = txq->concat_buf;
+
+	return ret;
+}
+
+#define CONFIG_IWM_TX_CONCATENATED 1
+
+void iwm_tx_worker(struct work_struct *work)
+{
+	struct iwm_priv *iwm;
+	struct iwm_tx_info *tx_info = NULL;
+	struct sk_buff *skb;
+	int cmdlen, ret;
+	struct iwm_tx_queue *txq;
+	int pool_id;
+
+	txq = container_of(work, struct iwm_tx_queue, worker);
+	iwm = container_of(txq, struct iwm_priv, txq[txq->id]);
+
+	pool_id = queue_to_pool_id(txq->id);
+
+	while (!test_bit(pool_id, &iwm->tx_credit.full_pools_map) &&
+	       !skb_queue_empty(&txq->queue)) {
+
+		skb = skb_dequeue(&txq->queue);
+		tx_info = skb_to_tx_info(skb);
+		cmdlen = IWM_UDMA_HDR_LEN + skb->len;
+
+		IWM_DBG_TX(iwm, DBG, "Tx frame on queue %d: skb: 0x%p, sta: "
+			   "%d, color: %d\n", txq->id, skb, tx_info->sta,
+			   tx_info->color);
+
+#if !CONFIG_IWM_TX_CONCATENATED
+		/* temporarily keep this to comparing the performance */
+		ret = iwm_send_packet(iwm, skb, pool_id);
+#else
+
+		if (txq->concat_count + cmdlen > IWM_HAL_CONCATENATE_BUF_SIZE)
+			iwm_tx_send_concat_packets(iwm, txq);
+
+		ret = iwm_tx_credit_alloc(iwm, pool_id, cmdlen);
+		if (ret) {
+			IWM_DBG_TX(iwm, DBG, "not enough tx_credit for queue "
+				   "%d, Tx worker stopped\n", txq->id);
+			skb_queue_head(&txq->queue, skb);
+			break;
+		}
+
+		txq->concat_ptr = txq->concat_buf + txq->concat_count;
+		iwm_tx_build_packet(iwm, skb, pool_id, txq->concat_ptr);
+		txq->concat_count += ALIGN(cmdlen, 16);
+#endif
+		kfree_skb(skb);
+	}
+
+	iwm_tx_send_concat_packets(iwm, txq);
+
+	if (__netif_subqueue_stopped(iwm_to_ndev(iwm), txq->id) &&
+	    !test_bit(pool_id, &iwm->tx_credit.full_pools_map) &&
+	    (skb_queue_len(&txq->queue) < IWM_TX_LIST_SIZE / 2)) {
+		IWM_DBG_TX(iwm, DBG, "LINK: start netif_subqueue[%d]", txq->id);
+		netif_wake_subqueue(iwm_to_ndev(iwm), txq->id);
+	}
+}
+
+int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct iwm_priv *iwm = ndev_to_iwm(netdev);
+	struct net_device *ndev = iwm_to_ndev(iwm);
+	struct wireless_dev *wdev = iwm_to_wdev(iwm);
+	u8 *dst_addr;
+	struct iwm_tx_info *tx_info;
+	struct iwm_tx_queue *txq;
+	struct iwm_sta_info *sta_info;
+	u8 sta_id;
+	u16 queue;
+	int ret;
+
+	if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
+		IWM_DBG_TX(iwm, DBG, "LINK: stop netif_all_queues: "
+			   "not associated\n");
+		netif_tx_stop_all_queues(netdev);
+		goto drop;
+	}
+
+	queue = skb_get_queue_mapping(skb);
+	BUG_ON(queue >= IWM_TX_DATA_QUEUES); /* no iPAN yet */
+
+	txq = &iwm->txq[queue];
+
+	/* No free space for Tx, tx_worker is too slow */
+	if (skb_queue_len(&txq->queue) > IWM_TX_LIST_SIZE) {
+		IWM_DBG_TX(iwm, DBG, "LINK: stop netif_subqueue[%d]\n", queue);
+		netif_stop_subqueue(netdev, queue);
+		return NETDEV_TX_BUSY;
+	}
+
+	ret = ieee80211_data_from_8023(skb, netdev->dev_addr, wdev->iftype,
+				       iwm->bssid, 0);
+	if (ret) {
+		IWM_ERR(iwm, "build wifi header failed\n");
+		goto drop;
+	}
+
+	dst_addr = ((struct ieee80211_hdr *)(skb->data))->addr1;
+
+	for (sta_id = 0; sta_id < IWM_STA_TABLE_NUM; sta_id++) {
+		sta_info = &iwm->sta_table[sta_id];
+		if (sta_info->valid &&
+		    !memcmp(dst_addr, sta_info->addr, ETH_ALEN))
+			break;
+	}
+
+	if (sta_id == IWM_STA_TABLE_NUM) {
+		IWM_ERR(iwm, "STA %pM not found in sta_table, Tx ignored\n",
+			dst_addr);
+		goto drop;
+	}
+
+	tx_info = skb_to_tx_info(skb);
+	tx_info->sta = sta_id;
+	tx_info->color = sta_info->color;
+	/* UMAC uses TID 8 (vs. 0) for non QoS packets */
+	if (sta_info->qos)
+		tx_info->tid = skb->priority;
+	else
+		tx_info->tid = IWM_UMAC_MGMT_TID;
+
+	skb_queue_tail(&iwm->txq[queue].queue, skb);
+
+	queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker);
+
+	ndev->stats.tx_packets++;
+	ndev->stats.tx_bytes += skb->len;
+	return NETDEV_TX_OK;
+
+ drop:
+	ndev->stats.tx_dropped++;
+	dev_kfree_skb_any(skb);
+	return NETDEV_TX_OK;
+}
diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h
new file mode 100644
index 0000000..4a95cce
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/umac.h
@@ -0,0 +1,744 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ *
+ * Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ */
+
+#ifndef __IWM_UMAC_H__
+#define __IWM_UMAC_H__
+
+struct iwm_udma_in_hdr {
+	__le32 cmd;
+	__le32 size;
+} __attribute__ ((packed));
+
+struct iwm_udma_out_nonwifi_hdr {
+	__le32 cmd;
+	__le32 addr;
+	__le32 op1_sz;
+	__le32 op2;
+} __attribute__ ((packed));
+
+struct iwm_udma_out_wifi_hdr {
+	__le32 cmd;
+	__le32 meta_data;
+} __attribute__ ((packed));
+
+/* Sequence numbering */
+#define UMAC_WIFI_SEQ_NUM_BASE		1
+#define UMAC_WIFI_SEQ_NUM_MAX		0x4000
+#define UMAC_NONWIFI_SEQ_NUM_BASE	1
+#define UMAC_NONWIFI_SEQ_NUM_MAX	0x10
+
+/* MAC address address */
+#define WICO_MAC_ADDRESS_ADDR               0x604008F8
+
+/* RA / TID */
+#define UMAC_HDI_ACT_TBL_IDX_TID_POS                  0
+#define UMAC_HDI_ACT_TBL_IDX_TID_SEED                 0xF
+
+#define UMAC_HDI_ACT_TBL_IDX_RA_POS                   4
+#define UMAC_HDI_ACT_TBL_IDX_RA_SEED                  0xF
+
+#define UMAC_HDI_ACT_TBL_IDX_RA_UMAC                  0xF
+#define UMAC_HDI_ACT_TBL_IDX_TID_UMAC                 0x9
+#define UMAC_HDI_ACT_TBL_IDX_TID_LMAC                 0xA
+
+#define UMAC_HDI_ACT_TBL_IDX_HOST_CMD \
+	((UMAC_HDI_ACT_TBL_IDX_RA_UMAC << UMAC_HDI_ACT_TBL_IDX_RA_POS) |\
+	 (UMAC_HDI_ACT_TBL_IDX_TID_UMAC << UMAC_HDI_ACT_TBL_IDX_TID_POS))
+#define UMAC_HDI_ACT_TBL_IDX_UMAC_CMD \
+	((UMAC_HDI_ACT_TBL_IDX_RA_UMAC << UMAC_HDI_ACT_TBL_IDX_RA_POS) |\
+	(UMAC_HDI_ACT_TBL_IDX_TID_LMAC << UMAC_HDI_ACT_TBL_IDX_TID_POS))
+
+/* iwm_umac_notif_alive.page_grp_state Group number -- bits [3:0] */
+#define UMAC_ALIVE_PAGE_STS_GRP_NUM_POS		0
+#define UMAC_ALIVE_PAGE_STS_GRP_NUM_SEED	0xF
+
+/* iwm_umac_notif_alive.page_grp_state Super group number -- bits [7:4] */
+#define UMAC_ALIVE_PAGE_STS_SGRP_NUM_POS	4
+#define UMAC_ALIVE_PAGE_STS_SGRP_NUM_SEED	0xF
+
+/* iwm_umac_notif_alive.page_grp_state Group min size -- bits [15:8] */
+#define UMAC_ALIVE_PAGE_STS_GRP_MIN_SIZE_POS	8
+#define UMAC_ALIVE_PAGE_STS_GRP_MIN_SIZE_SEED	0xFF
+
+/* iwm_umac_notif_alive.page_grp_state Group max size -- bits [23:16] */
+#define UMAC_ALIVE_PAGE_STS_GRP_MAX_SIZE_POS	16
+#define UMAC_ALIVE_PAGE_STS_GRP_MAX_SIZE_SEED	0xFF
+
+/* iwm_umac_notif_alive.page_grp_state Super group max size -- bits [31:24] */
+#define UMAC_ALIVE_PAGE_STS_SGRP_MAX_SIZE_POS	24
+#define UMAC_ALIVE_PAGE_STS_SGRP_MAX_SIZE_SEED	0xFF
+
+/* Barkers */
+#define UMAC_REBOOT_BARKER		0xdeadbeef
+#define UMAC_ACK_BARKER			0xfeedbabe
+#define UMAC_PAD_TERMINAL		0xadadadad
+
+/* UMAC JMP address */
+#define UMAC_MU_FW_INST_DATA_12_ADDR    0xBF0000
+
+/* iwm_umac_hdi_out_hdr.cmd OP code -- bits [3:0] */
+#define UMAC_HDI_OUT_CMD_OPCODE_POS	0
+#define UMAC_HDI_OUT_CMD_OPCODE_SEED	0xF
+
+/* iwm_umac_hdi_out_hdr.cmd End-Of-Transfer -- bits [10:10] */
+#define UMAC_HDI_OUT_CMD_EOT_POS	10
+#define UMAC_HDI_OUT_CMD_EOT_SEED	0x1
+
+/* iwm_umac_hdi_out_hdr.cmd UTFD only usage -- bits [11:11] */
+#define UMAC_HDI_OUT_CMD_UTFD_ONLY_POS	11
+#define UMAC_HDI_OUT_CMD_UTFD_ONLY_SEED	0x1
+
+/* iwm_umac_hdi_out_hdr.cmd Non-WiFi HW sequence number -- bits [12:15] */
+#define UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM_POS   12
+#define UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM_SEED  0xF
+
+/* iwm_umac_hdi_out_hdr.cmd Signature -- bits [31:16] */
+#define UMAC_HDI_OUT_CMD_SIGNATURE_POS	16
+#define UMAC_HDI_OUT_CMD_SIGNATURE_SEED	0xFFFF
+
+/* iwm_umac_hdi_out_hdr.meta_data Byte count -- bits [11:0] */
+#define UMAC_HDI_OUT_BYTE_COUNT_POS	0
+#define UMAC_HDI_OUT_BYTE_COUNT_SEED	0xFFF
+
+/* iwm_umac_hdi_out_hdr.meta_data Credit group -- bits [15:12] */
+#define UMAC_HDI_OUT_CREDIT_GRP_POS	12
+#define UMAC_HDI_OUT_CREDIT_GRP_SEED	0xF
+
+/* iwm_umac_hdi_out_hdr.meta_data RA/TID -- bits [23:16] */
+#define UMAC_HDI_OUT_RATID_POS		16
+#define UMAC_HDI_OUT_RATID_SEED		0xFF
+
+/* iwm_umac_hdi_out_hdr.meta_data LMAC offset -- bits [31:24] */
+#define UMAC_HDI_OUT_LMAC_OFFSET_POS	24
+#define UMAC_HDI_OUT_LMAC_OFFSET_SEED	0xFF
+
+/* Signature */
+#define UMAC_HDI_OUT_SIGNATURE		0xCBBC
+
+/* buffer alignment */
+#define UMAC_HDI_BUF_ALIGN_MSK		0xF
+
+/*  iwm_umac_hdi_in_hdr.cmd OP code -- bits [3:0] */
+#define UMAC_HDI_IN_CMD_OPCODE_POS                0
+#define UMAC_HDI_IN_CMD_OPCODE_SEED               0xF
+
+/*  iwm_umac_hdi_in_hdr.cmd Non-WiFi API response -- bits [6:4] */
+#define UMAC_HDI_IN_CMD_NON_WIFI_RESP_POS         4
+#define UMAC_HDI_IN_CMD_NON_WIFI_RESP_SEED        0x7
+
+/* iwm_umac_hdi_in_hdr.cmd WiFi API source -- bits [5:4] */
+#define UMAC_HDI_IN_CMD_SOURCE_POS                4
+#define UMAC_HDI_IN_CMD_SOURCE_SEED               0x3
+
+/* iwm_umac_hdi_in_hdr.cmd WiFi API EOT -- bits [6:6] */
+#define UMAC_HDI_IN_CMD_EOT_POS                   6
+#define UMAC_HDI_IN_CMD_EOT_SEED                  0x1
+
+/* iwm_umac_hdi_in_hdr.cmd timestamp present -- bits [7:7] */
+#define UMAC_HDI_IN_CMD_TIME_STAMP_PRESENT_POS    7
+#define UMAC_HDI_IN_CMD_TIME_STAMP_PRESENT_SEED   0x1
+
+/* iwm_umac_hdi_in_hdr.cmd WiFi Non-last AMSDU -- bits [8:8] */
+#define UMAC_HDI_IN_CMD_NON_LAST_AMSDU_POS        8
+#define UMAC_HDI_IN_CMD_NON_LAST_AMSDU_SEED       0x1
+
+/* iwm_umac_hdi_in_hdr.cmd WiFi HW sequence number -- bits [31:9] */
+#define UMAC_HDI_IN_CMD_HW_SEQ_NUM_POS            9
+#define UMAC_HDI_IN_CMD_HW_SEQ_NUM_SEED           0x7FFFFF
+
+/* iwm_umac_hdi_in_hdr.cmd Non-WiFi HW sequence number -- bits [12:15] */
+#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM_POS   12
+#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM_SEED  0xF
+
+/* iwm_umac_hdi_in_hdr.cmd Non-WiFi HW signature -- bits [16:31] */
+#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG_POS       16
+#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG_SEED      0xFFFF
+
+/* Fixed Non-WiFi signature */
+#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG           0xCBBC
+
+/* IN NTFY op-codes */
+#define UMAC_NOTIFY_OPCODE_ALIVE		0xA1
+#define UMAC_NOTIFY_OPCODE_INIT_COMPLETE	0xA2
+#define UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS	0xA3
+#define UMAC_NOTIFY_OPCODE_ERROR		0xA4
+#define UMAC_NOTIFY_OPCODE_DEBUG		0xA5
+#define UMAC_NOTIFY_OPCODE_WIFI_IF_WRAPPER	0xB0
+#define UMAC_NOTIFY_OPCODE_STATS		0xB1
+#define UMAC_NOTIFY_OPCODE_PAGE_DEALLOC		0xB3
+#define UMAC_NOTIFY_OPCODE_RX_TICKET		0xB4
+#define UMAC_NOTIFY_OPCODE_MAX		        (UMAC_NOTIFY_OPCODE_RX_TICKET -\
+						UMAC_NOTIFY_OPCODE_ALIVE + 1)
+#define UMAC_NOTIFY_OPCODE_FIRST		(UMAC_NOTIFY_OPCODE_ALIVE)
+
+/* HDI OUT OP CODE */
+#define UMAC_HDI_OUT_OPCODE_PING		0x0
+#define UMAC_HDI_OUT_OPCODE_READ		0x1
+#define UMAC_HDI_OUT_OPCODE_WRITE		0x2
+#define UMAC_HDI_OUT_OPCODE_JUMP		0x3
+#define UMAC_HDI_OUT_OPCODE_REBOOT		0x4
+#define UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT	0x5
+#define UMAC_HDI_OUT_OPCODE_READ_PERSISTENT	0x6
+#define UMAC_HDI_OUT_OPCODE_READ_MODIFY_WRITE	0x7
+/* #define UMAC_HDI_OUT_OPCODE_RESERVED		0x8..0xA */
+#define UMAC_HDI_OUT_OPCODE_WRITE_AUX_REG	0xB
+#define UMAC_HDI_OUT_OPCODE_WIFI		0xF
+
+/* HDI IN OP CODE -- Non WiFi*/
+#define UMAC_HDI_IN_OPCODE_PING			0x0
+#define UMAC_HDI_IN_OPCODE_READ			0x1
+#define UMAC_HDI_IN_OPCODE_WRITE		0x2
+#define UMAC_HDI_IN_OPCODE_WRITE_PERSISTENT	0x5
+#define UMAC_HDI_IN_OPCODE_READ_PERSISTENT	0x6
+#define UMAC_HDI_IN_OPCODE_READ_MODIFY_WRITE	0x7
+#define UMAC_HDI_IN_OPCODE_EP_MGMT		0x8
+#define UMAC_HDI_IN_OPCODE_CREDIT_CHANGE	0x9
+#define UMAC_HDI_IN_OPCODE_CTRL_DATABASE	0xA
+#define UMAC_HDI_IN_OPCODE_WRITE_AUX_REG	0xB
+#define UMAC_HDI_IN_OPCODE_NONWIFI_MAX \
+		(UMAC_HDI_IN_OPCODE_WRITE_AUX_REG + 1)
+#define UMAC_HDI_IN_OPCODE_WIFI			0xF
+
+/* HDI IN SOURCE */
+#define UMAC_HDI_IN_SOURCE_FHRX			0x0
+#define UMAC_HDI_IN_SOURCE_UDMA			0x1
+#define UMAC_HDI_IN_SOURCE_FW			0x2
+#define UMAC_HDI_IN_SOURCE_RESERVED		0x3
+
+/* OUT CMD op-codes */
+#define UMAC_CMD_OPCODE_ECHO                    0x01
+#define UMAC_CMD_OPCODE_HALT                    0x02
+#define UMAC_CMD_OPCODE_RESET                   0x03
+#define UMAC_CMD_OPCODE_BULK_EP_INACT_TIMEOUT   0x09
+#define UMAC_CMD_OPCODE_URB_CANCEL_ACK          0x0A
+#define UMAC_CMD_OPCODE_DCACHE_FLUSH            0x0B
+#define UMAC_CMD_OPCODE_EEPROM_PROXY            0x0C
+#define UMAC_CMD_OPCODE_TX_ECHO                 0x0D
+#define UMAC_CMD_OPCODE_DBG_MON                 0x0E
+#define UMAC_CMD_OPCODE_INTERNAL_TX             0x0F
+#define UMAC_CMD_OPCODE_SET_PARAM_FIX           0x10
+#define UMAC_CMD_OPCODE_SET_PARAM_VAR           0x11
+#define UMAC_CMD_OPCODE_GET_PARAM               0x12
+#define UMAC_CMD_OPCODE_DBG_EVENT_WRAPPER       0x13
+#define UMAC_CMD_OPCODE_TARGET                  0x14
+#define UMAC_CMD_OPCODE_STATISTIC_REQUEST       0x15
+#define UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST	0x16
+#define UMAC_CMD_OPCODE_SET_PARAM_LIST		0x17
+#define UMAC_CMD_OPCODE_GET_PARAM_LIST		0x18
+#define UMAC_CMD_OPCODE_BASE_WRAPPER            0xFA
+#define UMAC_CMD_OPCODE_LMAC_WRAPPER            0xFB
+#define UMAC_CMD_OPCODE_HW_TEST_WRAPPER         0xFC
+#define UMAC_CMD_OPCODE_WIFI_IF_WRAPPER         0xFD
+#define UMAC_CMD_OPCODE_WIFI_WRAPPER            0xFE
+#define UMAC_CMD_OPCODE_WIFI_PASS_THROUGH       0xFF
+
+/* UMAC WiFi interface op-codes */
+#define UMAC_WIFI_IF_CMD_SET_PROFILE                     0x11
+#define UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE              0x12
+#define UMAC_WIFI_IF_CMD_SET_EXCLUDE_LIST                0x13
+#define UMAC_WIFI_IF_CMD_SCAN_REQUEST                    0x14
+#define UMAC_WIFI_IF_CMD_SCAN_CONFIG                     0x15
+#define UMAC_WIFI_IF_CMD_ADD_WEP40_KEY                   0x16
+#define UMAC_WIFI_IF_CMD_ADD_WEP104_KEY                  0x17
+#define UMAC_WIFI_IF_CMD_ADD_TKIP_KEY                    0x18
+#define UMAC_WIFI_IF_CMD_ADD_CCMP_KEY                    0x19
+#define UMAC_WIFI_IF_CMD_REMOVE_KEY                      0x1A
+#define UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID                0x1B
+#define UMAC_WIFI_IF_CMD_SET_HOST_EXTENDED_IE            0x1C
+#define UMAC_WIFI_IF_CMD_GET_SUPPORTED_CHANNELS          0x1E
+#define UMAC_WIFI_IF_CMD_TX_PWR_TRIGGER                  0x20
+
+/* UMAC WiFi interface ports */
+#define UMAC_WIFI_IF_FLG_PORT_DEF                        0x00
+#define UMAC_WIFI_IF_FLG_PORT_PAN                        0x01
+#define UMAC_WIFI_IF_FLG_PORT_PAN_INVALID                WIFI_IF_FLG_PORT_DEF
+
+/* UMAC WiFi interface actions */
+#define UMAC_WIFI_IF_FLG_ACT_GET                         0x10
+#define UMAC_WIFI_IF_FLG_ACT_SET                         0x20
+
+/* iwm_umac_fw_cmd_hdr.meta_data byte count -- bits [11:0] */
+#define UMAC_FW_CMD_BYTE_COUNT_POS            0
+#define UMAC_FW_CMD_BYTE_COUNT_SEED           0xFFF
+
+/* iwm_umac_fw_cmd_hdr.meta_data status -- bits [15:12] */
+#define UMAC_FW_CMD_STATUS_POS                12
+#define UMAC_FW_CMD_STATUS_SEED               0xF
+
+/* iwm_umac_fw_cmd_hdr.meta_data full TX command by Driver -- bits [16:16] */
+#define UMAC_FW_CMD_TX_DRV_FULL_CMD_POS       16
+#define UMAC_FW_CMD_TX_DRV_FULL_CMD_SEED      0x1
+
+/* iwm_umac_fw_cmd_hdr.meta_data TX command by FW -- bits [17:17] */
+#define UMAC_FW_CMD_TX_FW_CMD_POS             17
+#define UMAC_FW_CMD_TX_FW_CMD_SEED            0x1
+
+/* iwm_umac_fw_cmd_hdr.meta_data TX plaintext mode -- bits [18:18] */
+#define UMAC_FW_CMD_TX_PLAINTEXT_POS          18
+#define UMAC_FW_CMD_TX_PLAINTEXT_SEED         0x1
+
+/* iwm_umac_fw_cmd_hdr.meta_data STA color -- bits [22:20] */
+#define UMAC_FW_CMD_TX_STA_COLOR_POS          20
+#define UMAC_FW_CMD_TX_STA_COLOR_SEED         0x7
+
+/* iwm_umac_fw_cmd_hdr.meta_data TX life time (TU) -- bits [31:24] */
+#define UMAC_FW_CMD_TX_LIFETIME_TU_POS        24
+#define UMAC_FW_CMD_TX_LIFETIME_TU_SEED       0xFF
+
+/* iwm_dev_cmd_hdr.flags Response required -- bits [5:5] */
+#define UMAC_DEV_CMD_FLAGS_RESP_REQ_POS		5
+#define UMAC_DEV_CMD_FLAGS_RESP_REQ_SEED	0x1
+
+/* iwm_dev_cmd_hdr.flags Aborted command -- bits [6:6] */
+#define UMAC_DEV_CMD_FLAGS_ABORT_POS		6
+#define UMAC_DEV_CMD_FLAGS_ABORT_SEED		0x1
+
+/* iwm_dev_cmd_hdr.flags Internal command -- bits [7:7] */
+#define DEV_CMD_FLAGS_FLD_INTERNAL_POS		7
+#define DEV_CMD_FLAGS_FLD_INTERNAL_SEED		0x1
+
+/* Rx */
+/* Rx actions */
+#define IWM_RX_TICKET_DROP           0x0
+#define IWM_RX_TICKET_RELEASE        0x1
+#define IWM_RX_TICKET_SNIFFER        0x2
+#define IWM_RX_TICKET_ENQUEUE        0x3
+
+/* Rx flags */
+#define IWM_RX_TICKET_PAD_SIZE_MSK        0x2
+#define IWM_RX_TICKET_SPECIAL_SNAP_MSK    0x4
+#define IWM_RX_TICKET_AMSDU_MSK           0x8
+#define IWM_RX_TICKET_DROP_REASON_POS       4
+#define IWM_RX_TICKET_DROP_REASON_MSK (0x1F << RX_TICKET_FLAGS_DROP_REASON_POS)
+
+#define IWM_RX_DROP_NO_DROP                          0x0
+#define IWM_RX_DROP_BAD_CRC                          0x1
+/* L2P no address match */
+#define IWM_RX_DROP_LMAC_ADDR_FILTER                 0x2
+/* Multicast address not in list */
+#define IWM_RX_DROP_MCAST_ADDR_FILTER                0x3
+/* Control frames are not sent to the driver */
+#define IWM_RX_DROP_CTL_FRAME                        0x4
+/* Our frame is back */
+#define IWM_RX_DROP_OUR_TX                           0x5
+/* Association class filtering */
+#define IWM_RX_DROP_CLASS_FILTER                     0x6
+/* Duplicated frame */
+#define IWM_RX_DROP_DUPLICATE_FILTER                 0x7
+/* Decryption error */
+#define IWM_RX_DROP_SEC_ERR                          0x8
+/* Unencrypted frame while encryption is on */
+#define IWM_RX_DROP_SEC_NO_ENCRYPTION                0x9
+/* Replay check failure */
+#define IWM_RX_DROP_SEC_REPLAY_ERR                   0xa
+/* uCode and FW key color mismatch, check before replay */
+#define IWM_RX_DROP_SEC_KEY_COLOR_MISMATCH           0xb
+#define IWM_RX_DROP_SEC_TKIP_COUNTER_MEASURE         0xc
+/* No fragmentations Db is found */
+#define IWM_RX_DROP_FRAG_NO_RESOURCE                 0xd
+/* Fragmention Db has seqCtl mismatch Vs. non-1st frag */
+#define IWM_RX_DROP_FRAG_ERR                         0xe
+#define IWM_RX_DROP_FRAG_LOST                        0xf
+#define IWM_RX_DROP_FRAG_COMPLETE                    0x10
+/* Should be handled by UMAC */
+#define IWM_RX_DROP_MANAGEMENT                       0x11
+/* STA not found by UMAC */
+#define IWM_RX_DROP_NO_STATION                       0x12
+/* NULL or QoS NULL */
+#define IWM_RX_DROP_NULL_DATA                        0x13
+#define IWM_RX_DROP_BA_REORDER_OLD_SEQCTL            0x14
+#define IWM_RX_DROP_BA_REORDER_DUPLICATE             0x15
+
+struct iwm_rx_ticket {
+	__le16 action;
+	__le16 id;
+	__le16 flags;
+	u8 payload_offset; /* includes: MAC header, pad, IV */
+	u8 tail_len; /* includes: MIC, ICV, CRC (w/o STATUS) */
+} __attribute__ ((packed));
+
+struct iwm_rx_mpdu_hdr {
+	__le16 len;
+	__le16 reserved;
+} __attribute__ ((packed));
+
+/* UMAC SW WIFI API */
+
+struct iwm_dev_cmd_hdr {
+	u8 cmd;
+	u8 flags;
+	__le16 seq_num;
+} __attribute__ ((packed));
+
+struct iwm_umac_fw_cmd_hdr {
+	__le32 meta_data;
+	struct iwm_dev_cmd_hdr cmd;
+} __attribute__ ((packed));
+
+struct iwm_umac_wifi_out_hdr {
+	struct iwm_udma_out_wifi_hdr hw_hdr;
+	struct iwm_umac_fw_cmd_hdr sw_hdr;
+} __attribute__ ((packed));
+
+struct iwm_umac_nonwifi_out_hdr {
+	struct iwm_udma_out_nonwifi_hdr hw_hdr;
+} __attribute__ ((packed));
+
+struct iwm_umac_wifi_in_hdr {
+	struct iwm_udma_in_hdr hw_hdr;
+	struct iwm_umac_fw_cmd_hdr sw_hdr;
+} __attribute__ ((packed));
+
+struct iwm_umac_nonwifi_in_hdr {
+	struct iwm_udma_in_hdr hw_hdr;
+	__le32 time_stamp;
+} __attribute__ ((packed));
+
+#define IWM_UMAC_PAGE_SIZE	0x200
+
+/* Notify structures */
+struct iwm_fw_version {
+	u8 minor;
+	u8 major;
+	__le16 id;
+};
+
+struct iwm_fw_build {
+	u8 type;
+	u8 subtype;
+	u8 platform;
+	u8 opt;
+};
+
+struct iwm_fw_alive_hdr {
+	struct iwm_fw_version ver;
+	struct iwm_fw_build build;
+	__le32 os_build;
+	__le32 log_hdr_addr;
+	__le32 log_buf_addr;
+	__le32 sys_timer_addr;
+};
+
+#define WAIT_NOTIF_TIMEOUT     (2 * HZ)
+#define SCAN_COMPLETE_TIMEOUT  (3 * HZ)
+
+#define UMAC_NTFY_ALIVE_STATUS_ERR		0xDEAD
+#define UMAC_NTFY_ALIVE_STATUS_OK		0xCAFE
+
+#define UMAC_NTFY_INIT_COMPLETE_STATUS_ERR	0xDEAD
+#define UMAC_NTFY_INIT_COMPLETE_STATUS_OK	0xCAFE
+
+#define UMAC_NTFY_WIFI_CORE_STATUS_LINK_EN      0x40
+#define UMAC_NTFY_WIFI_CORE_STATUS_MLME_EN      0x80
+
+#define IWM_MACS_OUT_GROUPS	6
+#define IWM_MACS_OUT_SGROUPS	1
+
+
+#define WIFI_IF_NTFY_ASSOC_START			0x80
+#define WIFI_IF_NTFY_ASSOC_COMPLETE			0x81
+#define WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE	0x82
+#define WIFI_IF_NTFY_CONNECTION_TERMINATED		0x83
+#define WIFI_IF_NTFY_SCAN_COMPLETE			0x84
+#define WIFI_IF_NTFY_STA_TABLE_CHANGE			0x85
+#define WIFI_IF_NTFY_EXTENDED_IE_REQUIRED		0x86
+#define WIFI_IF_NTFY_RADIO_PREEMPTION			0x87
+#define WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED		0x88
+#define WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED		0x89
+#define WIFI_IF_NTFY_LINK_QUALITY_STATISTICS		0x8A
+#define WIFI_IF_NTFY_MGMT_FRAME				0x8B
+
+/* DEBUG INDICATIONS */
+#define WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_START		0xE0
+#define WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_COMPLETE	0xE1
+#define WIFI_DBG_IF_NTFY_SCAN_CHANNEL_START		0xE2
+#define WIFI_DBG_IF_NTFY_SCAN_CHANNEL_RESULT		0xE3
+#define WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_START		0xE4
+#define WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_COMPLETE		0xE5
+#define WIFI_DBG_IF_NTFY_CNCT_ATC_START			0xE6
+#define WIFI_DBG_IF_NTFY_COEX_NOTIFICATION		0xE7
+#define WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP		0xE8
+#define WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP	0xE9
+
+/* Notification structures */
+struct iwm_umac_notif_wifi_if {
+	struct iwm_umac_wifi_in_hdr hdr;
+	u8 status;
+	u8 flags;
+	__le16 buf_size;
+} __attribute__ ((packed));
+
+#define UMAC_ROAM_REASON_FIRST_SELECTION	0x1
+#define UMAC_ROAM_REASON_AP_DEAUTH		0x2
+#define UMAC_ROAM_REASON_AP_CONNECT_LOST	0x3
+#define UMAC_ROAM_REASON_RSSI			0x4
+#define UMAC_ROAM_REASON_AP_ASSISTED_ROAM	0x5
+#define UMAC_ROAM_REASON_IBSS_COALESCING	0x6
+
+struct iwm_umac_notif_assoc_start {
+	struct iwm_umac_notif_wifi_if mlme_hdr;
+	__le32 roam_reason;
+	u8 bssid[ETH_ALEN];
+	u8 reserved[2];
+} __attribute__ ((packed));
+
+#define UMAC_ASSOC_COMPLETE_SUCCESS		0x0
+#define UMAC_ASSOC_COMPLETE_FAILURE		0x1
+
+struct iwm_umac_notif_assoc_complete {
+	struct iwm_umac_notif_wifi_if mlme_hdr;
+	__le32 status;
+	u8 bssid[ETH_ALEN];
+	u8 band;
+	u8 channel;
+} __attribute__ ((packed));
+
+#define UMAC_PROFILE_INVALID_ASSOC_TIMEOUT	0x0
+#define UMAC_PROFILE_INVALID_ROAM_TIMEOUT	0x1
+#define UMAC_PROFILE_INVALID_REQUEST		0x2
+#define UMAC_PROFILE_INVALID_RF_PREEMPTED	0x3
+
+struct iwm_umac_notif_profile_invalidate {
+	struct iwm_umac_notif_wifi_if mlme_hdr;
+	__le32 reason;
+} __attribute__ ((packed));
+
+#define UMAC_SCAN_RESULT_SUCCESS  0x0
+#define UMAC_SCAN_RESULT_ABORTED  0x1
+#define UMAC_SCAN_RESULT_REJECTED 0x2
+#define UMAC_SCAN_RESULT_FAILED   0x3
+
+struct iwm_umac_notif_scan_complete {
+	struct iwm_umac_notif_wifi_if mlme_hdr;
+	__le32 type;
+	__le32 result;
+	u8 seq_num;
+} __attribute__ ((packed));
+
+#define UMAC_OPCODE_ADD_MODIFY	0x0
+#define UMAC_OPCODE_REMOVE	0x1
+#define UMAC_OPCODE_CLEAR_ALL	0x2
+
+#define UMAC_STA_FLAG_QOS	0x1
+
+struct iwm_umac_notif_sta_info {
+	struct iwm_umac_notif_wifi_if mlme_hdr;
+	__le32 opcode;
+	u8 mac_addr[ETH_ALEN];
+	u8 sta_id; /* bits 0-3: station ID, bits 4-7: station color */
+	u8 flags;
+} __attribute__ ((packed));
+
+#define UMAC_BAND_2GHZ 0
+#define UMAC_BAND_5GHZ 1
+
+#define UMAC_CHANNEL_WIDTH_20MHZ 0
+#define UMAC_CHANNEL_WIDTH_40MHZ 1
+
+struct iwm_umac_notif_bss_info {
+	struct iwm_umac_notif_wifi_if mlme_hdr;
+	__le32 type;
+	__le32 timestamp;
+	__le16 table_idx;
+	__le16 frame_len;
+	u8 band;
+	u8 channel;
+	s8 rssi;
+	u8 reserved;
+	u8 frame_buf[1];
+} __attribute__ ((packed));
+
+#define IWM_BSS_REMOVE_INDEX_MSK           0x0fff
+#define IWM_BSS_REMOVE_FLAGS_MSK           0xfc00
+
+#define IWM_BSS_REMOVE_FLG_AGE             0x1000
+#define IWM_BSS_REMOVE_FLG_TIMEOUT         0x2000
+#define IWM_BSS_REMOVE_FLG_TABLE_FULL      0x4000
+
+struct iwm_umac_notif_bss_removed {
+	struct iwm_umac_notif_wifi_if mlme_hdr;
+	__le32 count;
+	__le16 entries[0];
+} __attribute__ ((packed));
+
+struct iwm_umac_notif_mgt_frame {
+	struct iwm_umac_notif_wifi_if mlme_hdr;
+	__le16 len;
+	u8 frame[1];
+} __attribute__ ((packed));
+
+struct iwm_umac_notif_alive {
+	struct iwm_umac_wifi_in_hdr hdr;
+	__le16 status;
+	__le16 reserved1;
+	struct iwm_fw_alive_hdr alive_data;
+	__le16 reserved2;
+	__le16 page_grp_count;
+	__le32 page_grp_state[IWM_MACS_OUT_GROUPS];
+} __attribute__ ((packed));
+
+struct iwm_umac_notif_init_complete {
+	__le16 status;
+	__le16 reserved;
+} __attribute__ ((packed));
+
+/* error categories */
+enum {
+	UMAC_SYS_ERR_CAT_NONE = 0,
+	UMAC_SYS_ERR_CAT_BOOT,
+	UMAC_SYS_ERR_CAT_UMAC,
+	UMAC_SYS_ERR_CAT_UAXM,
+	UMAC_SYS_ERR_CAT_LMAC,
+	UMAC_SYS_ERR_CAT_MAX
+};
+
+struct iwm_fw_error_hdr {
+	__le32 category;
+	__le32 status;
+	__le32 pc;
+	__le32 blink1;
+	__le32 blink2;
+	__le32 ilink1;
+	__le32 ilink2;
+	__le32 data1;
+	__le32 data2;
+	__le32 line_num;
+	__le32 umac_status;
+	__le32 lmac_status;
+	__le32 sdio_status;
+} __attribute__ ((packed));
+
+struct iwm_umac_notif_error {
+	struct iwm_umac_wifi_in_hdr hdr;
+	struct iwm_fw_error_hdr err;
+} __attribute__ ((packed));
+
+#define UMAC_DEALLOC_NTFY_CHANGES_CNT_POS	0
+#define UMAC_DEALLOC_NTFY_CHANGES_CNT_SEED	0xff
+#define UMAC_DEALLOC_NTFY_CHANGES_MSK_POS	8
+#define UMAC_DEALLOC_NTFY_CHANGES_MSK_SEED	0xffffff
+#define UMAC_DEALLOC_NTFY_PAGE_CNT_POS		0
+#define UMAC_DEALLOC_NTFY_PAGE_CNT_SEED		0xffffff
+#define UMAC_DEALLOC_NTFY_GROUP_NUM_POS		24
+#define UMAC_DEALLOC_NTFY_GROUP_NUM_SEED	0xf
+
+struct iwm_umac_notif_page_dealloc {
+	struct iwm_umac_wifi_in_hdr hdr;
+	__le32 changes;
+	__le32 grp_info[IWM_MACS_OUT_GROUPS];
+} __attribute__ ((packed));
+
+struct iwm_umac_notif_wifi_status {
+	struct iwm_umac_wifi_in_hdr hdr;
+	__le16 status;
+	__le16 reserved;
+} __attribute__ ((packed));
+
+struct iwm_umac_notif_rx_ticket {
+	struct iwm_umac_wifi_in_hdr hdr;
+	u8 num_tickets;
+	u8 reserved[3];
+	struct iwm_rx_ticket tickets[1];
+} __attribute__ ((packed));
+
+/* Tx/Rx rates window (number of max of last update window per second) */
+#define UMAC_NTF_RATE_SAMPLE_NR	4
+
+#define IWM_UMAC_MGMT_TID	8
+#define IWM_UMAC_TID_NR		8
+
+struct iwm_umac_notif_stats {
+	struct iwm_umac_wifi_in_hdr hdr;
+	__le32 flags;
+	__le32 timestamp;
+	__le16 tid_load[IWM_UMAC_TID_NR + 2]; /* 1 non-QoS + 1 dword align */
+	__le16 tx_rate[UMAC_NTF_RATE_SAMPLE_NR];
+	__le16 rx_rate[UMAC_NTF_RATE_SAMPLE_NR];
+	s32 rssi_dbm;
+	s32 noise_dbm;
+	__le32 supp_rates;
+	__le32 missed_beacons;
+	__le32 rx_beacons;
+	__le32 rx_dir_pkts;
+	__le32 rx_nondir_pkts;
+	__le32 rx_multicast;
+	__le32 rx_errors;
+	__le32 rx_drop_other_bssid;
+	__le32 rx_drop_decode;
+	__le32 rx_drop_reassembly;
+	__le32 rx_drop_bad_len;
+	__le32 rx_drop_overflow;
+	__le32 rx_drop_crc;
+	__le32 rx_drop_missed;
+	__le32 tx_dir_pkts;
+	__le32 tx_nondir_pkts;
+	__le32 tx_failure;
+	__le32 tx_errors;
+	__le32 tx_drop_max_retry;
+	__le32 tx_err_abort;
+	__le32 tx_err_carrier;
+	__le32 rx_bytes;
+	__le32 tx_bytes;
+	__le32 tx_power;
+	__le32 tx_max_power;
+	__le32 roam_threshold;
+	__le32 ap_assoc_nr;
+	__le32 scan_full;
+	__le32 scan_abort;
+	__le32 ap_nr;
+	__le32 roam_nr;
+	__le32 roam_missed_beacons;
+	__le32 roam_rssi;
+	__le32 roam_unassoc;
+	__le32 roam_deauth;
+	__le32 roam_ap_loadblance;
+} __attribute__ ((packed));
+
+/* WiFi interface wrapper header */
+struct iwm_umac_wifi_if {
+	u8 oid;
+	u8 flags;
+	__le16 buf_size;
+} __attribute__ ((packed));
+
+#define IWM_SEQ_NUM_HOST_MSK	0x0000
+#define IWM_SEQ_NUM_UMAC_MSK	0x4000
+#define IWM_SEQ_NUM_LMAC_MSK	0x8000
+#define IWM_SEQ_NUM_MSK		0xC000
+
+#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c
new file mode 100644
index 0000000..584c94d
--- /dev/null
+++ b/drivers/net/wireless/iwmc3200wifi/wext.c
@@ -0,0 +1,723 @@
+/*
+ * Intel Wireless Multicomm 3200 WiFi driver
+ *
+ * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
+ * Samuel Ortiz <samuel.ortiz@intel.com>
+ * Zhu Yi <yi.zhu@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <net/cfg80211.h>
+#include <net/iw_handler.h>
+
+#include "iwm.h"
+#include "umac.h"
+#include "commands.h"
+#include "debug.h"
+
+static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev)
+{
+	struct iwm_priv *iwm = ndev_to_iwm(dev);
+	struct iw_statistics *wstats = &iwm->wstats;
+
+	if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
+		memset(wstats, 0, sizeof(struct iw_statistics));
+		wstats->qual.updated = IW_QUAL_ALL_INVALID;
+	}
+
+	return wstats;
+}
+
+static int iwm_wext_siwfreq(struct net_device *dev,
+			    struct iw_request_info *info,
+			    struct iw_freq *freq, char *extra)
+{
+	struct iwm_priv *iwm = ndev_to_iwm(dev);
+
+	if (freq->flags == IW_FREQ_AUTO)
+		return 0;
+
+	/* frequency/channel can only be set in IBSS mode */
+	if (iwm->conf.mode != UMAC_MODE_IBSS)
+		return -EOPNOTSUPP;
+
+	return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
+}
+
+static int iwm_wext_giwfreq(struct net_device *dev,
+			    struct iw_request_info *info,
+			    struct iw_freq *freq, char *extra)
+{
+	struct iwm_priv *iwm = ndev_to_iwm(dev);
+
+	if (iwm->conf.mode == UMAC_MODE_IBSS)
+		return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
+
+	freq->e = 0;
+	freq->m = iwm->channel;
+
+	return 0;
+}
+
+static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info,
+			  struct sockaddr *ap_addr, char *extra)
+{
+	struct iwm_priv *iwm = ndev_to_iwm(dev);
+
+	if (iwm->conf.mode == UMAC_MODE_IBSS)
+		return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
+
+	if (!test_bit(IWM_STATUS_READY, &iwm->status))
+		return -EIO;
+
+	if (is_zero_ether_addr(ap_addr->sa_data) ||
+	    is_broadcast_ether_addr(ap_addr->sa_data)) {
+		IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n",
+			     iwm->umac_profile->bssid[0]);
+		memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
+		iwm->umac_profile->bss_num = 0;
+	} else {
+		IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n",
+			     ap_addr->sa_data);
+		memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data,
+		       ETH_ALEN);
+		iwm->umac_profile->bss_num = 1;
+	}
+
+	if (iwm->umac_profile_active) {
+		if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN))
+			return 0;
+
+		iwm_invalidate_mlme_profile(iwm);
+	}
+
+	if (iwm->umac_profile->ssid.ssid_len)
+		return iwm_send_mlme_profile(iwm);
+
+	return 0;
+}
+
+static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info,
+			  struct sockaddr *ap_addr, char *extra)
+{
+	struct iwm_priv *iwm = ndev_to_iwm(dev);
+
+	switch (iwm->conf.mode) {
+	case UMAC_MODE_IBSS:
+		return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
+	case UMAC_MODE_BSS:
+		if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
+			ap_addr->sa_family = ARPHRD_ETHER;
+			memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN);
+		} else
+			memset(&ap_addr->sa_data, 0, ETH_ALEN);
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static int iwm_wext_siwessid(struct net_device *dev,
+			     struct iw_request_info *info,
+			     struct iw_point *data, char *ssid)
+{
+	struct iwm_priv *iwm = ndev_to_iwm(dev);
+	size_t len = data->length;
+	int ret;
+
+	if (iwm->conf.mode == UMAC_MODE_IBSS)
+		return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
+
+	if (!test_bit(IWM_STATUS_READY, &iwm->status))
+		return -EIO;
+
+	if (len > 0 && ssid[len - 1] == '\0')
+		len--;
+
+	if (iwm->umac_profile_active) {
+		if (iwm->umac_profile->ssid.ssid_len == len &&
+		    !memcmp(iwm->umac_profile->ssid.ssid, ssid, len))
+			return 0;
+
+		ret = iwm_invalidate_mlme_profile(iwm);
+		if (ret < 0) {
+			IWM_ERR(iwm, "Couldn't invalidate profile\n");
+			return ret;
+		}
+	}
+
+	iwm->umac_profile->ssid.ssid_len = len;
+	memcpy(iwm->umac_profile->ssid.ssid, ssid, len);
+
+	return iwm_send_mlme_profile(iwm);
+}
+
+static int iwm_wext_giwessid(struct net_device *dev,
+			     struct iw_request_info *info,
+			     struct iw_point *data, char *ssid)
+{
+	struct iwm_priv *iwm = ndev_to_iwm(dev);
+
+	if (iwm->conf.mode == UMAC_MODE_IBSS)
+		return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
+
+	if (!test_bit(IWM_STATUS_READY, &iwm->status))
+		return -EIO;
+
+	data->length = iwm->umac_profile->ssid.ssid_len;
+	if (data->length) {
+		memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length);
+		data->flags = 1;
+	} else
+		data->flags = 0;
+
+	return 0;
+}
+
+static struct iwm_key *
+iwm_key_init(struct iwm_priv *iwm, u8 key_idx, bool in_use,
+	     struct iw_encode_ext *ext, u8 alg)
+{
+	struct iwm_key *key = &iwm->keys[key_idx];
+
+	memset(key, 0, sizeof(struct iwm_key));
+	memcpy(key->hdr.mac, ext->addr.sa_data, ETH_ALEN);
+	key->hdr.key_idx = key_idx;
+	if (is_broadcast_ether_addr(ext->addr.sa_data))
+		key->hdr.multicast = 1;
+
+	key->in_use = in_use;
+	key->flags = ext->ext_flags;
+	key->alg = alg;
+	key->key_len = ext->key_len;
+	memcpy(key->key, ext->key, ext->key_len);
+
+	return key;
+}
+
+static int iwm_wext_giwrate(struct net_device *dev,
+			    struct iw_request_info *info,
+			    struct iw_param *rate, char *extra)
+{
+	struct iwm_priv *iwm = ndev_to_iwm(dev);
+
+	rate->value = iwm->rate * 1000000;
+
+	return 0;
+}
+
+static int iwm_wext_siwencode(struct net_device *dev,
+			      struct iw_request_info *info,
+			      struct iw_point *erq, char *key_buf)
+{
+	struct iwm_priv *iwm = ndev_to_iwm(dev);
+	struct iwm_key *uninitialized_var(key);
+	int idx, i, uninitialized_var(alg), remove = 0, ret;
+
+	IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", erq->length);
+	IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
+
+	if (!iwm->umac_profile) {
+		IWM_ERR(iwm, "UMAC profile not allocated yet\n");
+		return -ENODEV;
+	}
+
+	if (erq->length == WLAN_KEY_LEN_WEP40) {
+		alg = UMAC_CIPHER_TYPE_WEP_40;
+		iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_40;
+		iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_40;
+	} else if (erq->length == WLAN_KEY_LEN_WEP104) {
+		alg = UMAC_CIPHER_TYPE_WEP_104;
+		iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_104;
+		iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_104;
+	}
+
+	if (erq->flags & IW_ENCODE_RESTRICTED)
+		iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
+	else
+		iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN;
+
+	idx = erq->flags & IW_ENCODE_INDEX;
+	if (idx == 0) {
+		if (iwm->default_key)
+			for (i = 0; i < IWM_NUM_KEYS; i++) {
+				if (iwm->default_key == &iwm->keys[i]) {
+					idx = i;
+					break;
+				}
+			}
+		else
+			iwm->default_key = &iwm->keys[idx];
+	} else if (idx < 1 || idx > 4) {
+		return -EINVAL;
+	} else
+		idx--;
+
+	if (erq->flags & IW_ENCODE_DISABLED)
+		remove = 1;
+	else if (erq->length == 0) {
+		if (!iwm->keys[idx].in_use)
+			return -EINVAL;
+		iwm->default_key = &iwm->keys[idx];
+	}
+
+	if (erq->length) {
+		key = &iwm->keys[idx];
+		memset(key, 0, sizeof(struct iwm_key));
+		memset(key->hdr.mac, 0xff, ETH_ALEN);
+		key->hdr.key_idx = idx;
+		key->hdr.multicast = 1;
+		key->in_use = !remove;
+		key->alg = alg;
+		key->key_len = erq->length;
+		memcpy(key->key, key_buf, erq->length);
+
+		IWM_DBG_WEXT(iwm, DBG, "Setting key %d, default: %d\n",
+			     idx, !!iwm->default_key);
+	}
+
+	if (remove) {
+		if ((erq->flags & IW_ENCODE_NOKEY) || (erq->length == 0)) {
+			int j;
+			for (j = 0; j < IWM_NUM_KEYS; j++)
+				if (iwm->keys[j].in_use) {
+					struct iwm_key *k = &iwm->keys[j];
+
+					k->in_use = 0;
+					ret = iwm_set_key(iwm, remove, 0, k);
+					if (ret < 0)
+						return ret;
+				}
+
+			iwm->umac_profile->sec.ucast_cipher =
+							UMAC_CIPHER_TYPE_NONE;
+			iwm->umac_profile->sec.mcast_cipher =
+							UMAC_CIPHER_TYPE_NONE;
+			iwm->umac_profile->sec.auth_type =
+							UMAC_AUTH_TYPE_OPEN;
+
+			return 0;
+		} else {
+			key->in_use = 0;
+			return iwm_set_key(iwm, remove, 0, key);
+		}
+	}
+
+	/*
+	 * If we havent set a profile yet, we cant set keys.
+	 * Keys will be pushed after we're associated.
+	 */
+	if (!iwm->umac_profile_active)
+		return 0;
+
+	/*
+	 * If there is a current active profile, but no
+	 * default key, it's not worth trying to associate again.
+	 */
+	if (!iwm->default_key)
+		return 0;
+
+	/*
+	 * Here we have an active profile, but a key setting changed.
+	 * We thus have to invalidate the current profile, and push the
+	 * new one. Keys will be pushed when association takes place.
+	 */
+	ret = iwm_invalidate_mlme_profile(iwm);
+	if (ret < 0) {
+		IWM_ERR(iwm, "Couldn't invalidate profile\n");
+		return ret;
+	}
+
+	return iwm_send_mlme_profile(iwm);
+}
+
+static int iwm_wext_giwencode(struct net_device *dev,
+			      struct iw_request_info *info,
+			      struct iw_point *erq, char *key)
+{
+	struct iwm_priv *iwm = ndev_to_iwm(dev);
+	int idx, i;
+
+	idx = erq->flags & IW_ENCODE_INDEX;
+	if (idx < 1 || idx > 4) {
+		idx = -1;
+		if (!iwm->default_key) {
+			erq->length = 0;
+			erq->flags |= IW_ENCODE_NOKEY;
+			return 0;
+		} else
+			for (i = 0; i < IWM_NUM_KEYS; i++) {
+				if (iwm->default_key == &iwm->keys[i]) {
+					idx = i;
+					break;
+				}
+			}
+		if (idx < 0)
+			return -EINVAL;
+	} else
+		idx--;
+
+	erq->flags = idx + 1;
+
+	if (!iwm->keys[idx].in_use) {
+		erq->length = 0;
+		erq->flags |= IW_ENCODE_DISABLED;
+		return 0;
+	}
+
+	memcpy(key, iwm->keys[idx].key,
+	       min_t(int, erq->length, iwm->keys[idx].key_len));
+	erq->length = iwm->keys[idx].key_len;
+	erq->flags |= IW_ENCODE_ENABLED;
+
+	if (iwm->umac_profile->mode == UMAC_MODE_BSS) {
+		switch (iwm->umac_profile->sec.auth_type) {
+		case UMAC_AUTH_TYPE_OPEN:
+			erq->flags |= IW_ENCODE_OPEN;
+			break;
+		default:
+			erq->flags |= IW_ENCODE_RESTRICTED;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version)
+{
+	if (wpa_version & IW_AUTH_WPA_VERSION_WPA2)
+		iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
+	else if (wpa_version & IW_AUTH_WPA_VERSION_WPA)
+		iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK;
+	else
+		iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
+
+	return 0;
+}
+
+static int iwm_wext_siwpower(struct net_device *dev,
+			     struct iw_request_info *info,
+			     struct iw_param *wrq, char *extra)
+{
+	struct iwm_priv *iwm = ndev_to_iwm(dev);
+	u32 power_index;
+
+	if (wrq->disabled) {
+		power_index = IWM_POWER_INDEX_MIN;
+		goto set;
+	} else
+		power_index = IWM_POWER_INDEX_DEFAULT;
+
+	switch (wrq->flags & IW_POWER_MODE) {
+	case IW_POWER_ON:
+	case IW_POWER_MODE:
+	case IW_POWER_ALL_R:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+ set:
+	if (power_index == iwm->conf.power_index)
+		return 0;
+
+	iwm->conf.power_index = power_index;
+
+	return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+				       CFG_POWER_INDEX, iwm->conf.power_index);
+}
+
+static int iwm_wext_giwpower(struct net_device *dev,
+			     struct iw_request_info *info,
+			     union iwreq_data *wrqu, char *extra)
+{
+	struct iwm_priv *iwm = ndev_to_iwm(dev);
+
+	wrqu->power.disabled = (iwm->conf.power_index == IWM_POWER_INDEX_MIN);
+
+	return 0;
+}
+
+static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt)
+{
+	u8 *auth_type = &iwm->umac_profile->sec.auth_type;
+
+	if (key_mgt == IW_AUTH_KEY_MGMT_802_1X)
+		*auth_type = UMAC_AUTH_TYPE_8021X;
+	else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) {
+		if (iwm->umac_profile->sec.flags &
+		    (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
+			*auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
+		else
+			*auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
+	} else {
+		IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int iwm_set_cipher(struct iwm_priv *iwm, u8 cipher, u8 ucast)
+{
+	u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
+		&iwm->umac_profile->sec.mcast_cipher;
+
+	switch (cipher) {
+	case IW_AUTH_CIPHER_NONE:
+		*profile_cipher = UMAC_CIPHER_TYPE_NONE;
+		break;
+	case IW_AUTH_CIPHER_WEP40:
+		*profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
+		break;
+	case IW_AUTH_CIPHER_TKIP:
+		*profile_cipher = UMAC_CIPHER_TYPE_TKIP;
+		break;
+	case IW_AUTH_CIPHER_CCMP:
+		*profile_cipher = UMAC_CIPHER_TYPE_CCMP;
+		break;
+	case IW_AUTH_CIPHER_WEP104:
+		*profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
+		break;
+	default:
+		IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
+		return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg)
+{
+	u8 *auth_type = &iwm->umac_profile->sec.auth_type;
+
+	switch (auth_alg) {
+	case IW_AUTH_ALG_OPEN_SYSTEM:
+		*auth_type = UMAC_AUTH_TYPE_OPEN;
+		break;
+	case IW_AUTH_ALG_SHARED_KEY:
+		if (iwm->umac_profile->sec.flags &
+		    (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
+			if (*auth_type == UMAC_AUTH_TYPE_8021X)
+				return -EINVAL;
+			*auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
+		} else {
+			*auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
+		}
+		break;
+	case IW_AUTH_ALG_LEAP:
+	default:
+		IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", auth_alg);
+		return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+static int iwm_wext_siwauth(struct net_device *dev,
+			    struct iw_request_info *info,
+			    struct iw_param *data, char *extra)
+{
+	struct iwm_priv *iwm = ndev_to_iwm(dev);
+	int ret;
+
+	if ((data->flags) &
+	    (IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT |
+	     IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) {
+		/* We need to invalidate the current profile */
+		if (iwm->umac_profile_active) {
+			ret = iwm_invalidate_mlme_profile(iwm);
+			if (ret < 0) {
+				IWM_ERR(iwm, "Couldn't invalidate profile\n");
+				return ret;
+			}
+		}
+	}
+
+	switch (data->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_WPA_VERSION:
+		return iwm_set_wpa_version(iwm, data->value);
+		break;
+	case IW_AUTH_CIPHER_PAIRWISE:
+		return iwm_set_cipher(iwm, data->value, 1);
+		break;
+	case IW_AUTH_CIPHER_GROUP:
+		return iwm_set_cipher(iwm, data->value, 0);
+		break;
+	case IW_AUTH_KEY_MGMT:
+		return iwm_set_key_mgt(iwm, data->value);
+		break;
+	case IW_AUTH_80211_AUTH_ALG:
+		return iwm_set_auth_alg(iwm, data->value);
+		break;
+	default:
+		return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+static int iwm_wext_giwauth(struct net_device *dev,
+			    struct iw_request_info *info,
+			    struct iw_param *data, char *extra)
+{
+	return 0;
+}
+
+static int iwm_wext_siwencodeext(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_point *erq, char *extra)
+{
+	struct iwm_priv *iwm = ndev_to_iwm(dev);
+	struct iwm_key *key;
+	struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
+	int uninitialized_var(alg), idx, i, remove = 0;
+
+	IWM_DBG_WEXT(iwm, DBG, "alg: 0x%x\n", ext->alg);
+	IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", ext->key_len);
+	IWM_DBG_WEXT(iwm, DBG, "ext_flags: 0x%x\n", ext->ext_flags);
+	IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
+	IWM_DBG_WEXT(iwm, DBG, "length: 0x%x\n", erq->length);
+
+	switch (ext->alg) {
+	case IW_ENCODE_ALG_NONE:
+		remove = 1;
+		break;
+	case IW_ENCODE_ALG_WEP:
+		if (ext->key_len == WLAN_KEY_LEN_WEP40)
+			alg = UMAC_CIPHER_TYPE_WEP_40;
+		else if (ext->key_len == WLAN_KEY_LEN_WEP104)
+			alg = UMAC_CIPHER_TYPE_WEP_104;
+		else {
+			IWM_ERR(iwm, "Invalid key length: %d\n", ext->key_len);
+			return -EINVAL;
+		}
+
+		break;
+	case IW_ENCODE_ALG_TKIP:
+		alg = UMAC_CIPHER_TYPE_TKIP;
+		break;
+	case IW_ENCODE_ALG_CCMP:
+		alg = UMAC_CIPHER_TYPE_CCMP;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	idx = erq->flags & IW_ENCODE_INDEX;
+
+	if (idx == 0) {
+		if (iwm->default_key)
+			for (i = 0; i < IWM_NUM_KEYS; i++) {
+				if (iwm->default_key == &iwm->keys[i]) {
+					idx = i;
+					break;
+				}
+			}
+	} else if (idx < 1 || idx > 4) {
+		return -EINVAL;
+	} else
+		idx--;
+
+	if (erq->flags & IW_ENCODE_DISABLED)
+		remove = 1;
+	else if ((erq->length == 0) ||
+		 (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) {
+		iwm->default_key = &iwm->keys[idx];
+		if (iwm->umac_profile_active && ext->alg == IW_ENCODE_ALG_WEP)
+			return iwm_set_tx_key(iwm, idx);
+	}
+
+	key = iwm_key_init(iwm, idx, !remove, ext, alg);
+
+	return iwm_set_key(iwm, remove, !iwm->default_key, key);
+}
+
+static const iw_handler iwm_handlers[] =
+{
+	(iw_handler) NULL,				/* SIOCSIWCOMMIT */
+	(iw_handler) cfg80211_wext_giwname,		/* SIOCGIWNAME */
+	(iw_handler) NULL,				/* SIOCSIWNWID */
+	(iw_handler) NULL,				/* SIOCGIWNWID */
+	(iw_handler) iwm_wext_siwfreq,			/* SIOCSIWFREQ */
+	(iw_handler) iwm_wext_giwfreq,			/* SIOCGIWFREQ */
+	(iw_handler) cfg80211_wext_siwmode,		/* SIOCSIWMODE */
+	(iw_handler) cfg80211_wext_giwmode,		/* SIOCGIWMODE */
+	(iw_handler) NULL,				/* SIOCSIWSENS */
+	(iw_handler) NULL,				/* SIOCGIWSENS */
+	(iw_handler) NULL /* not used */,		/* SIOCSIWRANGE */
+	(iw_handler) cfg80211_wext_giwrange,		/* SIOCGIWRANGE */
+	(iw_handler) NULL /* not used */,		/* SIOCSIWPRIV */
+	(iw_handler) NULL /* kernel code */,		/* SIOCGIWPRIV */
+	(iw_handler) NULL /* not used */,		/* SIOCSIWSTATS */
+	(iw_handler) NULL /* kernel code */,		/* SIOCGIWSTATS */
+	(iw_handler) NULL,				/* SIOCSIWSPY */
+	(iw_handler) NULL,				/* SIOCGIWSPY */
+	(iw_handler) NULL,				/* SIOCSIWTHRSPY */
+	(iw_handler) NULL,				/* SIOCGIWTHRSPY */
+	(iw_handler) iwm_wext_siwap,	                /* SIOCSIWAP */
+	(iw_handler) iwm_wext_giwap,			/* SIOCGIWAP */
+	(iw_handler) NULL,			        /* SIOCSIWMLME */
+	(iw_handler) NULL,				/* SIOCGIWAPLIST */
+	(iw_handler) cfg80211_wext_siwscan,		/* SIOCSIWSCAN */
+	(iw_handler) cfg80211_wext_giwscan,		/* SIOCGIWSCAN */
+	(iw_handler) iwm_wext_siwessid,			/* SIOCSIWESSID */
+	(iw_handler) iwm_wext_giwessid,			/* SIOCGIWESSID */
+	(iw_handler) NULL,				/* SIOCSIWNICKN */
+	(iw_handler) NULL,				/* SIOCGIWNICKN */
+	(iw_handler) NULL,				/* -- hole -- */
+	(iw_handler) NULL,				/* -- hole -- */
+	(iw_handler) NULL,				/* SIOCSIWRATE */
+	(iw_handler) iwm_wext_giwrate,			/* SIOCGIWRATE */
+	(iw_handler) cfg80211_wext_siwrts,		/* SIOCSIWRTS */
+	(iw_handler) cfg80211_wext_giwrts,		/* SIOCGIWRTS */
+	(iw_handler) cfg80211_wext_siwfrag,	        /* SIOCSIWFRAG */
+	(iw_handler) cfg80211_wext_giwfrag,		/* SIOCGIWFRAG */
+	(iw_handler) NULL,				/* SIOCSIWTXPOW */
+	(iw_handler) NULL,				/* SIOCGIWTXPOW */
+	(iw_handler) NULL,				/* SIOCSIWRETRY */
+	(iw_handler) NULL,				/* SIOCGIWRETRY */
+	(iw_handler) iwm_wext_siwencode,		/* SIOCSIWENCODE */
+	(iw_handler) iwm_wext_giwencode,		/* SIOCGIWENCODE */
+	(iw_handler) iwm_wext_siwpower,			/* SIOCSIWPOWER */
+	(iw_handler) iwm_wext_giwpower,			/* SIOCGIWPOWER */
+	(iw_handler) NULL,				/* -- hole -- */
+	(iw_handler) NULL,				/* -- hole -- */
+	(iw_handler) NULL,                              /* SIOCSIWGENIE */
+	(iw_handler) NULL,				/* SIOCGIWGENIE */
+	(iw_handler) iwm_wext_siwauth,			/* SIOCSIWAUTH */
+	(iw_handler) iwm_wext_giwauth,			/* SIOCGIWAUTH */
+	(iw_handler) iwm_wext_siwencodeext,	        /* SIOCSIWENCODEEXT */
+	(iw_handler) NULL,				/* SIOCGIWENCODEEXT */
+	(iw_handler) NULL,				/* SIOCSIWPMKSA */
+	(iw_handler) NULL,				/* -- hole -- */
+};
+
+const struct iw_handler_def iwm_iw_handler_def = {
+	.num_standard	= ARRAY_SIZE(iwm_handlers),
+	.standard	= (iw_handler *) iwm_handlers,
+	.get_wireless_stats = iwm_get_wireless_stats,
+};
+
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index cbaafa6..a4455ec 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -321,6 +321,8 @@
 
 	u32 monitormode;
 	u8 fw_ready;
+	u8 fn_init_required;
+	u8 fn_shutdown_required;
 };
 
 extern struct cmd_confirm_sleep confirm_sleep;
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index 8ff8ac9..fe8f0cb 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -86,6 +86,8 @@
 #define CMD_MESH_CONFIG_OLD			0x00a3
 #define CMD_MESH_CONFIG				0x00ac
 #define	CMD_SET_BOOT2_VER			0x00a5
+#define	CMD_FUNC_INIT				0x00a9
+#define	CMD_FUNC_SHUTDOWN			0x00aa
 #define CMD_802_11_BEACON_CTRL			0x00b0
 
 /* For the IEEE Power Save */
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 55864c1..a7e3fc1 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -61,26 +61,30 @@
 	int model;
 	const char *helper;
 	const char *firmware;
+	struct if_sdio_card *card;
 };
 
 static struct if_sdio_model if_sdio_models[] = {
 	{
 		/* 8385 */
-		.model = 0x04,
+		.model = IF_SDIO_MODEL_8385,
 		.helper = "sd8385_helper.bin",
 		.firmware = "sd8385.bin",
+		.card = NULL,
 	},
 	{
 		/* 8686 */
-		.model = 0x0B,
+		.model = IF_SDIO_MODEL_8686,
 		.helper = "sd8686_helper.bin",
 		.firmware = "sd8686.bin",
+		.card = NULL,
 	},
 	{
 		/* 8688 */
-		.model = 0x10,
+		.model = IF_SDIO_MODEL_8688,
 		.helper = "sd8688_helper.bin",
 		.firmware = "sd8688.bin",
+		.card = NULL,
 	},
 };
 
@@ -96,6 +100,7 @@
 
 	int			model;
 	unsigned long		ioport;
+	unsigned int		scratch_reg;
 
 	const char		*helper;
 	const char		*firmware;
@@ -107,25 +112,29 @@
 
 	struct workqueue_struct	*workqueue;
 	struct work_struct	packet_worker;
+
+	u8			rx_unit;
 };
 
 /********************************************************************/
 /* I/O                                                              */
 /********************************************************************/
 
+/*
+ *  For SD8385/SD8686, this function reads firmware status after
+ *  the image is downloaded, or reads RX packet length when
+ *  interrupt (with IF_SDIO_H_INT_UPLD bit set) is received.
+ *  For SD8688, this function reads firmware status only.
+ */
 static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err)
 {
-	int ret, reg;
+	int ret;
 	u16 scratch;
 
-	if (card->model == 0x04)
-		reg = IF_SDIO_SCRATCH_OLD;
-	else
-		reg = IF_SDIO_SCRATCH;
-
-	scratch = sdio_readb(card->func, reg, &ret);
+	scratch = sdio_readb(card->func, card->scratch_reg, &ret);
 	if (!ret)
-		scratch |= sdio_readb(card->func, reg + 1, &ret) << 8;
+		scratch |= sdio_readb(card->func, card->scratch_reg + 1,
+					&ret) << 8;
 
 	if (err)
 		*err = ret;
@@ -136,6 +145,46 @@
 	return scratch;
 }
 
+static u8 if_sdio_read_rx_unit(struct if_sdio_card *card)
+{
+	int ret;
+	u8 rx_unit;
+
+	rx_unit = sdio_readb(card->func, IF_SDIO_RX_UNIT, &ret);
+
+	if (ret)
+		rx_unit = 0;
+
+	return rx_unit;
+}
+
+static u16 if_sdio_read_rx_len(struct if_sdio_card *card, int *err)
+{
+	int ret;
+	u16 rx_len;
+
+	switch (card->model) {
+	case IF_SDIO_MODEL_8385:
+	case IF_SDIO_MODEL_8686:
+		rx_len = if_sdio_read_scratch(card, &ret);
+		break;
+	case IF_SDIO_MODEL_8688:
+	default: /* for newer chipsets */
+		rx_len = sdio_readb(card->func, IF_SDIO_RX_LEN, &ret);
+		if (!ret)
+			rx_len <<= card->rx_unit;
+		else
+			rx_len = 0xffff;	/* invalid length */
+
+		break;
+	}
+
+	if (err)
+		*err = ret;
+
+	return rx_len;
+}
+
 static int if_sdio_handle_cmd(struct if_sdio_card *card,
 		u8 *buffer, unsigned size)
 {
@@ -216,7 +265,7 @@
 
 	lbs_deb_enter(LBS_DEB_SDIO);
 
-	if (card->model == 0x04) {
+	if (card->model == IF_SDIO_MODEL_8385) {
 		event = sdio_readb(card->func, IF_SDIO_EVENT, &ret);
 		if (ret)
 			goto out;
@@ -254,7 +303,7 @@
 
 	lbs_deb_enter(LBS_DEB_SDIO);
 
-	size = if_sdio_read_scratch(card, &ret);
+	size = if_sdio_read_rx_len(card, &ret);
 	if (ret)
 		goto out;
 
@@ -497,7 +546,6 @@
 	ret = 0;
 
 release:
-	sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE);
 	sdio_release_host(card->func);
 	kfree(chunk_buffer);
 release_fw:
@@ -633,7 +681,6 @@
 	ret = 0;
 
 release:
-	sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE);
 	sdio_release_host(card->func);
 	kfree(chunk_buffer);
 release_fw:
@@ -662,6 +709,8 @@
 	if (ret)
 		goto out;
 
+	lbs_deb_sdio("firmware status = %#x\n", scratch);
+
 	if (scratch == IF_SDIO_FIRMWARE_OK) {
 		lbs_deb_sdio("firmware already loaded\n");
 		goto success;
@@ -676,6 +725,9 @@
 		goto out;
 
 success:
+	sdio_claim_host(card->func);
+	sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE);
+	sdio_release_host(card->func);
 	ret = 0;
 
 out:
@@ -829,10 +881,10 @@
 		if (sscanf(func->card->info[i],
 				"ID: %x", &model) == 1)
 			break;
-               if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) {
-                       model = 4;
-                       break;
-               }
+		if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) {
+			model = IF_SDIO_MODEL_8385;
+			break;
+		}
 	}
 
 	if (i == func->card->num_info) {
@@ -846,6 +898,20 @@
 
 	card->func = func;
 	card->model = model;
+
+	switch (card->model) {
+	case IF_SDIO_MODEL_8385:
+		card->scratch_reg = IF_SDIO_SCRATCH_OLD;
+		break;
+	case IF_SDIO_MODEL_8686:
+		card->scratch_reg = IF_SDIO_SCRATCH;
+		break;
+	case IF_SDIO_MODEL_8688:
+	default: /* for newer chipsets */
+		card->scratch_reg = IF_SDIO_FW_STATUS;
+		break;
+	}
+
 	spin_lock_init(&card->lock);
 	card->workqueue = create_workqueue("libertas_sdio");
 	INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
@@ -861,6 +927,8 @@
 		goto free;
 	}
 
+	if_sdio_models[i].card = card;
+
 	card->helper = if_sdio_models[i].helper;
 	card->firmware = if_sdio_models[i].firmware;
 
@@ -923,15 +991,32 @@
 
 	priv->fw_ready = 1;
 
+	sdio_claim_host(func);
+
+	/*
+	 * Get rx_unit if the chip is SD8688 or newer.
+	 * SD8385 & SD8686 do not have rx_unit.
+	 */
+	if ((card->model != IF_SDIO_MODEL_8385)
+			&& (card->model != IF_SDIO_MODEL_8686))
+		card->rx_unit = if_sdio_read_rx_unit(card);
+	else
+		card->rx_unit = 0;
+
 	/*
 	 * Enable interrupts now that everything is set up
 	 */
-	sdio_claim_host(func);
 	sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret);
 	sdio_release_host(func);
 	if (ret)
 		goto reclaim;
 
+	/*
+	 * FUNC_INIT is required for SD8688 WLAN/BT multiple functions
+	 */
+	priv->fn_init_required =
+		(card->model == IF_SDIO_MODEL_8688) ? 1 : 0;
+
 	ret = lbs_start_card(priv);
 	if (ret)
 		goto err_activate_card;
@@ -972,23 +1057,30 @@
 {
 	struct if_sdio_card *card;
 	struct if_sdio_packet *packet;
+	int ret;
 
 	lbs_deb_enter(LBS_DEB_SDIO);
 
 	card = sdio_get_drvdata(func);
 
+	lbs_stop_card(card->priv);
+
 	card->priv->surpriseremoved = 1;
 
 	lbs_deb_sdio("call remove card\n");
-	lbs_stop_card(card->priv);
 	lbs_remove_card(card->priv);
 
 	flush_workqueue(card->workqueue);
 	destroy_workqueue(card->workqueue);
 
 	sdio_claim_host(func);
+
+	/* Disable interrupts */
+	sdio_writeb(func, 0x00, IF_SDIO_H_INT_MASK, &ret);
+
 	sdio_release_irq(func);
 	sdio_disable_func(func);
+
 	sdio_release_host(func);
 
 	while (card->packets) {
@@ -1031,8 +1123,23 @@
 
 static void __exit if_sdio_exit_module(void)
 {
+	int i;
+	struct if_sdio_card *card;
+
 	lbs_deb_enter(LBS_DEB_SDIO);
 
+	for (i = 0; i < ARRAY_SIZE(if_sdio_models); i++) {
+		card = if_sdio_models[i].card;
+
+		/*
+		 * FUNC_SHUTDOWN is required for SD8688 WLAN/BT
+		 * multiple functions
+		 */
+		if (card && card->priv)
+			card->priv->fn_shutdown_required =
+				(card->model == IF_SDIO_MODEL_8688) ? 1 : 0;
+	}
+
 	sdio_unregister_driver(&if_sdio_driver);
 
 	lbs_deb_leave(LBS_DEB_SDIO);
diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h
index 37ada2c..60c9b2f 100644
--- a/drivers/net/wireless/libertas/if_sdio.h
+++ b/drivers/net/wireless/libertas/if_sdio.h
@@ -12,6 +12,10 @@
 #ifndef _LBS_IF_SDIO_H
 #define _LBS_IF_SDIO_H
 
+#define IF_SDIO_MODEL_8385	0x04
+#define IF_SDIO_MODEL_8686	0x0b
+#define IF_SDIO_MODEL_8688	0x10
+
 #define IF_SDIO_IOPORT		0x00
 
 #define IF_SDIO_H_INT_MASK	0x04
@@ -38,8 +42,12 @@
 
 #define IF_SDIO_SCRATCH		0x34
 #define IF_SDIO_SCRATCH_OLD	0x80fe
+#define IF_SDIO_FW_STATUS	0x40
 #define   IF_SDIO_FIRMWARE_OK	0xfedc
 
+#define IF_SDIO_RX_LEN		0x42
+#define IF_SDIO_RX_UNIT		0x43
+
 #define IF_SDIO_EVENT           0x80fc
 
 #define IF_SDIO_BLOCK_SIZE	256
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index dccd01f..5fa55fe 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -814,6 +814,13 @@
 	if (err)
 		goto out;
 
+	/* re-enable the card event interrupt */
+	spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG,
+			~IF_SPI_HICU_CARD_EVENT);
+
+	/* generate a card interrupt */
+	spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG, IF_SPI_CIC_HOST_EVENT);
+
 	spin_lock_irqsave(&priv->driver_lock, flags);
 	lbs_queue_event(priv, cause & 0xff);
 	spin_unlock_irqrestore(&priv->driver_lock, flags);
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 89575e4..a58a123 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -1002,9 +1002,17 @@
 {
 	int ret = -1;
 	s16 curlevel = 0, minlevel = 0, maxlevel = 0;
+	struct cmd_header cmd;
 
 	lbs_deb_enter(LBS_DEB_FW);
 
+	if (priv->fn_init_required) {
+		memset(&cmd, 0, sizeof(cmd));
+		if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
+				lbs_cmd_copyback, (unsigned long) &cmd))
+			lbs_pr_alert("CMD_FUNC_INIT command failed\n");
+	}
+
 	/* Read MAC address from firmware */
 	memset(priv->current_addr, 0xff, ETH_ALEN);
 	ret = lbs_update_hw_spec(priv);
@@ -1192,6 +1200,9 @@
 	priv->mesh_open = 0;
 	priv->infra_open = 0;
 
+	priv->fn_init_required = 0;
+	priv->fn_shutdown_required = 0;
+
 	/* Setup the OS Interface to our functions */
  	dev->netdev_ops = &lbs_netdev_ops;
 	dev->watchdog_timeo = 5 * HZ;
@@ -1373,11 +1384,20 @@
 	struct net_device *dev;
 	struct cmd_ctrl_node *cmdnode;
 	unsigned long flags;
+	struct cmd_header cmd;
 
 	lbs_deb_enter(LBS_DEB_MAIN);
 
 	if (!priv)
 		goto out;
+
+	if (priv->fn_shutdown_required) {
+		memset(&cmd, 0, sizeof(cmd));
+		if (__lbs_cmd(priv, CMD_FUNC_SHUTDOWN, &cmd, sizeof(cmd),
+				lbs_cmd_copyback, (unsigned long) &cmd))
+			lbs_pr_alert("CMD_FUNC_SHUTDOWN command failed\n");
+	}
+
 	dev = priv->dev;
 
 	netif_stop_queue(dev);
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 61a4ad7..574b8bb 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -291,6 +291,14 @@
 	bool ps_poll_pending;
 	struct dentry *debugfs;
 	struct dentry *debugfs_ps;
+
+	/*
+	 * Only radios in the same group can communicate together (the
+	 * channel has to match too). Each bit represents a group. A
+	 * radio can be in more then one group.
+	 */
+	u64 group;
+	struct dentry *debugfs_group;
 };
 
 
@@ -412,7 +420,8 @@
 
 		if (!data2->started || !data2->radio_enabled ||
 		    !hwsim_ps_rx_ok(data2, skb) ||
-		    data->channel->center_freq != data2->channel->center_freq)
+		    data->channel->center_freq != data2->channel->center_freq ||
+		    !(data->group & data2->group))
 			continue;
 
 		nskb = skb_copy(skb, GFP_ATOMIC);
@@ -720,6 +729,7 @@
 	spin_unlock_bh(&hwsim_radio_lock);
 
 	list_for_each_entry(data, &tmplist, list) {
+		debugfs_remove(data->debugfs_group);
 		debugfs_remove(data->debugfs_ps);
 		debugfs_remove(data->debugfs);
 		ieee80211_unregister_hw(data->hw);
@@ -872,6 +882,24 @@
 			"%llu\n");
 
 
+static int hwsim_fops_group_read(void *dat, u64 *val)
+{
+	struct mac80211_hwsim_data *data = dat;
+	*val = data->group;
+	return 0;
+}
+
+static int hwsim_fops_group_write(void *dat, u64 val)
+{
+	struct mac80211_hwsim_data *data = dat;
+	data->group = val;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_group,
+			hwsim_fops_group_read, hwsim_fops_group_write,
+			"%llx\n");
+
 static int __init init_mac80211_hwsim(void)
 {
 	int i, err = 0;
@@ -976,6 +1004,8 @@
 
 			hw->wiphy->bands[band] = sband;
 		}
+		/* By default all radios are belonging to the first group */
+		data->group = 1;
 
 		/* Work to be done prior to ieee80211_register_hw() */
 		switch (regtest) {
@@ -1100,6 +1130,9 @@
 		data->debugfs_ps = debugfs_create_file("ps", 0666,
 						       data->debugfs, data,
 						       &hwsim_fops_ps);
+		data->debugfs_group = debugfs_create_file("group", 0666,
+							data->debugfs, data,
+							&hwsim_fops_group);
 
 		setup_timer(&data->beacon_timer, mac80211_hwsim_beacon,
 			    (unsigned long) hw);
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
index 48d81d9..b618bd1 100644
--- a/drivers/net/wireless/p54/p54common.c
+++ b/drivers/net/wireless/p54/p54common.c
@@ -823,30 +823,30 @@
 	struct p54_tx_info *range;
 	unsigned long flags;
 
-	if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue)))
+	if (unlikely(!skb || !dev || skb_queue_empty(&priv->tx_queue)))
 		return;
 
-	/*
-	 * don't try to free an already unlinked skb
+	/* There used to be a check here to see if the SKB was on the
+	 * TX queue or not.  This can never happen because all SKBs we
+	 * see here successfully went through p54_assign_address()
+	 * which means the SKB is on the ->tx_queue.
 	 */
-	if (unlikely((!skb->next) || (!skb->prev)))
-		return;
 
 	spin_lock_irqsave(&priv->tx_queue.lock, flags);
 	info = IEEE80211_SKB_CB(skb);
 	range = (void *)info->rate_driver_data;
-	if (skb->prev != (struct sk_buff *)&priv->tx_queue) {
+	if (!skb_queue_is_first(&priv->tx_queue, skb)) {
 		struct ieee80211_tx_info *ni;
 		struct p54_tx_info *mr;
 
-		ni = IEEE80211_SKB_CB(skb->prev);
+		ni = IEEE80211_SKB_CB(skb_queue_prev(&priv->tx_queue, skb));
 		mr = (struct p54_tx_info *)ni->rate_driver_data;
 	}
-	if (skb->next != (struct sk_buff *)&priv->tx_queue) {
+	if (!skb_queue_is_last(&priv->tx_queue, skb)) {
 		struct ieee80211_tx_info *ni;
 		struct p54_tx_info *mr;
 
-		ni = IEEE80211_SKB_CB(skb->next);
+		ni = IEEE80211_SKB_CB(skb_queue_next(&priv->tx_queue, skb));
 		mr = (struct p54_tx_info *)ni->rate_driver_data;
 	}
 	__skb_unlink(skb, &priv->tx_queue);
@@ -864,15 +864,13 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->tx_queue.lock, flags);
-	entry = priv->tx_queue.next;
-	while (entry != (struct sk_buff *)&priv->tx_queue) {
+	skb_queue_walk(&priv->tx_queue, entry) {
 		struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
 
 		if (hdr->req_id == req_id) {
 			spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
 			return entry;
 		}
-		entry = entry->next;
 	}
 	spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
 	return NULL;
@@ -890,24 +888,22 @@
 	int count, idx;
 
 	spin_lock_irqsave(&priv->tx_queue.lock, flags);
-	entry = (struct sk_buff *) priv->tx_queue.next;
-	while (entry != (struct sk_buff *)&priv->tx_queue) {
+	skb_queue_walk(&priv->tx_queue, entry) {
 		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
 		struct p54_hdr *entry_hdr;
 		struct p54_tx_data *entry_data;
 		unsigned int pad = 0, frame_len;
 
 		range = (void *)info->rate_driver_data;
-		if (range->start_addr != addr) {
-			entry = entry->next;
+		if (range->start_addr != addr)
 			continue;
-		}
 
-		if (entry->next != (struct sk_buff *)&priv->tx_queue) {
+		if (!skb_queue_is_last(&priv->tx_queue, entry)) {
 			struct ieee80211_tx_info *ni;
 			struct p54_tx_info *mr;
 
-			ni = IEEE80211_SKB_CB(entry->next);
+			ni = IEEE80211_SKB_CB(skb_queue_next(&priv->tx_queue,
+							     entry));
 			mr = (struct p54_tx_info *)ni->rate_driver_data;
 		}
 
@@ -1168,23 +1164,21 @@
 		}
 	}
 
-	entry = priv->tx_queue.next;
-	while (left--) {
+	skb_queue_walk(&priv->tx_queue, entry) {
 		u32 hole_size;
 		info = IEEE80211_SKB_CB(entry);
 		range = (void *)info->rate_driver_data;
 		hole_size = range->start_addr - last_addr;
 		if (!target_skb && hole_size >= len) {
-			target_skb = entry->prev;
+			target_skb = skb_queue_prev(&priv->tx_queue, entry);
 			hole_size -= len;
 			target_addr = last_addr;
 		}
 		largest_hole = max(largest_hole, hole_size);
 		last_addr = range->end_addr;
-		entry = entry->next;
 	}
 	if (!target_skb && priv->rx_end - last_addr >= len) {
-		target_skb = priv->tx_queue.prev;
+		target_skb = skb_peek_tail(&priv->tx_queue);
 		largest_hole = max(largest_hole, priv->rx_end - last_addr - len);
 		if (!skb_queue_empty(&priv->tx_queue)) {
 			info = IEEE80211_SKB_CB(target_skb);
@@ -2090,7 +2084,6 @@
 static void p54_stop(struct ieee80211_hw *dev)
 {
 	struct p54_common *priv = dev->priv;
-	struct sk_buff *skb;
 
 	mutex_lock(&priv->conf_mutex);
 	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
@@ -2105,8 +2098,7 @@
 		p54_tx_cancel(dev, priv->cached_beacon);
 
 	priv->stop(dev);
-	while ((skb = skb_dequeue(&priv->tx_queue)))
-		kfree_skb(skb);
+	skb_queue_purge(&priv->tx_queue);
 	priv->cached_beacon = NULL;
 	priv->tsf_high32 = priv->tsf_low32 = 0;
 	mutex_unlock(&priv->conf_mutex);
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c
index 59a5e77..83116ba 100644
--- a/drivers/net/wireless/p54/p54spi.c
+++ b/drivers/net/wireless/p54/p54spi.c
@@ -96,7 +96,7 @@
 	spi_message_add_tail(&t[0], &m);
 
 	t[1].tx_buf = buf;
-	t[1].len = len;
+	t[1].len = len & ~1;
 	spi_message_add_tail(&t[1], &m);
 
 	if (len % 2) {
@@ -172,8 +172,6 @@
 		__le32 buffer = p54spi_read32(priv, reg);
 		if ((buffer & bits) == bits)
 			return 1;
-
-		msleep(0);
 	}
 	return 0;
 }
@@ -181,9 +179,6 @@
 static int p54spi_spi_write_dma(struct p54s_priv *priv, __le32 base,
 				const void *buf, size_t len)
 {
-	p54spi_write16(priv, SPI_ADRS_DMA_WRITE_CTRL,
-		       cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE));
-
 	if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL,
 			     cpu_to_le32(HOST_ALLOWED))) {
 		dev_err(&priv->spi->dev, "spi_write_dma not allowed "
@@ -191,6 +186,9 @@
 		return -EAGAIN;
 	}
 
+	p54spi_write16(priv, SPI_ADRS_DMA_WRITE_CTRL,
+		       cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE));
+
 	p54spi_write16(priv, SPI_ADRS_DMA_WRITE_LEN, cpu_to_le16(len));
 	p54spi_write32(priv, SPI_ADRS_DMA_WRITE_BASE, base);
 	p54spi_spi_write(priv, SPI_ADRS_DMA_DATA, buf, len);
@@ -327,7 +325,7 @@
 	p54spi_write32(priv, SPI_ADRS_HOST_INT_ACK, cpu_to_le32(val));
 }
 
-static void p54spi_wakeup(struct p54s_priv *priv)
+static int p54spi_wakeup(struct p54s_priv *priv)
 {
 	/* wake the chip */
 	p54spi_write32(priv, SPI_ADRS_ARM_INTERRUPTS,
@@ -337,13 +335,11 @@
 	if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS,
 			     cpu_to_le32(SPI_HOST_INT_READY))) {
 		dev_err(&priv->spi->dev, "INT_READY timeout\n");
-		goto out;
+		return -EBUSY;
 	}
 
 	p54spi_int_ack(priv, SPI_HOST_INT_READY);
-
-out:
-	return;
+	return 0;
 }
 
 static inline void p54spi_sleep(struct p54s_priv *priv)
@@ -375,31 +371,44 @@
 {
 	struct sk_buff *skb;
 	u16 len;
+	u16 rx_head[2];
+#define READAHEAD_SZ (sizeof(rx_head)-sizeof(u16))
 
-	p54spi_wakeup(priv);
+	if (p54spi_wakeup(priv) < 0)
+		return -EBUSY;
 
-	/* dummy read to flush SPI DMA controller bug */
-	p54spi_read16(priv, SPI_ADRS_GEN_PURP_1);
-
-	len = p54spi_read16(priv, SPI_ADRS_DMA_DATA);
+	/* Read data size and first data word in one SPI transaction
+	 * This is workaround for firmware/DMA bug,
+	 * when first data word gets lost under high load.
+	 */
+	p54spi_spi_read(priv, SPI_ADRS_DMA_DATA, rx_head, sizeof(rx_head));
+	len = rx_head[0];
 
 	if (len == 0) {
-		dev_err(&priv->spi->dev, "rx request of zero bytes");
+		p54spi_sleep(priv);
+		dev_err(&priv->spi->dev, "rx request of zero bytes\n");
 		return 0;
 	}
 
-
 	/* Firmware may insert up to 4 padding bytes after the lmac header,
 	 * but it does not amend the size of SPI data transfer.
 	 * Such packets has correct data size in header, thus referencing
 	 * past the end of allocated skb. Reserve extra 4 bytes for this case */
 	skb = dev_alloc_skb(len + 4);
 	if (!skb) {
+		p54spi_sleep(priv);
 		dev_err(&priv->spi->dev, "could not alloc skb");
-		return 0;
+		return -ENOMEM;
 	}
 
-	p54spi_spi_read(priv, SPI_ADRS_DMA_DATA, skb_put(skb, len), len);
+	if (len <= READAHEAD_SZ) {
+		memcpy(skb_put(skb, len), rx_head + 1, len);
+	} else {
+		memcpy(skb_put(skb, READAHEAD_SZ), rx_head + 1, READAHEAD_SZ);
+		p54spi_spi_read(priv, SPI_ADRS_DMA_DATA,
+				skb_put(skb, len - READAHEAD_SZ),
+				len - READAHEAD_SZ);
+	}
 	p54spi_sleep(priv);
 	/* Put additional bytes to compensate for the possible
 	 * alignment-caused truncation */
@@ -427,7 +436,8 @@
 	struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
 	int ret = 0;
 
-	p54spi_wakeup(priv);
+	if (p54spi_wakeup(priv) < 0)
+		return -EBUSY;
 
 	ret = p54spi_spi_write_dma(priv, hdr->req_id, skb->data, skb->len);
 	if (ret < 0)
@@ -436,16 +446,16 @@
 	if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS,
 			     cpu_to_le32(SPI_HOST_INT_WR_READY))) {
 		dev_err(&priv->spi->dev, "WR_READY timeout\n");
-		ret = -1;
+		ret = -EAGAIN;
 		goto out;
 	}
 
 	p54spi_int_ack(priv, SPI_HOST_INT_WR_READY);
-	p54spi_sleep(priv);
 
 	if (FREE_AFTER_TX(skb))
 		p54_free_skb(priv->hw, skb);
 out:
+	p54spi_sleep(priv);
 	return ret;
 }
 
@@ -515,8 +525,7 @@
 
 	mutex_lock(&priv->mutex);
 
-	if (priv->fw_state == FW_STATE_OFF &&
-	    priv->fw_state == FW_STATE_RESET)
+	if (priv->fw_state == FW_STATE_OFF)
 		goto out;
 
 	ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS);
@@ -543,11 +552,6 @@
 	}
 
 	ret = p54spi_wq_tx(priv);
-	if (ret < 0)
-		goto out;
-
-	ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS);
-
 out:
 	mutex_unlock(&priv->mutex);
 }
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 52fc647..c254fdf 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -2,7 +2,7 @@
  * Driver for RNDIS based wireless USB devices.
  *
  * Copyright (C) 2007 by Bjorge Dijkstra <bjd@jooz.net>
- * Copyright (C) 2008 by Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ * Copyright (C) 2008-2009 by Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
  *
  * 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
@@ -196,6 +196,18 @@
 	ndis_80211_priv_8021x_wep
 };
 
+enum ndis_80211_addkey_bits {
+	ndis_80211_addkey_8021x_auth = cpu_to_le32(1 << 28),
+	ndis_80211_addkey_set_init_recv_seq = cpu_to_le32(1 << 29),
+	ndis_80211_addkey_pairwise_key = cpu_to_le32(1 << 30),
+	ndis_80211_addkey_transmit_key = cpu_to_le32(1 << 31),
+};
+
+enum ndis_80211_addwep_bits {
+	ndis_80211_addwep_perclient_key = cpu_to_le32(1 << 30),
+	ndis_80211_addwep_transmit_key = cpu_to_le32(1 << 31),
+};
+
 struct ndis_80211_ssid {
 	__le32 length;
 	u8 essid[NDIS_802_11_LENGTH_SSID];
@@ -309,7 +321,6 @@
 #define CAP_MODE_80211B		2
 #define CAP_MODE_80211G		4
 #define CAP_MODE_MASK		7
-#define CAP_SUPPORT_TXPOWER	8
 
 #define WORK_LINK_UP		(1<<0)
 #define WORK_LINK_DOWN		(1<<1)
@@ -394,6 +405,7 @@
 	int  encr_tx_key_index;
 	char encr_keys[4][32];
 	int  encr_key_len[4];
+	char encr_key_wpa[4];
 	int  wpa_version;
 	int  wpa_keymgmt;
 	int  wpa_authalg;
@@ -945,7 +957,7 @@
 	if (priv->wpa_keymgmt == 0 ||
 		priv->wpa_keymgmt == IW_AUTH_KEY_MGMT_802_1X) {
 		for (i = 0; i < 4; i++) {
-			if (priv->encr_key_len[i] > 0)
+			if (priv->encr_key_len[i] > 0 && !priv->encr_key_wpa[i])
 				add_wep_key(usbdev, priv->encr_keys[i],
 						priv->encr_key_len[i], i);
 		}
@@ -999,7 +1011,7 @@
 	memcpy(&ndis_key.material, key, key_len);
 
 	if (index == priv->encr_tx_key_index) {
-		ndis_key.index |= cpu_to_le32(1 << 31);
+		ndis_key.index |= ndis_80211_addwep_transmit_key;
 		ret = set_encr_mode(usbdev, IW_AUTH_CIPHER_WEP104,
 						IW_AUTH_CIPHER_NONE);
 		if (ret)
@@ -1016,12 +1028,81 @@
 	}
 
 	priv->encr_key_len[index] = key_len;
+	priv->encr_key_wpa[index] = 0;
 	memcpy(&priv->encr_keys[index], key, key_len);
 
 	return 0;
 }
 
 
+static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
+			int index, const struct sockaddr *addr,
+			const u8 *rx_seq, int alg, int flags)
+{
+	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+	struct ndis_80211_key ndis_key;
+	int ret;
+
+	if (index < 0 || index >= 4)
+		return -EINVAL;
+	if (key_len > sizeof(ndis_key.material) || key_len < 0)
+		return -EINVAL;
+	if ((flags & ndis_80211_addkey_set_init_recv_seq) && !rx_seq)
+		return -EINVAL;
+	if ((flags & ndis_80211_addkey_pairwise_key) && !addr)
+		return -EINVAL;
+
+	devdbg(usbdev, "add_wpa_key(%i): flags:%i%i%i", index,
+			!!(flags & ndis_80211_addkey_transmit_key),
+			!!(flags & ndis_80211_addkey_pairwise_key),
+			!!(flags & ndis_80211_addkey_set_init_recv_seq));
+
+	memset(&ndis_key, 0, sizeof(ndis_key));
+
+	ndis_key.size = cpu_to_le32(sizeof(ndis_key) -
+				sizeof(ndis_key.material) + key_len);
+	ndis_key.length = cpu_to_le32(key_len);
+	ndis_key.index = cpu_to_le32(index) | flags;
+
+	if (alg == IW_ENCODE_ALG_TKIP && key_len == 32) {
+		/* wpa_supplicant gives us the Michael MIC RX/TX keys in
+		 * different order than NDIS spec, so swap the order here. */
+		memcpy(ndis_key.material, key, 16);
+		memcpy(ndis_key.material + 16, key + 24, 8);
+		memcpy(ndis_key.material + 24, key + 16, 8);
+	} else
+		memcpy(ndis_key.material, key, key_len);
+
+	if (flags & ndis_80211_addkey_set_init_recv_seq)
+		memcpy(ndis_key.rsc, rx_seq, 6);
+
+	if (flags & ndis_80211_addkey_pairwise_key) {
+		/* pairwise key */
+		memcpy(ndis_key.bssid, addr->sa_data, ETH_ALEN);
+	} else {
+		/* group key */
+		if (priv->infra_mode == ndis_80211_infra_adhoc)
+			memset(ndis_key.bssid, 0xff, ETH_ALEN);
+		else
+			get_bssid(usbdev, ndis_key.bssid);
+	}
+
+	ret = rndis_set_oid(usbdev, OID_802_11_ADD_KEY, &ndis_key,
+					le32_to_cpu(ndis_key.size));
+	devdbg(usbdev, "add_wpa_key: OID_802_11_ADD_KEY -> %08X", ret);
+	if (ret != 0)
+		return ret;
+
+	priv->encr_key_len[index] = key_len;
+	priv->encr_key_wpa[index] = 1;
+
+	if (flags & ndis_80211_addkey_transmit_key)
+		priv->encr_tx_key_index = index;
+
+	return 0;
+}
+
+
 /* remove_key is for both wep and wpa */
 static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN])
 {
@@ -1034,6 +1115,7 @@
 		return 0;
 
 	priv->encr_key_len[index] = 0;
+	priv->encr_key_wpa[index] = 0;
 	memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index]));
 
 	if (priv->wpa_cipher_pair == IW_AUTH_CIPHER_TKIP ||
@@ -1045,7 +1127,8 @@
 		if (bssid) {
 			/* pairwise key */
 			if (memcmp(bssid, ffff_bssid, ETH_ALEN) != 0)
-				remove_key.index |= cpu_to_le32(1 << 30);
+				remove_key.index |=
+					ndis_80211_addkey_pairwise_key;
 			memcpy(remove_key.bssid, bssid,
 					sizeof(remove_key.bssid));
 		} else
@@ -1590,9 +1673,7 @@
 	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
 	struct usbnet *usbdev = netdev_priv(dev);
 	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
-	struct ndis_80211_key ndis_key;
-	int keyidx, ret;
-	u8 *addr;
+	int keyidx, flags;
 
 	keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX;
 
@@ -1615,58 +1696,16 @@
 	    ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0)
 		return remove_key(usbdev, keyidx, NULL);
 
-	if (ext->key_len > sizeof(ndis_key.material))
-		return -1;
-
-	memset(&ndis_key, 0, sizeof(ndis_key));
-
-	ndis_key.size = cpu_to_le32(sizeof(ndis_key) -
-				sizeof(ndis_key.material) + ext->key_len);
-	ndis_key.length = cpu_to_le32(ext->key_len);
-	ndis_key.index = cpu_to_le32(keyidx);
-
-	if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
-		memcpy(ndis_key.rsc, ext->rx_seq, 6);
-		ndis_key.index |= cpu_to_le32(1 << 29);
-	}
-
-	addr = ext->addr.sa_data;
-	if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
-		/* group key */
-		if (priv->infra_mode == ndis_80211_infra_adhoc)
-			memset(ndis_key.bssid, 0xff, ETH_ALEN);
-		else
-			get_bssid(usbdev, ndis_key.bssid);
-	} else {
-		/* pairwise key */
-		ndis_key.index |= cpu_to_le32(1 << 30);
-		memcpy(ndis_key.bssid, addr, ETH_ALEN);
-	}
-
+	flags = 0;
+	if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
+		flags |= ndis_80211_addkey_set_init_recv_seq;
+	if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY))
+		flags |= ndis_80211_addkey_pairwise_key;
 	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
-		ndis_key.index |= cpu_to_le32(1 << 31);
+		flags |= ndis_80211_addkey_transmit_key;
 
-	if (ext->alg == IW_ENCODE_ALG_TKIP && ext->key_len == 32) {
-		/* wpa_supplicant gives us the Michael MIC RX/TX keys in
-		 * different order than NDIS spec, so swap the order here. */
-		memcpy(ndis_key.material, ext->key, 16);
-		memcpy(ndis_key.material + 16, ext->key + 24, 8);
-		memcpy(ndis_key.material + 24, ext->key + 16, 8);
-	} else
-		memcpy(ndis_key.material, ext->key, ext->key_len);
-
-	ret = rndis_set_oid(usbdev, OID_802_11_ADD_KEY, &ndis_key,
-					le32_to_cpu(ndis_key.size));
-	devdbg(usbdev, "SIOCSIWENCODEEXT: OID_802_11_ADD_KEY -> %08X", ret);
-	if (ret != 0)
-		return ret;
-
-	priv->encr_key_len[keyidx] = ext->key_len;
-	memcpy(&priv->encr_keys[keyidx], ndis_key.material, ext->key_len);
-	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
-		priv->encr_tx_key_index = keyidx;
-
-	return 0;
+	return add_wpa_key(usbdev, ext->key, ext->key_len, keyidx, &ext->addr,
+				ext->rx_seq, ext->alg, flags);
 }
 
 
@@ -1849,18 +1888,10 @@
 	struct usbnet *usbdev = netdev_priv(dev);
 	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
 	__le32 tx_power;
-	int ret = 0, len;
 
 	if (priv->radio_on) {
-		if (priv->caps & CAP_SUPPORT_TXPOWER) {
-			len = sizeof(tx_power);
-			ret = rndis_query_oid(usbdev, OID_802_11_TX_POWER_LEVEL,
-							&tx_power, &len);
-			if (ret != 0)
-				return ret;
-		} else
-			/* fake incase not supported */
-			tx_power = cpu_to_le32(get_bcm4320_power(priv));
+		/* fake since changing tx_power (by userlevel) not supported */
+		tx_power = cpu_to_le32(get_bcm4320_power(priv));
 
 		wrqu->txpower.flags = IW_TXPOW_MWATT;
 		wrqu->txpower.value = le32_to_cpu(tx_power);
@@ -1873,7 +1904,7 @@
 
 	devdbg(usbdev, "SIOCGIWTXPOW: %d", wrqu->txpower.value);
 
-	return ret;
+	return 0;
 }
 
 
@@ -1883,7 +1914,6 @@
 	struct usbnet *usbdev = netdev_priv(dev);
 	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
 	__le32 tx_power = 0;
-	int ret = 0;
 
 	if (!wrqu->txpower.disabled) {
 		if (wrqu->txpower.flags == IW_TXPOW_MWATT)
@@ -1906,22 +1936,10 @@
 	devdbg(usbdev, "SIOCSIWTXPOW: %d", le32_to_cpu(tx_power));
 
 	if (le32_to_cpu(tx_power) != 0) {
-		if (priv->caps & CAP_SUPPORT_TXPOWER) {
-			/* turn radio on first */
-			if (!priv->radio_on)
-				disassociate(usbdev, 1);
-
-			ret = rndis_set_oid(usbdev, OID_802_11_TX_POWER_LEVEL,
-						&tx_power, sizeof(tx_power));
-			if (ret != 0)
-				ret = -EOPNOTSUPP;
-			return ret;
-		} else {
-			/* txpower unsupported, just turn radio on */
-			if (!priv->radio_on)
-				return disassociate(usbdev, 1);
-			return 0; /* all ready on */
-		}
+		/* txpower unsupported, just turn radio on */
+		if (!priv->radio_on)
+			return disassociate(usbdev, 1);
+		return 0; /* all ready on */
 	}
 
 	/* tx_power == 0, turn off radio */
@@ -2130,16 +2148,8 @@
 		__le32	items[8];
 	} networks_supported;
 	int len, retval, i, n;
-	__le32 tx_power;
 	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
 
-	/* determine if supports setting txpower */
-	len = sizeof(tx_power);
-	retval = rndis_query_oid(usbdev, OID_802_11_TX_POWER_LEVEL, &tx_power,
-									&len);
-	if (retval == 0 && le32_to_cpu(tx_power) != 0xFF)
-		priv->caps |= CAP_SUPPORT_TXPOWER;
-
 	/* determine supported modes */
 	len = sizeof(networks_supported);
 	retval = rndis_query_oid(usbdev, OID_802_11_NETWORK_TYPES_SUPPORTED,
@@ -2275,7 +2285,17 @@
 }
 
 
-static int bcm4320_early_init(struct usbnet *usbdev)
+static int bcm4320a_early_init(struct usbnet *usbdev)
+{
+	/* bcm4320a doesn't handle configuration parameters well. Try
+	 * set any and you get partially zeroed mac and broken device.
+	 */
+
+	return 0;
+}
+
+
+static int bcm4320b_early_init(struct usbnet *usbdev)
 {
 	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
 	char buf[8];
@@ -2515,7 +2535,7 @@
 	.rx_fixup =	rndis_rx_fixup,
 	.tx_fixup =	rndis_tx_fixup,
 	.reset =	rndis_wext_reset,
-	.early_init =	bcm4320_early_init,
+	.early_init =	bcm4320b_early_init,
 	.link_change =	rndis_wext_link_change,
 };
 
@@ -2528,7 +2548,7 @@
 	.rx_fixup =	rndis_rx_fixup,
 	.tx_fixup =	rndis_tx_fixup,
 	.reset =	rndis_wext_reset,
-	.early_init =	bcm4320_early_init,
+	.early_init =	bcm4320a_early_init,
 	.link_change =	rndis_wext_link_change,
 };
 
@@ -2541,7 +2561,7 @@
 	.rx_fixup =	rndis_rx_fixup,
 	.tx_fixup =	rndis_tx_fixup,
 	.reset =	rndis_wext_reset,
-	.early_init =	bcm4320_early_init,
+	.early_init =	bcm4320a_early_init,
 	.link_change =	rndis_wext_link_change,
 };
 
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 6f39ba6..0197531 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -335,10 +335,11 @@
 	preamble_mask = erp->short_preamble << 3;
 
 	rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
-	rt2x00_set_field32(&reg, TXCSR1_ACK_TIMEOUT,
-			   erp->ack_timeout);
+	rt2x00_set_field32(&reg, TXCSR1_ACK_TIMEOUT, erp->ack_timeout);
 	rt2x00_set_field32(&reg, TXCSR1_ACK_CONSUME_TIME,
 			   erp->ack_consume_time);
+	rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
+	rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
 	rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
 
 	rt2x00pci_register_read(rt2x00dev, ARCSR2, &reg);
@@ -371,6 +372,11 @@
 	rt2x00_set_field32(&reg, CSR11_SLOT_TIME, erp->slot_time);
 	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
 
+	rt2x00pci_register_read(rt2x00dev, CSR12, &reg);
+	rt2x00_set_field32(&reg, CSR12_BEACON_INTERVAL, erp->beacon_int * 16);
+	rt2x00_set_field32(&reg, CSR12_CFP_MAX_DURATION, erp->beacon_int * 16);
+	rt2x00pci_register_write(rt2x00dev, CSR12, reg);
+
 	rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
 	rt2x00_set_field32(&reg, CSR18_SIFS, erp->sifs);
 	rt2x00_set_field32(&reg, CSR18_PIFS, erp->pifs);
@@ -503,24 +509,6 @@
 	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
 }
 
-static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev,
-				      struct rt2x00lib_conf *libconf)
-{
-	u32 reg;
-
-	rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
-	rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
-	rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
-	rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
-
-	rt2x00pci_register_read(rt2x00dev, CSR12, &reg);
-	rt2x00_set_field32(&reg, CSR12_BEACON_INTERVAL,
-			   libconf->conf->beacon_int * 16);
-	rt2x00_set_field32(&reg, CSR12_CFP_MAX_DURATION,
-			   libconf->conf->beacon_int * 16);
-	rt2x00pci_register_write(rt2x00dev, CSR12, reg);
-}
-
 static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev,
 				struct rt2x00lib_conf *libconf)
 {
@@ -558,8 +546,6 @@
 					 libconf->conf->power_level);
 	if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
 		rt2400pci_config_retry_limit(rt2x00dev, libconf);
-	if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
-		rt2400pci_config_duration(rt2x00dev, libconf);
 	if (flags & IEEE80211_CONF_CHANGE_PS)
 		rt2400pci_config_ps(rt2x00dev, libconf);
 }
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 906960f..f95cb64 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -341,10 +341,11 @@
 	preamble_mask = erp->short_preamble << 3;
 
 	rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
-	rt2x00_set_field32(&reg, TXCSR1_ACK_TIMEOUT,
-			   erp->ack_timeout);
+	rt2x00_set_field32(&reg, TXCSR1_ACK_TIMEOUT, erp->ack_timeout);
 	rt2x00_set_field32(&reg, TXCSR1_ACK_CONSUME_TIME,
 			   erp->ack_consume_time);
+	rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
+	rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
 	rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
 
 	rt2x00pci_register_read(rt2x00dev, ARCSR2, &reg);
@@ -377,6 +378,11 @@
 	rt2x00_set_field32(&reg, CSR11_SLOT_TIME, erp->slot_time);
 	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
 
+	rt2x00pci_register_read(rt2x00dev, CSR12, &reg);
+	rt2x00_set_field32(&reg, CSR12_BEACON_INTERVAL, erp->beacon_int * 16);
+	rt2x00_set_field32(&reg, CSR12_CFP_MAX_DURATION, erp->beacon_int * 16);
+	rt2x00pci_register_write(rt2x00dev, CSR12, reg);
+
 	rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
 	rt2x00_set_field32(&reg, CSR18_SIFS, erp->sifs);
 	rt2x00_set_field32(&reg, CSR18_PIFS, erp->pifs);
@@ -552,24 +558,6 @@
 	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
 }
 
-static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev,
-				      struct rt2x00lib_conf *libconf)
-{
-	u32 reg;
-
-	rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
-	rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
-	rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
-	rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
-
-	rt2x00pci_register_read(rt2x00dev, CSR12, &reg);
-	rt2x00_set_field32(&reg, CSR12_BEACON_INTERVAL,
-			   libconf->conf->beacon_int * 16);
-	rt2x00_set_field32(&reg, CSR12_CFP_MAX_DURATION,
-			   libconf->conf->beacon_int * 16);
-	rt2x00pci_register_write(rt2x00dev, CSR12, reg);
-}
-
 static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev,
 				struct rt2x00lib_conf *libconf)
 {
@@ -609,8 +597,6 @@
 					 libconf->conf->power_level);
 	if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
 		rt2500pci_config_retry_limit(rt2x00dev, libconf);
-	if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
-		rt2500pci_config_duration(rt2x00dev, libconf);
 	if (flags & IEEE80211_CONF_CHANGE_PS)
 		rt2500pci_config_ps(rt2x00dev, libconf);
 }
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 1debb88..69f966f 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -503,6 +503,10 @@
 
 	rt2500usb_register_write(rt2x00dev, TXRX_CSR11, erp->basic_rates);
 
+	rt2500usb_register_read(rt2x00dev, TXRX_CSR18, &reg);
+	rt2x00_set_field16(&reg, TXRX_CSR18_INTERVAL, erp->beacon_int * 4);
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg);
+
 	rt2500usb_register_write(rt2x00dev, MAC_CSR10, erp->slot_time);
 	rt2500usb_register_write(rt2x00dev, MAC_CSR11, erp->sifs);
 	rt2500usb_register_write(rt2x00dev, MAC_CSR12, erp->eifs);
@@ -632,17 +636,6 @@
 	rt2500usb_rf_write(rt2x00dev, 3, rf3);
 }
 
-static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev,
-				      struct rt2x00lib_conf *libconf)
-{
-	u16 reg;
-
-	rt2500usb_register_read(rt2x00dev, TXRX_CSR18, &reg);
-	rt2x00_set_field16(&reg, TXRX_CSR18_INTERVAL,
-			   libconf->conf->beacon_int * 4);
-	rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg);
-}
-
 static void rt2500usb_config_ps(struct rt2x00_dev *rt2x00dev,
 				struct rt2x00lib_conf *libconf)
 {
@@ -680,8 +673,6 @@
 	    !(flags & IEEE80211_CONF_CHANGE_CHANNEL))
 		rt2500usb_config_txpower(rt2x00dev,
 					 libconf->conf->power_level);
-	if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
-		rt2500usb_config_duration(rt2x00dev, libconf);
 	if (flags & IEEE80211_CONF_CHANGE_PS)
 		rt2500usb_config_ps(rt2x00dev, libconf);
 }
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 257bfb5..142ad34 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -616,6 +616,11 @@
 	rt2x00_set_field32(&reg, XIFS_TIME_CFG_EIFS, erp->eifs);
 	rt2x00_set_field32(&reg, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1);
 	rt2x00usb_register_write(rt2x00dev, XIFS_TIME_CFG, reg);
+
+	rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+	rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_INTERVAL,
+			   erp->beacon_int * 16);
+	rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg);
 }
 
 static void rt2800usb_config_ant(struct rt2x00_dev *rt2x00dev,
@@ -955,17 +960,6 @@
 	rt2x00usb_register_write(rt2x00dev, TX_RTY_CFG, reg);
 }
 
-static void rt2800usb_config_duration(struct rt2x00_dev *rt2x00dev,
-				      struct rt2x00lib_conf *libconf)
-{
-	u32 reg;
-
-	rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
-	rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_INTERVAL,
-			   libconf->conf->beacon_int * 16);
-	rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-}
-
 static void rt2800usb_config_ps(struct rt2x00_dev *rt2x00dev,
 				struct rt2x00lib_conf *libconf)
 {
@@ -1010,8 +1004,6 @@
 		rt2800usb_config_txpower(rt2x00dev, libconf->conf->power_level);
 	if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
 		rt2800usb_config_retry_limit(rt2x00dev, libconf);
-	if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
-		rt2800usb_config_duration(rt2x00dev, libconf);
 	if (flags & IEEE80211_CONF_CHANGE_PS)
 		rt2800usb_config_ps(rt2x00dev, libconf);
 }
@@ -2881,8 +2873,6 @@
  * rt2800usb module information.
  */
 static struct usb_device_id rt2800usb_device_table[] = {
-	/* ??? */
-	{ USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) },
 	/* Abocom */
 	{ USB_DEVICE(0x07b8, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
 	{ USB_DEVICE(0x07b8, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -2912,6 +2902,7 @@
 	{ USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) },
 	{ USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) },
 	{ USB_DEVICE(0x050d, 0x815c), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x050d, 0x825a), USB_DEVICE_DATA(&rt2800usb_ops) },
 	/* Buffalo */
 	{ USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) },
 	{ USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -3026,6 +3017,10 @@
 	{ USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) },
 	/* Sparklan */
 	{ USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) },
+	/* Sweex */
+	{ USB_DEVICE(0x177f, 0x0153), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x177f, 0x0313), USB_DEVICE_DATA(&rt2800usb_ops) },
 	/* U-Media*/
 	{ USB_DEVICE(0x157e, 0x300e), USB_DEVICE_DATA(&rt2800usb_ops) },
 	/* ZCOM */
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 419b1b9..2b64a61 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -417,6 +417,8 @@
 	short pifs;
 	short difs;
 	short eifs;
+
+	u16 beacon_int;
 };
 
 /*
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 863e399..c5bbf0b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -106,6 +106,7 @@
 	}
 
 	erp.basic_rates = bss_conf->basic_rates;
+	erp.beacon_int = bss_conf->beacon_int;
 
 	rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp);
 }
diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c
index 57ab42c..bc4e81e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00crypto.c
+++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c
@@ -33,7 +33,7 @@
 {
 	switch (key->alg) {
 	case ALG_WEP:
-		if (key->keylen == LEN_WEP40)
+		if (key->keylen == WLAN_KEY_LEN_WEP40)
 			return CIPHER_WEP64;
 		else
 			return CIPHER_WEP128;
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index 07d378e..7b3ee8c 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -138,7 +138,7 @@
 
 	if (cipher == CIPHER_TKIP_NO_MIC)
 		cipher = CIPHER_TKIP;
-	if (cipher == CIPHER_NONE || cipher > CIPHER_MAX)
+	if (cipher == CIPHER_NONE || cipher >= CIPHER_MAX)
 		return;
 
 	/* Remove CIPHER_NONE index */
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index f227084..57813e7 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -260,7 +260,8 @@
 	 * Update TX statistics.
 	 */
 	rt2x00dev->link.qual.tx_success +=
-	    test_bit(TXDONE_SUCCESS, &txdesc->flags);
+	    test_bit(TXDONE_SUCCESS, &txdesc->flags) ||
+	    test_bit(TXDONE_UNKNOWN, &txdesc->flags);
 	rt2x00dev->link.qual.tx_failed +=
 	    test_bit(TXDONE_FAILURE, &txdesc->flags);
 
@@ -278,14 +279,16 @@
 	tx_info->status.rates[1].idx = -1; /* terminate */
 
 	if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
-		if (test_bit(TXDONE_SUCCESS, &txdesc->flags))
+		if (test_bit(TXDONE_SUCCESS, &txdesc->flags) ||
+				test_bit(TXDONE_UNKNOWN, &txdesc->flags))
 			tx_info->flags |= IEEE80211_TX_STAT_ACK;
 		else if (test_bit(TXDONE_FAILURE, &txdesc->flags))
 			rt2x00dev->low_level_stats.dot11ACKFailureCount++;
 	}
 
 	if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
-		if (test_bit(TXDONE_SUCCESS, &txdesc->flags))
+		if (test_bit(TXDONE_SUCCESS, &txdesc->flags) ||
+				test_bit(TXDONE_UNKNOWN, &txdesc->flags))
 			rt2x00dev->low_level_stats.dot11RTSSuccessCount++;
 		else if (test_bit(TXDONE_FAILURE, &txdesc->flags))
 			rt2x00dev->low_level_stats.dot11RTSFailureCount++;
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index cb521ee..a8bf5c4 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -603,15 +603,22 @@
 
 	rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout);
+	rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
 	rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
 
 	rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_ENABLE, 1);
 	rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
 			   !!erp->short_preamble);
 	rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
 
 	rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates);
 
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL,
+			   erp->beacon_int * 16);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+
 	rt2x00pci_register_read(rt2x00dev, MAC_CSR9, &reg);
 	rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, erp->slot_time);
 	rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg);
@@ -938,25 +945,6 @@
 	rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
 }
 
-static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev,
-				    struct rt2x00lib_conf *libconf)
-{
-	u32 reg;
-
-	rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
-	rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
-	rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
-
-	rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
-	rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_ENABLE, 1);
-	rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
-
-	rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
-	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL,
-			   libconf->conf->beacon_int * 16);
-	rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
-}
-
 static void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev,
 				struct rt2x00lib_conf *libconf)
 {
@@ -1016,8 +1004,6 @@
 		rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level);
 	if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
 		rt61pci_config_retry_limit(rt2x00dev, libconf);
-	if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
-		rt61pci_config_duration(rt2x00dev, libconf);
 	if (flags & IEEE80211_CONF_CHANGE_PS)
 		rt61pci_config_ps(rt2x00dev, libconf);
 }
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 270dd4e..211a3d6 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -566,15 +566,22 @@
 
 	rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout);
+	rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
 	rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
 
 	rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_ENABLE, 1);
 	rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
 			   !!erp->short_preamble);
 	rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg);
 
 	rt2x00usb_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates);
 
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL,
+			   erp->beacon_int * 16);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+
 	rt2x00usb_register_read(rt2x00dev, MAC_CSR9, &reg);
 	rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, erp->slot_time);
 	rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg);
@@ -834,25 +841,6 @@
 	rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg);
 }
 
-static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev,
-				    struct rt2x00lib_conf *libconf)
-{
-	u32 reg;
-
-	rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
-	rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
-	rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
-
-	rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
-	rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_ENABLE, 1);
-	rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg);
-
-	rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
-	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL,
-			   libconf->conf->beacon_int * 16);
-	rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
-}
-
 static void rt73usb_config_ps(struct rt2x00_dev *rt2x00dev,
 				struct rt2x00lib_conf *libconf)
 {
@@ -906,8 +894,6 @@
 		rt73usb_config_txpower(rt2x00dev, libconf->conf->power_level);
 	if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
 		rt73usb_config_retry_limit(rt2x00dev, libconf);
-	if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
-		rt73usb_config_duration(rt2x00dev, libconf);
 	if (flags & IEEE80211_CONF_CHANGE_PS)
 		rt73usb_config_ps(rt2x00dev, libconf);
 }
diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
index 6499ccc..3f22cc0 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
@@ -321,12 +321,7 @@
 	unsigned long f;
 
 	spin_lock_irqsave(&priv->rx_queue.lock, f);
-	if (skb->next)
-		__skb_unlink(skb, &priv->rx_queue);
-	else {
-		spin_unlock_irqrestore(&priv->rx_queue.lock, f);
-		return;
-	}
+	__skb_unlink(skb, &priv->rx_queue);
 	spin_unlock_irqrestore(&priv->rx_queue.lock, f);
 	skb_put(skb, urb->actual_length);
 
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index f952046..b7b0c46 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -2509,7 +2509,7 @@
 	 *  netdev_priv(dev) Already holds a pointer to our struct strip
 	 */
 
-	*(MetricomAddress *) & dev->broadcast = broadcast_address;
+	*(MetricomAddress *)dev->broadcast = broadcast_address;
 	dev->dev_addr[0] = 0;
 	dev->addr_len = sizeof(MetricomAddress);
 
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index 3ab3eb9..25d27b6 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -2869,10 +2869,6 @@
 		if (lp->tx_n_in_use == (NTXBLOCKS - 1))
 			return 1;
 	}
-#ifdef DEBUG_TX_ERROR
-	if (skb->next)
-		printk(KERN_INFO "skb has next\n");
-#endif
 
 	/* Do we need some padding? */
 	/* Note : on wireless the propagation time is in the order of 1us,
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index e55b339..1a90d69 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -3107,11 +3107,6 @@
        * so the Tx buffer is now free */
     }
 
-#ifdef DEBUG_TX_ERROR
-	if (skb->next)
-		printk(KERN_INFO "skb has next\n");
-#endif
-
 	/* Check if we need some padding */
 	/* Note : on wireless the propagation time is in the order of 1us,
 	 * and we don't have the Ethernet specific requirement of beeing
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 6bdb170..40b07b9 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -420,9 +420,9 @@
 	if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
 		cs->control |= ZD_CS_NEED_RANDOM_BACKOFF;
 
-	/* Multicast */
-	if (is_multicast_ether_addr(header->addr1))
-		cs->control |= ZD_CS_MULTICAST;
+	/* No ACK expected (multicast, etc.) */
+	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
+		cs->control |= ZD_CS_NO_ACK;
 
 	/* PS-POLL */
 	if (ieee80211_is_pspoll(header->frame_control))
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index 4c05d3e..7c27591 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -87,7 +87,7 @@
 
 /* zd_ctrlset control field */
 #define ZD_CS_NEED_RANDOM_BACKOFF	0x01
-#define ZD_CS_MULTICAST			0x02
+#define ZD_CS_NO_ACK			0x02
 
 #define ZD_CS_FRAME_TYPE_MASK		0x0c
 #define ZD_CS_DATA_FRAME		0x00
diff --git a/drivers/staging/agnx/pci.c b/drivers/staging/agnx/pci.c
index 25c0ffd..43b3fe3 100644
--- a/drivers/staging/agnx/pci.c
+++ b/drivers/staging/agnx/pci.c
@@ -303,14 +303,18 @@
 	return 0;
 }
 
-static int agnx_config_interface(struct ieee80211_hw *dev,
-				 struct ieee80211_vif *vif,
-				 struct ieee80211_if_conf *conf)
+static void agnx_bss_info_changed(struct ieee80211_hw *dev,
+				  struct ieee80211_vif *vif,
+				  struct ieee80211_bss_conf *conf,
+				  u32 changed)
 {
 	struct agnx_priv *priv = dev->priv;
 	void __iomem *ctl = priv->ctl;
 	AGNX_TRACE;
 
+	if (!(changed & BSS_CHANGED_BSSID))
+		return;
+
 	spin_lock(&priv->lock);
 
 	if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) {
@@ -323,8 +327,7 @@
 		agnx_write32(ctl, AGNX_BM_MTSM, 0xff & ~0x1);
 	}
 	spin_unlock(&priv->lock);
-	return 0;
-} /* agnx_config_interface */
+} /* agnx_bss_info_changed */
 
 
 static void agnx_configure_filter(struct ieee80211_hw *dev,
@@ -422,7 +425,7 @@
 	.add_interface		= agnx_add_interface,
 	.remove_interface	= agnx_remove_interface,
 	.config			= agnx_config,
-	.config_interface	= agnx_config_interface,
+	.bss_info_changed	= agnx_bss_info_changed,
 	.configure_filter	= agnx_configure_filter,
 	.get_stats		= agnx_get_stats,
 	.get_tx_stats		= agnx_get_tx_stats,
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 05c29c0..34de8b2 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -493,6 +493,7 @@
 /* Mesh flags */
 #define MESH_FLAGS_AE_A4 	0x1
 #define MESH_FLAGS_AE_A5_A6	0x2
+#define MESH_FLAGS_AE		0x3
 #define MESH_FLAGS_PS_DEEP	0x4
 
 /**
@@ -1085,6 +1086,14 @@
 	WLAN_ACTION_SPCT_CHL_SWITCH = 4,
 };
 
+/* Security key length */
+enum ieee80211_key_len {
+	WLAN_KEY_LEN_WEP40 = 5,
+	WLAN_KEY_LEN_WEP104 = 13,
+	WLAN_KEY_LEN_CCMP = 16,
+	WLAN_KEY_LEN_TKIP = 32,
+};
+
 /*
  * IEEE 802.11-2007 7.3.2.9 Country information element
  *
diff --git a/include/linux/mISDNdsp.h b/include/linux/mISDNdsp.h
index 6b71d2d..41d1eeb 100644
--- a/include/linux/mISDNdsp.h
+++ b/include/linux/mISDNdsp.h
@@ -12,7 +12,8 @@
 	void	*(*new)(const char *arg);
 	void	(*free)(void *p);
 	void	(*process_tx)(void *p, unsigned char *data, int len);
-	void	(*process_rx)(void *p, unsigned char *data, int len);
+	void	(*process_rx)(void *p, unsigned char *data, int len,
+			unsigned int txlen);
 	int	num_args;
 	struct mISDN_dsp_element_arg
 		*args;
@@ -24,6 +25,7 @@
 struct dsp_features {
 	int	hfc_id; /* unique id to identify the chip (or -1) */
 	int	hfc_dtmf; /* set if HFCmulti card supports dtmf */
+	int	hfc_conf; /* set if HFCmulti card supports conferences */
 	int	hfc_loops; /* set if card supports tone loops */
 	int	hfc_echocanhw; /* set if card supports echocancelation*/
 	int	pcm_id; /* unique id to identify the pcm bus (or -1) */
diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h
index 97ffdc1..ce900f4 100644
--- a/include/linux/mISDNhw.h
+++ b/include/linux/mISDNhw.h
@@ -185,7 +185,7 @@
 extern int	bchannel_senddata(struct bchannel *, struct sk_buff *);
 extern void	recv_Dchannel(struct dchannel *);
 extern void	recv_Echannel(struct dchannel *, struct dchannel *);
-extern void	recv_Bchannel(struct bchannel *);
+extern void	recv_Bchannel(struct bchannel *, unsigned int id);
 extern void	recv_Dchannel_skb(struct dchannel *, struct sk_buff *);
 extern void	recv_Bchannel_skb(struct bchannel *, struct sk_buff *);
 extern void	confirm_Bsend(struct bchannel *bch);
diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h
index 5da3d95..45100b3 100644
--- a/include/linux/mISDNif.h
+++ b/include/linux/mISDNif.h
@@ -229,6 +229,7 @@
 #define OPTION_L2_PTP		2
 #define OPTION_L2_FIXEDTEI	3
 #define OPTION_L2_CLEANUP	4
+#define OPTION_L1_HOLD		5
 
 /* should be in sync with linux/kobject.h:KOBJ_NAME_LEN */
 #define MISDN_MAX_IDLEN		20
@@ -291,19 +292,19 @@
 
 /* MPH_INFORMATION_REQ payload */
 struct ph_info_ch {
-        __u32 protocol;
-        __u64 Flags;
+	__u32 protocol;
+	__u64 Flags;
 };
 
 struct ph_info_dch {
-        struct ph_info_ch ch;
-        __u16 state;
-        __u16 num_bch;
+	struct ph_info_ch ch;
+	__u16 state;
+	__u16 num_bch;
 };
 
 struct ph_info {
-        struct ph_info_dch dch;
-        struct ph_info_ch  bch[];
+	struct ph_info_dch dch;
+	struct ph_info_ch  bch[];
 };
 
 /* timer device ioctl */
@@ -317,6 +318,7 @@
 #define IMCTRLREQ	_IOR('I', 69, int)
 #define IMCLEAR_L2	_IOR('I', 70, int)
 #define IMSETDEVNAME	_IOR('I', 71, struct mISDN_devrename)
+#define IMHOLD_L1	_IOR('I', 72, int)
 
 static inline int
 test_channelmap(u_int nr, u_char *map)
@@ -362,7 +364,8 @@
 #define MISDN_CTRL_HFC_RECEIVE_ON	0x4006
 #define MISDN_CTRL_HFC_ECHOCAN_ON 	0x4007
 #define MISDN_CTRL_HFC_ECHOCAN_OFF 	0x4008
-
+#define MISDN_CTRL_HFC_WD_INIT		0x4009
+#define MISDN_CTRL_HFC_WD_RESET		0x400A
 
 /* socket options */
 #define MISDN_TIME_STAMP		0x0001
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index f8574e7..8e03b06 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -901,49 +901,10 @@
 	/* max exchange id for FCoE LRO by ddp */
 	unsigned int		fcoe_ddp_xid;
 #endif
-
-#ifdef CONFIG_COMPAT_NET_DEV_OPS
-	struct {
-		int			(*init)(struct net_device *dev);
-		void			(*uninit)(struct net_device *dev);
-		int			(*open)(struct net_device *dev);
-		int			(*stop)(struct net_device *dev);
-		int			(*hard_start_xmit) (struct sk_buff *skb,
-							    struct net_device *dev);
-		u16			(*select_queue)(struct net_device *dev,
-							struct sk_buff *skb);
-		void			(*change_rx_flags)(struct net_device *dev,
-							   int flags);
-		void			(*set_rx_mode)(struct net_device *dev);
-		void			(*set_multicast_list)(struct net_device *dev);
-		int			(*set_mac_address)(struct net_device *dev,
-							   void *addr);
-		int			(*validate_addr)(struct net_device *dev);
-		int			(*do_ioctl)(struct net_device *dev,
-						    struct ifreq *ifr, int cmd);
-		int			(*set_config)(struct net_device *dev,
-						      struct ifmap *map);
-		int			(*change_mtu)(struct net_device *dev, int new_mtu);
-		int			(*neigh_setup)(struct net_device *dev,
-						       struct neigh_parms *);
-		void			(*tx_timeout) (struct net_device *dev);
-		struct net_device_stats* (*get_stats)(struct net_device *dev);
-		void			(*vlan_rx_register)(struct net_device *dev,
-							    struct vlan_group *grp);
-		void			(*vlan_rx_add_vid)(struct net_device *dev,
-							   unsigned short vid);
-		void			(*vlan_rx_kill_vid)(struct net_device *dev,
-							    unsigned short vid);
-#ifdef CONFIG_NET_POLL_CONTROLLER
-		void                    (*poll_controller)(struct net_device *dev);
-#endif
-	};
-#endif
 };
 #define to_net_dev(d) container_of(d, struct net_device, dev)
 
 #define	NETDEV_ALIGN		32
-#define	NETDEV_ALIGN_CONST	(NETDEV_ALIGN - 1)
 
 static inline
 struct netdev_queue *netdev_get_tx_queue(const struct net_device *dev,
@@ -1014,9 +975,7 @@
  */
 static inline void *netdev_priv(const struct net_device *dev)
 {
-	return (char *)dev + ((sizeof(struct net_device)
-			       + NETDEV_ALIGN_CONST)
-			      & ~NETDEV_ALIGN_CONST);
+	return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN);
 }
 
 /* Set the sysfs physical device reference for the network logical device
@@ -1046,6 +1005,12 @@
 void netif_napi_del(struct napi_struct *napi);
 
 struct napi_gro_cb {
+	/* Virtual address of skb_shinfo(skb)->frags[0].page + offset. */
+	void *frag0;
+
+	/* Length of frag0. */
+	unsigned int frag0_len;
+
 	/* This indicates where we are processing relative to skb->data. */
 	int data_offset;
 
@@ -1145,9 +1110,9 @@
 #ifdef CONFIG_NETPOLL_TRAP
 extern int		netpoll_trap(void);
 #endif
-extern void	      *skb_gro_header(struct sk_buff *skb, unsigned int hlen);
 extern int	       skb_gro_receive(struct sk_buff **head,
 				       struct sk_buff *skb);
+extern void	       skb_gro_reset_offset(struct sk_buff *skb);
 
 static inline unsigned int skb_gro_offset(const struct sk_buff *skb)
 {
@@ -1164,23 +1129,34 @@
 	NAPI_GRO_CB(skb)->data_offset += len;
 }
 
-static inline void skb_gro_reset_offset(struct sk_buff *skb)
+static inline void *skb_gro_header_fast(struct sk_buff *skb,
+					unsigned int offset)
 {
-	NAPI_GRO_CB(skb)->data_offset = 0;
+	return NAPI_GRO_CB(skb)->frag0 + offset;
+}
+
+static inline int skb_gro_header_hard(struct sk_buff *skb, unsigned int hlen)
+{
+	return NAPI_GRO_CB(skb)->frag0_len < hlen;
+}
+
+static inline void *skb_gro_header_slow(struct sk_buff *skb, unsigned int hlen,
+					unsigned int offset)
+{
+	NAPI_GRO_CB(skb)->frag0 = NULL;
+	NAPI_GRO_CB(skb)->frag0_len = 0;
+	return pskb_may_pull(skb, hlen) ? skb->data + offset : NULL;
 }
 
 static inline void *skb_gro_mac_header(struct sk_buff *skb)
 {
-	return skb_headlen(skb) ? skb_mac_header(skb) :
-	       page_address(skb_shinfo(skb)->frags[0].page) +
-	       skb_shinfo(skb)->frags[0].page_offset;
+	return NAPI_GRO_CB(skb)->frag0 ?: skb_mac_header(skb);
 }
 
 static inline void *skb_gro_network_header(struct sk_buff *skb)
 {
-	return skb_headlen(skb) ? skb_network_header(skb) :
-	       page_address(skb_shinfo(skb)->frags[0].page) +
-	       skb_shinfo(skb)->frags[0].page_offset + skb_network_offset(skb);
+	return (NAPI_GRO_CB(skb)->frag0 ?: skb->data) +
+	       skb_network_offset(skb);
 }
 
 static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev,
@@ -1712,6 +1688,12 @@
 	spin_unlock_bh(&txq->_xmit_lock);
 }
 
+static inline void txq_trans_update(struct netdev_queue *txq)
+{
+	if (txq->xmit_lock_owner != -1)
+		txq->trans_start = jiffies;
+}
+
 /**
  *	netif_tx_lock - grab network device transmit lock
  *	@dev: network device
@@ -1993,4 +1975,4 @@
 }
 #endif /* __KERNEL__ */
 
-#endif	/* _LINUX_DEV_H */
+#endif	/* _LINUX_NETDEVICE_H */
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 3038ac2..12db06c 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1914,6 +1914,8 @@
 #define PCI_SUBDEVICE_ID_CCD_SWYX4S	0xB540
 #define PCI_SUBDEVICE_ID_CCD_JH4S20	0xB550
 #define PCI_SUBDEVICE_ID_CCD_IOB8ST_1	0xB552
+#define PCI_SUBDEVICE_ID_CCD_JHSE1	0xB553
+#define PCI_SUBDEVICE_ID_CCD_JH8S	0xB55B
 #define PCI_SUBDEVICE_ID_CCD_BN4S	0xB560
 #define PCI_SUBDEVICE_ID_CCD_BN8S	0xB562
 #define PCI_SUBDEVICE_ID_CCD_BNE1	0xB563
diff --git a/include/linux/phy.h b/include/linux/phy.h
index c216e4e..b1368b8 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -79,7 +79,7 @@
  * Need to be a little smaller than phydev->dev.bus_id to leave room
  * for the ":%02x"
  */
-#define MII_BUS_ID_SIZE	(BUS_ID_SIZE - 3)
+#define MII_BUS_ID_SIZE	(20 - 3)
 
 /*
  * The Bus class for PHYs.  Devices which provide access to
@@ -407,7 +407,7 @@
 /* A Structure for boards to register fixups with the PHY Lib */
 struct phy_fixup {
 	struct list_head list;
-	char bus_id[BUS_ID_SIZE];
+	char bus_id[20];
 	u32 phy_uid;
 	u32 phy_uid_mask;
 	int (*run)(struct phy_device *phydev);
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 9e17a83..f20da7d 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -56,9 +56,9 @@
  *	on this channel.
  * @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel.
  * @IEEE80211_CHAN_RADAR: Radar detection is required on this channel.
- * @IEEE80211_CHAN_NO_FAT_ABOVE: extension channel above this channel
+ * @IEEE80211_CHAN_NO_HT40PLUS: extension channel above this channel
  * 	is not permitted.
- * @IEEE80211_CHAN_NO_FAT_BELOW: extension channel below this channel
+ * @IEEE80211_CHAN_NO_HT40MINUS: extension channel below this channel
  * 	is not permitted.
  */
 enum ieee80211_channel_flags {
@@ -66,10 +66,13 @@
 	IEEE80211_CHAN_PASSIVE_SCAN	= 1<<1,
 	IEEE80211_CHAN_NO_IBSS		= 1<<2,
 	IEEE80211_CHAN_RADAR		= 1<<3,
-	IEEE80211_CHAN_NO_FAT_ABOVE	= 1<<4,
-	IEEE80211_CHAN_NO_FAT_BELOW	= 1<<5,
+	IEEE80211_CHAN_NO_HT40PLUS	= 1<<4,
+	IEEE80211_CHAN_NO_HT40MINUS	= 1<<5,
 };
 
+#define IEEE80211_CHAN_NO_HT40 \
+	(IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS)
+
 /**
  * struct ieee80211_channel - channel definition
  *
@@ -778,10 +781,11 @@
  * @get_key: get information about the key with the given parameters.
  *	@mac_addr will be %NULL when requesting information for a group
  *	key. All pointers given to the @callback function need not be valid
- *	after it returns.
+ *	after it returns. This function should return an error if it is
+ *	not possible to retrieve the key, -ENOENT if it doesn't exist.
  *
  * @del_key: remove a key given the @mac_addr (%NULL for a group key)
- *	and @key_index
+ *	and @key_index, return -ENOENT if the key doesn't exist.
  *
  * @set_default_key: set the default key on an interface
  *
@@ -994,7 +998,7 @@
 	 * know whether it points to a wiphy your driver has registered
 	 * or not. Assign this to something global to your driver to
 	 * help determine whether you own this wiphy or not. */
-	void *privid;
+	const void *privid;
 
 	struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS];
 
@@ -1070,7 +1074,7 @@
  * The returned pointer must be assigned to each netdev's
  * ieee80211_ptr for proper operation.
  */
-struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv);
+struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv);
 
 /**
  * wiphy_register - register a wiphy with cfg80211
@@ -1240,6 +1244,53 @@
 extern int ieee80211_radiotap_iterator_next(
    struct ieee80211_radiotap_iterator *iterator);
 
+extern const unsigned char rfc1042_header[6];
+extern const unsigned char bridge_tunnel_header[6];
+
+/**
+ * ieee80211_get_hdrlen_from_skb - get header length from data
+ *
+ * Given an skb with a raw 802.11 header at the data pointer this function
+ * returns the 802.11 header length in bytes (not including encryption
+ * headers). If the data in the sk_buff is too short to contain a valid 802.11
+ * header the function returns 0.
+ *
+ * @skb: the frame
+ */
+unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb);
+
+/**
+ * ieee80211_hdrlen - get header length in bytes from frame control
+ * @fc: frame control field in little-endian format
+ */
+unsigned int ieee80211_hdrlen(__le16 fc);
+
+/**
+ * ieee80211_data_to_8023 - convert an 802.11 data frame to 802.3
+ * @skb: the 802.11 data frame
+ * @addr: the device MAC address
+ * @iftype: the virtual interface type
+ */
+int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
+			   enum nl80211_iftype iftype);
+
+/**
+ * ieee80211_data_from_8023 - convert an 802.3 frame to 802.11
+ * @skb: the 802.3 frame
+ * @addr: the device MAC address
+ * @iftype: the virtual interface type
+ * @bssid: the network bssid (used only for iftype STATION and ADHOC)
+ * @qos: build 802.11 QoS data frame
+ */
+int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr,
+			     enum nl80211_iftype iftype, u8 *bssid, bool qos);
+
+/**
+ * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
+ * @skb: the data frame
+ */
+unsigned int cfg80211_classify8021d(struct sk_buff *skb);
+
 /*
  * Regulatory helper functions for wiphys
  */
@@ -1303,9 +1354,10 @@
  * freq_reg_info - get regulatory information for the given frequency
  * @wiphy: the wiphy for which we want to process this rule for
  * @center_freq: Frequency in KHz for which we want regulatory information for
- * @bandwidth: the bandwidth requirement you have in KHz, if you do not have one
- * 	you can set this to 0. If this frequency is allowed we then set
- * 	this value to the maximum allowed bandwidth.
+ * @desired_bw_khz: the desired max bandwidth you want to use per
+ *	channel. Note that this is still 20 MHz if you want to use HT40
+ *	as HT40 makes use of two channels for its 40 MHz width bandwidth.
+ *	If set to 0 we'll assume you want the standard 20 MHz.
  * @reg_rule: the regulatory rule which we have for this frequency
  *
  * Use this function to get the regulatory rule for a specific frequency on
@@ -1320,7 +1372,9 @@
  * freq_in_rule_band() for our current definition of a band -- this is purely
  * subjective and right now its 802.11 specific.
  */
-extern int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth,
+extern int freq_reg_info(struct wiphy *wiphy,
+			 u32 center_freq,
+			 u32 desired_bw_khz,
 			 const struct ieee80211_reg_rule **reg_rule);
 
 /*
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index d10ed17..d72346f 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -173,7 +173,6 @@
  * @timestamp: beacon timestamp
  * @beacon_int: beacon interval
  * @assoc_capability: capabilities taken from assoc resp
- * @ht: BSS's HT configuration
  * @basic_rates: bitmap of basic rates, each bit stands for an
  *	index into the rate table configured by the driver in
  *	the current band.
@@ -673,16 +672,6 @@
 };
 
 /**
- * enum ieee80211_key_len - key length
- * @LEN_WEP40: WEP 5-byte long key
- * @LEN_WEP104: WEP 13-byte long key
- */
-enum ieee80211_key_len {
-	LEN_WEP40 = 5,
-	LEN_WEP104 = 13,
-};
-
-/**
  * enum ieee80211_key_flags - key flags
  *
  * These flags are used for communication about keys between the driver
@@ -1813,24 +1802,6 @@
 ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
 
 /**
- * ieee80211_get_hdrlen_from_skb - get header length from data
- *
- * Given an skb with a raw 802.11 header at the data pointer this function
- * returns the 802.11 header length in bytes (not including encryption
- * headers). If the data in the sk_buff is too short to contain a valid 802.11
- * header the function returns 0.
- *
- * @skb: the frame
- */
-unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb);
-
-/**
- * ieee80211_hdrlen - get header length in bytes from frame control
- * @fc: frame control field in little-endian format
- */
-unsigned int ieee80211_hdrlen(__le16 fc);
-
-/**
  * ieee80211_get_tkip_key - get a TKIP rc4 for skb
  *
  * This function computes a TKIP rc4 key for an skb. It computes
diff --git a/net/802/fddi.c b/net/802/fddi.c
index 539e606..3ef0ab0 100644
--- a/net/802/fddi.c
+++ b/net/802/fddi.c
@@ -185,10 +185,6 @@
 static void fddi_setup(struct net_device *dev)
 {
 	dev->header_ops		= &fddi_header_ops;
-#ifdef CONFIG_COMPAT_NET_DEV_OPS
-	dev->change_mtu		= fddi_change_mtu,
-#endif
-
 	dev->type		= ARPHRD_FDDI;
 	dev->hard_header_len	= FDDI_K_SNAP_HLEN+3;	/* Assume 802.2 SNAP hdr len + 3 pad bytes */
 	dev->mtu		= FDDI_K_SNAP_DLEN;	/* Assume max payload of 802.2 SNAP frame */
diff --git a/net/802/hippi.c b/net/802/hippi.c
index 313b9eb..cd3e8e9 100644
--- a/net/802/hippi.c
+++ b/net/802/hippi.c
@@ -193,11 +193,6 @@
 
 static void hippi_setup(struct net_device *dev)
 {
-#ifdef CONFIG_COMPAT_NET_DEV_OPS
-	dev->change_mtu			= hippi_change_mtu;
-	dev->set_mac_address 		= hippi_mac_addr;
-	dev->neigh_setup 		= hippi_neigh_setup_dev;
-#endif
 	dev->header_ops			= &hippi_header_ops;
 
 	/*
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index ff7572a..1e2ad4c 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -644,7 +644,6 @@
 		dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN;
 		dev->netdev_ops         = &vlan_netdev_ops;
 	}
-	netdev_resync_ops(dev);
 
 	if (is_vlan_dev(real_dev))
 		subclass = 1;
diff --git a/net/appletalk/dev.c b/net/appletalk/dev.c
index 72277d7..6c8016f 100644
--- a/net/appletalk/dev.c
+++ b/net/appletalk/dev.c
@@ -9,21 +9,10 @@
 #include <linux/if_arp.h>
 #include <linux/if_ltalk.h>
 
-#ifdef CONFIG_COMPAT_NET_DEV_OPS
-static int ltalk_change_mtu(struct net_device *dev, int mtu)
-{
-	return -EINVAL;
-}
-#endif
-
 static void ltalk_setup(struct net_device *dev)
 {
 	/* Fill in the fields of the device structure with localtalk-generic values. */
 
-#ifdef CONFIG_COMPAT_NET_DEV_OPS
-	dev->change_mtu		= ltalk_change_mtu;
-#endif
-
 	dev->type		= ARPHRD_LOCALTLK;
 	dev->hard_header_len 	= LTALK_HLEN;
 	dev->mtu		= LTALK_MTU;
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index 3100a89..bfa8fa9 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -445,9 +445,10 @@
  */
 static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
 {
+	struct sk_buff_head queue;
 	int err;
 	struct br2684_vcc *brvcc;
-	struct sk_buff *skb;
+	struct sk_buff *skb, *tmp;
 	struct sk_buff_head *rq;
 	struct br2684_dev *brdev;
 	struct net_device *net_dev;
@@ -505,29 +506,20 @@
 	barrier();
 	atmvcc->push = br2684_push;
 
+	__skb_queue_head_init(&queue);
 	rq = &sk_atm(atmvcc)->sk_receive_queue;
 
 	spin_lock_irqsave(&rq->lock, flags);
-	if (skb_queue_empty(rq)) {
-		skb = NULL;
-	} else {
-		/* NULL terminate the list.  */
-		rq->prev->next = NULL;
-		skb = rq->next;
-	}
-	rq->prev = rq->next = (struct sk_buff *)rq;
-	rq->qlen = 0;
+	skb_queue_splice_init(rq, &queue);
 	spin_unlock_irqrestore(&rq->lock, flags);
 
-	while (skb) {
-		struct sk_buff *next = skb->next;
+	skb_queue_walk_safe(&queue, skb, tmp) {
+		struct net_device *dev = skb->dev;
 
-		skb->next = skb->prev = NULL;
+		dev->stats.rx_bytes -= skb->len;
+		dev->stats.rx_packets--;
+
 		br2684_push(atmvcc, skb);
-		skb->dev->stats.rx_bytes -= skb->len;
-		skb->dev->stats.rx_packets--;
-
-		skb = next;
 	}
 	__module_get(THIS_MODULE);
 	return 0;
diff --git a/net/atm/clip.c b/net/atm/clip.c
index 3dc0a3a..5597b87 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -445,9 +445,9 @@
 
 static int clip_mkip(struct atm_vcc *vcc, int timeout)
 {
+	struct sk_buff_head *rq, queue;
 	struct clip_vcc *clip_vcc;
-	struct sk_buff *skb;
-	struct sk_buff_head *rq;
+	struct sk_buff *skb, *tmp;
 	unsigned long flags;
 
 	if (!vcc->push)
@@ -469,39 +469,28 @@
 	vcc->push = clip_push;
 	vcc->pop = clip_pop;
 
+	__skb_queue_head_init(&queue);
 	rq = &sk_atm(vcc)->sk_receive_queue;
 
 	spin_lock_irqsave(&rq->lock, flags);
-	if (skb_queue_empty(rq)) {
-		skb = NULL;
-	} else {
-		/* NULL terminate the list.  */
-		rq->prev->next = NULL;
-		skb = rq->next;
-	}
-	rq->prev = rq->next = (struct sk_buff *)rq;
-	rq->qlen = 0;
+	skb_queue_splice_init(rq, &queue);
 	spin_unlock_irqrestore(&rq->lock, flags);
 
 	/* re-process everything received between connection setup and MKIP */
-	while (skb) {
-		struct sk_buff *next = skb->next;
-
-		skb->next = skb->prev = NULL;
+	skb_queue_walk_safe(&queue, skb, tmp) {
 		if (!clip_devs) {
 			atm_return(vcc, skb->truesize);
 			kfree_skb(skb);
 		} else {
+			struct net_device *dev = skb->dev;
 			unsigned int len = skb->len;
 
 			skb_get(skb);
 			clip_push(vcc, skb);
-			skb->dev->stats.rx_packets--;
-			skb->dev->stats.rx_bytes -= len;
+			dev->stats.rx_packets--;
+			dev->stats.rx_bytes -= len;
 			kfree_skb(skb);
 		}
-
-		skb = next;
 	}
 	return 0;
 }
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index a48f5ef..cb3e97b 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -398,7 +398,7 @@
 		if (unlikely(fdb->is_local)) {
 			if (net_ratelimit())
 				printk(KERN_WARNING "%s: received packet with "
-				       " own address as source address\n",
+				       "own address as source address\n",
 				       source->dev->name);
 		} else {
 			/* fastpath: update of existing entry */
diff --git a/net/core/dev.c b/net/core/dev.c
index 3942266..32ceee1 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1698,6 +1698,8 @@
 			skb->dst = NULL;
 		}
 		rc = ops->ndo_start_xmit(skb, dev);
+		if (rc == 0)
+			txq_trans_update(txq);
 		/*
 		 * TODO: if skb_orphan() was called by
 		 * dev->hard_start_xmit() (for example, the unmodified
@@ -1727,6 +1729,7 @@
 			skb->next = nskb;
 			return rc;
 		}
+		txq_trans_update(txq);
 		if (unlikely(netif_tx_queue_stopped(txq) && skb->next))
 			return NETDEV_TX_BUSY;
 	} while (skb->next);
@@ -2387,21 +2390,6 @@
 }
 EXPORT_SYMBOL(napi_gro_flush);
 
-void *skb_gro_header(struct sk_buff *skb, unsigned int hlen)
-{
-	unsigned int offset = skb_gro_offset(skb);
-
-	hlen += offset;
-	if (unlikely(skb_headlen(skb) ||
-		     skb_shinfo(skb)->frags[0].size < hlen ||
-		     PageHighMem(skb_shinfo(skb)->frags[0].page)))
-		return pskb_may_pull(skb, hlen) ? skb->data + offset : NULL;
-
-	return page_address(skb_shinfo(skb)->frags[0].page) +
-	       skb_shinfo(skb)->frags[0].page_offset + offset;
-}
-EXPORT_SYMBOL(skb_gro_header);
-
 int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
 {
 	struct sk_buff **pp = NULL;
@@ -2464,10 +2452,25 @@
 	ret = GRO_HELD;
 
 pull:
-	if (unlikely(!pskb_may_pull(skb, skb_gro_offset(skb)))) {
-		if (napi->gro_list == skb)
-			napi->gro_list = skb->next;
-		ret = GRO_DROP;
+	if (skb_headlen(skb) < skb_gro_offset(skb)) {
+		int grow = skb_gro_offset(skb) - skb_headlen(skb);
+
+		BUG_ON(skb->end - skb->tail < grow);
+
+		memcpy(skb_tail_pointer(skb), NAPI_GRO_CB(skb)->frag0, grow);
+
+		skb->tail += grow;
+		skb->data_len -= grow;
+
+		skb_shinfo(skb)->frags[0].page_offset += grow;
+		skb_shinfo(skb)->frags[0].size -= grow;
+
+		if (unlikely(!skb_shinfo(skb)->frags[0].size)) {
+			put_page(skb_shinfo(skb)->frags[0].page);
+			memmove(skb_shinfo(skb)->frags,
+				skb_shinfo(skb)->frags + 1,
+				--skb_shinfo(skb)->nr_frags);
+		}
 	}
 
 ok:
@@ -2517,6 +2520,22 @@
 }
 EXPORT_SYMBOL(napi_skb_finish);
 
+void skb_gro_reset_offset(struct sk_buff *skb)
+{
+	NAPI_GRO_CB(skb)->data_offset = 0;
+	NAPI_GRO_CB(skb)->frag0 = NULL;
+	NAPI_GRO_CB(skb)->frag0_len = 0;
+
+	if (skb->mac_header == skb->tail &&
+	    !PageHighMem(skb_shinfo(skb)->frags[0].page)) {
+		NAPI_GRO_CB(skb)->frag0 =
+			page_address(skb_shinfo(skb)->frags[0].page) +
+			skb_shinfo(skb)->frags[0].page_offset;
+		NAPI_GRO_CB(skb)->frag0_len = skb_shinfo(skb)->frags[0].size;
+	}
+}
+EXPORT_SYMBOL(skb_gro_reset_offset);
+
 int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
 {
 	skb_gro_reset_offset(skb);
@@ -2586,17 +2605,24 @@
 {
 	struct sk_buff *skb = napi->skb;
 	struct ethhdr *eth;
+	unsigned int hlen;
+	unsigned int off;
 
 	napi->skb = NULL;
 
 	skb_reset_mac_header(skb);
 	skb_gro_reset_offset(skb);
 
-	eth = skb_gro_header(skb, sizeof(*eth));
-	if (!eth) {
-		napi_reuse_skb(napi, skb);
-		skb = NULL;
-		goto out;
+	off = skb_gro_offset(skb);
+	hlen = off + sizeof(*eth);
+	eth = skb_gro_header_fast(skb, off);
+	if (skb_gro_header_hard(skb, hlen)) {
+		eth = skb_gro_header_slow(skb, hlen, off);
+		if (unlikely(!eth)) {
+			napi_reuse_skb(napi, skb);
+			skb = NULL;
+			goto out;
+		}
 	}
 
 	skb_gro_pull(skb, sizeof(*eth));
@@ -4580,39 +4606,6 @@
 }
 EXPORT_SYMBOL(netdev_fix_features);
 
-/* Some devices need to (re-)set their netdev_ops inside
- * ->init() or similar.  If that happens, we have to setup
- * the compat pointers again.
- */
-void netdev_resync_ops(struct net_device *dev)
-{
-#ifdef CONFIG_COMPAT_NET_DEV_OPS
-	const struct net_device_ops *ops = dev->netdev_ops;
-
-	dev->init = ops->ndo_init;
-	dev->uninit = ops->ndo_uninit;
-	dev->open = ops->ndo_open;
-	dev->change_rx_flags = ops->ndo_change_rx_flags;
-	dev->set_rx_mode = ops->ndo_set_rx_mode;
-	dev->set_multicast_list = ops->ndo_set_multicast_list;
-	dev->set_mac_address = ops->ndo_set_mac_address;
-	dev->validate_addr = ops->ndo_validate_addr;
-	dev->do_ioctl = ops->ndo_do_ioctl;
-	dev->set_config = ops->ndo_set_config;
-	dev->change_mtu = ops->ndo_change_mtu;
-	dev->neigh_setup = ops->ndo_neigh_setup;
-	dev->tx_timeout = ops->ndo_tx_timeout;
-	dev->get_stats = ops->ndo_get_stats;
-	dev->vlan_rx_register = ops->ndo_vlan_rx_register;
-	dev->vlan_rx_add_vid = ops->ndo_vlan_rx_add_vid;
-	dev->vlan_rx_kill_vid = ops->ndo_vlan_rx_kill_vid;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = ops->ndo_poll_controller;
-#endif
-#endif
-}
-EXPORT_SYMBOL(netdev_resync_ops);
-
 /**
  *	register_netdevice	- register a network device
  *	@dev: device to register
@@ -4652,23 +4645,6 @@
 
 	dev->iflink = -1;
 
-#ifdef CONFIG_COMPAT_NET_DEV_OPS
-	/* Netdevice_ops API compatibility support.
-	 * This is temporary until all network devices are converted.
-	 */
-	if (dev->netdev_ops) {
-		netdev_resync_ops(dev);
-	} else {
-		char drivername[64];
-		pr_info("%s (%s): not using net_device_ops yet\n",
-			dev->name, netdev_drivername(dev, drivername, 64));
-
-		/* This works only because net_device_ops and the
-		   compatibility structure are the same. */
-		dev->netdev_ops = (void *) &(dev->init);
-	}
-#endif
-
 	/* Init, if this function is available */
 	if (dev->netdev_ops->ndo_init) {
 		ret = dev->netdev_ops->ndo_init(dev);
@@ -5012,18 +4988,18 @@
 	struct netdev_queue *tx;
 	struct net_device *dev;
 	size_t alloc_size;
-	void *p;
+	struct net_device *p;
 
 	BUG_ON(strlen(name) >= sizeof(dev->name));
 
 	alloc_size = sizeof(struct net_device);
 	if (sizeof_priv) {
 		/* ensure 32-byte alignment of private area */
-		alloc_size = (alloc_size + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST;
+		alloc_size = ALIGN(alloc_size, NETDEV_ALIGN);
 		alloc_size += sizeof_priv;
 	}
 	/* ensure 32-byte alignment of whole construct */
-	alloc_size += NETDEV_ALIGN_CONST;
+	alloc_size += NETDEV_ALIGN - 1;
 
 	p = kzalloc(alloc_size, GFP_KERNEL);
 	if (!p) {
@@ -5038,8 +5014,7 @@
 		goto free_p;
 	}
 
-	dev = (struct net_device *)
-		(((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
+	dev = PTR_ALIGN(p, NETDEV_ALIGN);
 	dev->padded = (char *)dev - (char *)p;
 
 	if (dev_addr_init(dev))
diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c
index 6d62d46..78e5bfc 100644
--- a/net/core/gen_estimator.c
+++ b/net/core/gen_estimator.c
@@ -128,12 +128,12 @@
 		npackets = e->bstats->packets;
 		brate = (nbytes - e->last_bytes)<<(7 - idx);
 		e->last_bytes = nbytes;
-		e->avbps += ((s64)(brate - e->avbps)) >> e->ewma_log;
+		e->avbps += (brate >> e->ewma_log) - (e->avbps >> e->ewma_log);
 		e->rate_est->bps = (e->avbps+0xF)>>5;
 
 		rate = (npackets - e->last_packets)<<(12 - idx);
 		e->last_packets = npackets;
-		e->avpps += ((long)rate - (long)e->avpps) >> e->ewma_log;
+		e->avpps += (rate >> e->ewma_log) - (e->avpps >> e->ewma_log);
 		e->rate_est->pps = (e->avpps+0x1FF)>>10;
 skip:
 		read_unlock(&est_lock);
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index b9641e8..3994680 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -499,7 +499,6 @@
 	dev->platform_data = net;
 	dev->groups = groups;
 
-	BUILD_BUG_ON(BUS_ID_SIZE < IFNAMSIZ);
 	dev_set_name(dev, "%s", net->name);
 
 #ifdef CONFIG_SYSFS
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 67b4f3e..7ab31a7 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -302,8 +302,11 @@
 		for (tries = jiffies_to_usecs(1)/USEC_PER_POLL;
 		     tries > 0; --tries) {
 			if (__netif_tx_trylock(txq)) {
-				if (!netif_tx_queue_stopped(txq))
+				if (!netif_tx_queue_stopped(txq)) {
 					status = ops->ndo_start_xmit(skb, dev);
+					if (status == NETDEV_TX_OK)
+						txq_trans_update(txq);
+				}
 				__netif_tx_unlock(txq);
 
 				if (status == NETDEV_TX_OK)
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 3779c14..b8ccd3c 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -2447,7 +2447,7 @@
 	if (pkt_dev->cflows) {
 		/* let go of the SAs if we have them */
 		int i = 0;
-		for (;  i < pkt_dev->nflows; i++){
+		for (;  i < pkt_dev->cflows; i++) {
 			struct xfrm_state *x = pkt_dev->flows[i].x;
 			if (x) {
 				xfrm_state_put(x);
@@ -3438,6 +3438,7 @@
 	      retry_now:
 		ret = (*xmit)(pkt_dev->skb, odev);
 		if (likely(ret == NETDEV_TX_OK)) {
+			txq_trans_update(txq);
 			pkt_dev->last_ok = 1;
 			pkt_dev->sofar++;
 			pkt_dev->seq_num++;
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index d152394..8e815e6 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -526,8 +526,7 @@
 	new->sp			= secpath_get(old->sp);
 #endif
 	memcpy(new->cb, old->cb, sizeof(old->cb));
-	new->csum_start		= old->csum_start;
-	new->csum_offset	= old->csum_offset;
+	new->csum		= old->csum;
 	new->local_df		= old->local_df;
 	new->pkt_type		= old->pkt_type;
 	new->ip_summed		= old->ip_summed;
@@ -538,6 +537,7 @@
 #endif
 	new->protocol		= old->protocol;
 	new->mark		= old->mark;
+	new->iif		= old->iif;
 	__nf_copy(new, old);
 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
     defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
@@ -550,10 +550,18 @@
 #endif
 #endif
 	new->vlan_tci		= old->vlan_tci;
+#if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE)
+	new->do_not_encrypt	= old->do_not_encrypt;
+	new->requeue		= old->requeue;
+#endif
 
 	skb_copy_secmark(new, old);
 }
 
+/*
+ * You should not add any new code to this function.  Add it to
+ * __copy_skb_header above instead.
+ */
 static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb)
 {
 #define C(x) n->x = skb->x
@@ -569,16 +577,11 @@
 	n->cloned = 1;
 	n->nohdr = 0;
 	n->destructor = NULL;
-	C(iif);
 	C(tail);
 	C(end);
 	C(head);
 	C(data);
 	C(truesize);
-#if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE)
-	C(do_not_encrypt);
-	C(requeue);
-#endif
 	atomic_set(&n->users, 1);
 
 	atomic_inc(&(skb_shinfo(skb)->dataref));
@@ -2288,7 +2291,7 @@
 next_skb:
 	block_limit = skb_headlen(st->cur_skb) + st->stepped_offset;
 
-	if (abs_offset < block_limit) {
+	if (abs_offset < block_limit && !st->frag_data) {
 		*data = st->cur_skb->data + (abs_offset - st->stepped_offset);
 		return block_limit - abs_offset;
 	}
@@ -2661,30 +2664,40 @@
 {
 	struct sk_buff *p = *head;
 	struct sk_buff *nskb;
+	struct skb_shared_info *skbinfo = skb_shinfo(skb);
+	struct skb_shared_info *pinfo = skb_shinfo(p);
 	unsigned int headroom;
 	unsigned int len = skb_gro_len(skb);
+	unsigned int offset = skb_gro_offset(skb);
+	unsigned int headlen = skb_headlen(skb);
 
 	if (p->len + len >= 65536)
 		return -E2BIG;
 
-	if (skb_shinfo(p)->frag_list)
+	if (pinfo->frag_list)
 		goto merge;
-	else if (skb_headlen(skb) <= skb_gro_offset(skb)) {
-		if (skb_shinfo(p)->nr_frags + skb_shinfo(skb)->nr_frags >
-		    MAX_SKB_FRAGS)
+	else if (headlen <= offset) {
+		skb_frag_t *frag;
+		skb_frag_t *frag2;
+		int i = skbinfo->nr_frags;
+		int nr_frags = pinfo->nr_frags + i;
+
+		offset -= headlen;
+
+		if (nr_frags > MAX_SKB_FRAGS)
 			return -E2BIG;
 
-		skb_shinfo(skb)->frags[0].page_offset +=
-			skb_gro_offset(skb) - skb_headlen(skb);
-		skb_shinfo(skb)->frags[0].size -=
-			skb_gro_offset(skb) - skb_headlen(skb);
+		pinfo->nr_frags = nr_frags;
+		skbinfo->nr_frags = 0;
 
-		memcpy(skb_shinfo(p)->frags + skb_shinfo(p)->nr_frags,
-		       skb_shinfo(skb)->frags,
-		       skb_shinfo(skb)->nr_frags * sizeof(skb_frag_t));
+		frag = pinfo->frags + nr_frags;
+		frag2 = skbinfo->frags + i;
+		do {
+			*--frag = *--frag2;
+		} while (--i);
 
-		skb_shinfo(p)->nr_frags += skb_shinfo(skb)->nr_frags;
-		skb_shinfo(skb)->nr_frags = 0;
+		frag->page_offset += offset;
+		frag->size -= offset;
 
 		skb->truesize -= skb->data_len;
 		skb->len -= skb->data_len;
@@ -2715,7 +2728,7 @@
 
 	*NAPI_GRO_CB(nskb) = *NAPI_GRO_CB(p);
 	skb_shinfo(nskb)->frag_list = p;
-	skb_shinfo(nskb)->gso_size = skb_shinfo(p)->gso_size;
+	skb_shinfo(nskb)->gso_size = pinfo->gso_size;
 	skb_header_release(p);
 	nskb->prev = p;
 
@@ -2730,16 +2743,13 @@
 	p = nskb;
 
 merge:
-	if (skb_gro_offset(skb) > skb_headlen(skb)) {
-		skb_shinfo(skb)->frags[0].page_offset +=
-			skb_gro_offset(skb) - skb_headlen(skb);
-		skb_shinfo(skb)->frags[0].size -=
-			skb_gro_offset(skb) - skb_headlen(skb);
-		skb_gro_reset_offset(skb);
-		skb_gro_pull(skb, skb_headlen(skb));
+	if (offset > headlen) {
+		skbinfo->frags[0].page_offset += offset - headlen;
+		skbinfo->frags[0].size -= offset - headlen;
+		offset = headlen;
 	}
 
-	__skb_pull(skb, skb_gro_offset(skb));
+	__skb_pull(skb, offset);
 
 	p->prev->next = skb;
 	p->prev = skb;
diff --git a/net/core/sock.c b/net/core/sock.c
index 7dbf3ff..58dec9d 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -212,6 +212,7 @@
 
 /* Maximal space eaten by iovec or ancilliary data plus some space */
 int sysctl_optmem_max __read_mostly = sizeof(unsigned long)*(2*UIO_MAXIOV+512);
+EXPORT_SYMBOL(sysctl_optmem_max);
 
 static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen)
 {
@@ -444,7 +445,7 @@
 int sock_setsockopt(struct socket *sock, int level, int optname,
 		    char __user *optval, int optlen)
 {
-	struct sock *sk=sock->sk;
+	struct sock *sk = sock->sk;
 	int val;
 	int valbool;
 	struct linger ling;
@@ -463,15 +464,15 @@
 	if (get_user(val, (int __user *)optval))
 		return -EFAULT;
 
-	valbool = val?1:0;
+	valbool = val ? 1 : 0;
 
 	lock_sock(sk);
 
-	switch(optname) {
+	switch (optname) {
 	case SO_DEBUG:
-		if (val && !capable(CAP_NET_ADMIN)) {
+		if (val && !capable(CAP_NET_ADMIN))
 			ret = -EACCES;
-		} else
+		else
 			sock_valbool_flag(sk, SOCK_DBG, valbool);
 		break;
 	case SO_REUSEADDR:
@@ -582,7 +583,7 @@
 			ret = -EINVAL;	/* 1003.1g */
 			break;
 		}
-		if (copy_from_user(&ling,optval,sizeof(ling))) {
+		if (copy_from_user(&ling, optval, sizeof(ling))) {
 			ret = -EFAULT;
 			break;
 		}
@@ -690,9 +691,8 @@
 	case SO_MARK:
 		if (!capable(CAP_NET_ADMIN))
 			ret = -EPERM;
-		else {
+		else
 			sk->sk_mark = val;
-		}
 		break;
 
 		/* We implement the SO_SNDLOWAT etc to
@@ -704,6 +704,7 @@
 	release_sock(sk);
 	return ret;
 }
+EXPORT_SYMBOL(sock_setsockopt);
 
 
 int sock_getsockopt(struct socket *sock, int level, int optname,
@@ -727,7 +728,7 @@
 
 	memset(&v, 0, sizeof(v));
 
-	switch(optname) {
+	switch (optname) {
 	case SO_DEBUG:
 		v.val = sock_flag(sk, SOCK_DBG);
 		break;
@@ -762,7 +763,7 @@
 
 	case SO_ERROR:
 		v.val = -sock_error(sk);
-		if (v.val==0)
+		if (v.val == 0)
 			v.val = xchg(&sk->sk_err_soft, 0);
 		break;
 
@@ -816,7 +817,7 @@
 		break;
 
 	case SO_RCVTIMEO:
-		lv=sizeof(struct timeval);
+		lv = sizeof(struct timeval);
 		if (sk->sk_rcvtimeo == MAX_SCHEDULE_TIMEOUT) {
 			v.tm.tv_sec = 0;
 			v.tm.tv_usec = 0;
@@ -827,7 +828,7 @@
 		break;
 
 	case SO_SNDTIMEO:
-		lv=sizeof(struct timeval);
+		lv = sizeof(struct timeval);
 		if (sk->sk_sndtimeo == MAX_SCHEDULE_TIMEOUT) {
 			v.tm.tv_sec = 0;
 			v.tm.tv_usec = 0;
@@ -842,7 +843,7 @@
 		break;
 
 	case SO_SNDLOWAT:
-		v.val=1;
+		v.val = 1;
 		break;
 
 	case SO_PASSCRED:
@@ -1002,6 +1003,7 @@
 
 	return sk;
 }
+EXPORT_SYMBOL(sk_alloc);
 
 void sk_free(struct sock *sk)
 {
@@ -1026,6 +1028,7 @@
 	put_net(sock_net(sk));
 	sk_prot_free(sk->sk_prot_creator, sk);
 }
+EXPORT_SYMBOL(sk_free);
 
 /*
  * Last sock_put should drop referrence to sk->sk_net. It has already
@@ -1126,7 +1129,6 @@
 out:
 	return newsk;
 }
-
 EXPORT_SYMBOL_GPL(sk_clone);
 
 void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
@@ -1177,6 +1179,7 @@
 		sk->sk_write_space(sk);
 	sock_put(sk);
 }
+EXPORT_SYMBOL(sock_wfree);
 
 /*
  * Read buffer destructor automatically called from kfree_skb.
@@ -1188,6 +1191,7 @@
 	atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
 	sk_mem_uncharge(skb->sk, skb->truesize);
 }
+EXPORT_SYMBOL(sock_rfree);
 
 
 int sock_i_uid(struct sock *sk)
@@ -1199,6 +1203,7 @@
 	read_unlock(&sk->sk_callback_lock);
 	return uid;
 }
+EXPORT_SYMBOL(sock_i_uid);
 
 unsigned long sock_i_ino(struct sock *sk)
 {
@@ -1209,6 +1214,7 @@
 	read_unlock(&sk->sk_callback_lock);
 	return ino;
 }
+EXPORT_SYMBOL(sock_i_ino);
 
 /*
  * Allocate a skb from the socket's send buffer.
@@ -1217,7 +1223,7 @@
 			     gfp_t priority)
 {
 	if (force || atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) {
-		struct sk_buff * skb = alloc_skb(size, priority);
+		struct sk_buff *skb = alloc_skb(size, priority);
 		if (skb) {
 			skb_set_owner_w(skb, sk);
 			return skb;
@@ -1225,6 +1231,7 @@
 	}
 	return NULL;
 }
+EXPORT_SYMBOL(sock_wmalloc);
 
 /*
  * Allocate a skb from the socket's receive buffer.
@@ -1261,6 +1268,7 @@
 	}
 	return NULL;
 }
+EXPORT_SYMBOL(sock_kmalloc);
 
 /*
  * Free an option memory block.
@@ -1270,11 +1278,12 @@
 	kfree(mem);
 	atomic_sub(size, &sk->sk_omem_alloc);
 }
+EXPORT_SYMBOL(sock_kfree_s);
 
 /* It is almost wait_for_tcp_memory minus release_sock/lock_sock.
    I think, these locks should be removed for datagram sockets.
  */
-static long sock_wait_for_wmem(struct sock * sk, long timeo)
+static long sock_wait_for_wmem(struct sock *sk, long timeo)
 {
 	DEFINE_WAIT(wait);
 
@@ -1392,6 +1401,7 @@
 {
 	return sock_alloc_send_pskb(sk, size, 0, noblock, errcode);
 }
+EXPORT_SYMBOL(sock_alloc_send_skb);
 
 static void __lock_sock(struct sock *sk)
 {
@@ -1460,7 +1470,6 @@
 	finish_wait(sk->sk_sleep, &wait);
 	return rc;
 }
-
 EXPORT_SYMBOL(sk_wait_data);
 
 /**
@@ -1541,7 +1550,6 @@
 	atomic_sub(amt, prot->memory_allocated);
 	return 0;
 }
-
 EXPORT_SYMBOL(__sk_mem_schedule);
 
 /**
@@ -1560,7 +1568,6 @@
 	    (atomic_read(prot->memory_allocated) < prot->sysctl_mem[0]))
 		*prot->memory_pressure = 0;
 }
-
 EXPORT_SYMBOL(__sk_mem_reclaim);
 
 
@@ -1575,78 +1582,92 @@
 {
 	return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_bind);
 
 int sock_no_connect(struct socket *sock, struct sockaddr *saddr,
 		    int len, int flags)
 {
 	return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_connect);
 
 int sock_no_socketpair(struct socket *sock1, struct socket *sock2)
 {
 	return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_socketpair);
 
 int sock_no_accept(struct socket *sock, struct socket *newsock, int flags)
 {
 	return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_accept);
 
 int sock_no_getname(struct socket *sock, struct sockaddr *saddr,
 		    int *len, int peer)
 {
 	return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_getname);
 
-unsigned int sock_no_poll(struct file * file, struct socket *sock, poll_table *pt)
+unsigned int sock_no_poll(struct file *file, struct socket *sock, poll_table *pt)
 {
 	return 0;
 }
+EXPORT_SYMBOL(sock_no_poll);
 
 int sock_no_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
 	return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_ioctl);
 
 int sock_no_listen(struct socket *sock, int backlog)
 {
 	return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_listen);
 
 int sock_no_shutdown(struct socket *sock, int how)
 {
 	return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_shutdown);
 
 int sock_no_setsockopt(struct socket *sock, int level, int optname,
 		    char __user *optval, int optlen)
 {
 	return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_setsockopt);
 
 int sock_no_getsockopt(struct socket *sock, int level, int optname,
 		    char __user *optval, int __user *optlen)
 {
 	return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_getsockopt);
 
 int sock_no_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
 		    size_t len)
 {
 	return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_sendmsg);
 
 int sock_no_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
 		    size_t len, int flags)
 {
 	return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_recvmsg);
 
 int sock_no_mmap(struct file *file, struct socket *sock, struct vm_area_struct *vma)
 {
 	/* Mirror missing mmap method error code */
 	return -ENODEV;
 }
+EXPORT_SYMBOL(sock_no_mmap);
 
 ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags)
 {
@@ -1660,6 +1681,7 @@
 	kunmap(page);
 	return res;
 }
+EXPORT_SYMBOL(sock_no_sendpage);
 
 /*
  *	Default Socket Callbacks
@@ -1723,6 +1745,7 @@
 		if (send_sigurg(&sk->sk_socket->file->f_owner))
 			sk_wake_async(sk, SOCK_WAKE_URG, POLL_PRI);
 }
+EXPORT_SYMBOL(sk_send_sigurg);
 
 void sk_reset_timer(struct sock *sk, struct timer_list* timer,
 		    unsigned long expires)
@@ -1730,7 +1753,6 @@
 	if (!mod_timer(timer, expires))
 		sock_hold(sk);
 }
-
 EXPORT_SYMBOL(sk_reset_timer);
 
 void sk_stop_timer(struct sock *sk, struct timer_list* timer)
@@ -1738,7 +1760,6 @@
 	if (timer_pending(timer) && del_timer(timer))
 		__sock_put(sk);
 }
-
 EXPORT_SYMBOL(sk_stop_timer);
 
 void sock_init_data(struct socket *sock, struct sock *sk)
@@ -1797,6 +1818,7 @@
 	atomic_set(&sk->sk_refcnt, 1);
 	atomic_set(&sk->sk_drops, 0);
 }
+EXPORT_SYMBOL(sock_init_data);
 
 void lock_sock_nested(struct sock *sk, int subclass)
 {
@@ -1812,7 +1834,6 @@
 	mutex_acquire(&sk->sk_lock.dep_map, subclass, 0, _RET_IP_);
 	local_bh_enable();
 }
-
 EXPORT_SYMBOL(lock_sock_nested);
 
 void release_sock(struct sock *sk)
@@ -1895,7 +1916,6 @@
 
 	return sk->sk_prot->getsockopt(sk, level, optname, optval, optlen);
 }
-
 EXPORT_SYMBOL(sock_common_getsockopt);
 
 #ifdef CONFIG_COMPAT
@@ -1925,7 +1945,6 @@
 		msg->msg_namelen = addr_len;
 	return err;
 }
-
 EXPORT_SYMBOL(sock_common_recvmsg);
 
 /*
@@ -1938,7 +1957,6 @@
 
 	return sk->sk_prot->setsockopt(sk, level, optname, optval, optlen);
 }
-
 EXPORT_SYMBOL(sock_common_setsockopt);
 
 #ifdef CONFIG_COMPAT
@@ -1989,7 +2007,6 @@
 	sk_refcnt_debug_release(sk);
 	sock_put(sk);
 }
-
 EXPORT_SYMBOL(sk_common_release);
 
 static DEFINE_RWLOCK(proto_list_lock);
@@ -2171,7 +2188,6 @@
 out:
 	return -ENOBUFS;
 }
-
 EXPORT_SYMBOL(proto_register);
 
 void proto_unregister(struct proto *prot)
@@ -2198,7 +2214,6 @@
 		prot->twsk_prot->twsk_slab = NULL;
 	}
 }
-
 EXPORT_SYMBOL(proto_unregister);
 
 #ifdef CONFIG_PROC_FS
@@ -2324,33 +2339,3 @@
 subsys_initcall(proto_init);
 
 #endif /* PROC_FS */
-
-EXPORT_SYMBOL(sk_alloc);
-EXPORT_SYMBOL(sk_free);
-EXPORT_SYMBOL(sk_send_sigurg);
-EXPORT_SYMBOL(sock_alloc_send_skb);
-EXPORT_SYMBOL(sock_init_data);
-EXPORT_SYMBOL(sock_kfree_s);
-EXPORT_SYMBOL(sock_kmalloc);
-EXPORT_SYMBOL(sock_no_accept);
-EXPORT_SYMBOL(sock_no_bind);
-EXPORT_SYMBOL(sock_no_connect);
-EXPORT_SYMBOL(sock_no_getname);
-EXPORT_SYMBOL(sock_no_getsockopt);
-EXPORT_SYMBOL(sock_no_ioctl);
-EXPORT_SYMBOL(sock_no_listen);
-EXPORT_SYMBOL(sock_no_mmap);
-EXPORT_SYMBOL(sock_no_poll);
-EXPORT_SYMBOL(sock_no_recvmsg);
-EXPORT_SYMBOL(sock_no_sendmsg);
-EXPORT_SYMBOL(sock_no_sendpage);
-EXPORT_SYMBOL(sock_no_setsockopt);
-EXPORT_SYMBOL(sock_no_shutdown);
-EXPORT_SYMBOL(sock_no_socketpair);
-EXPORT_SYMBOL(sock_rfree);
-EXPORT_SYMBOL(sock_setsockopt);
-EXPORT_SYMBOL(sock_wfree);
-EXPORT_SYMBOL(sock_wmalloc);
-EXPORT_SYMBOL(sock_i_uid);
-EXPORT_SYMBOL(sock_i_ino);
-EXPORT_SYMBOL(sysctl_optmem_max);
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 9647d91..bccb388 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -1250,14 +1250,8 @@
 		if (skb) {
 			amount = skb->len;
 		} else {
-			skb = sk->sk_receive_queue.next;
-			for (;;) {
-				if (skb ==
-				    (struct sk_buff *)&sk->sk_receive_queue)
-					break;
+			skb_queue_walk(&sk->sk_receive_queue, skb)
 				amount += skb->len;
-				skb = skb->next;
-			}
 		}
 		release_sock(sk);
 		err = put_user(amount, (int __user *)arg);
@@ -1644,13 +1638,13 @@
 
 static int dn_data_ready(struct sock *sk, struct sk_buff_head *q, int flags, int target)
 {
-	struct sk_buff *skb = q->next;
+	struct sk_buff *skb;
 	int len = 0;
 
 	if (flags & MSG_OOB)
 		return !skb_queue_empty(q) ? 1 : 0;
 
-	while(skb != (struct sk_buff *)q) {
+	skb_queue_walk(q, skb) {
 		struct dn_skb_cb *cb = DN_SKB_CB(skb);
 		len += skb->len;
 
@@ -1666,8 +1660,6 @@
 		/* minimum data length for read exceeded */
 		if (len >= target)
 			return 1;
-
-		skb = skb->next;
 	}
 
 	return 0;
@@ -1683,7 +1675,7 @@
 	size_t target = size > 1 ? 1 : 0;
 	size_t copied = 0;
 	int rv = 0;
-	struct sk_buff *skb, *nskb;
+	struct sk_buff *skb, *n;
 	struct dn_skb_cb *cb = NULL;
 	unsigned char eor = 0;
 	long timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
@@ -1758,7 +1750,7 @@
 		finish_wait(sk->sk_sleep, &wait);
 	}
 
-	for(skb = queue->next; skb != (struct sk_buff *)queue; skb = nskb) {
+	skb_queue_walk_safe(queue, skb, n) {
 		unsigned int chunk = skb->len;
 		cb = DN_SKB_CB(skb);
 
@@ -1775,7 +1767,6 @@
 			skb_pull(skb, chunk);
 
 		eor = cb->nsp_flags & 0x40;
-		nskb = skb->next;
 
 		if (skb->len == 0) {
 			skb_unlink(skb, queue);
diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c
index 2013c25..da04f45 100644
--- a/net/decnet/dn_nsp_out.c
+++ b/net/decnet/dn_nsp_out.c
@@ -382,7 +382,7 @@
 {
 	struct dn_skb_cb *cb = DN_SKB_CB(skb);
 	struct dn_scp *scp = DN_SK(sk);
-	struct sk_buff *skb2, *list, *ack = NULL;
+	struct sk_buff *skb2, *n, *ack = NULL;
 	int wakeup = 0;
 	int try_retrans = 0;
 	unsigned long reftime = cb->stamp;
@@ -390,9 +390,7 @@
 	unsigned short xmit_count;
 	unsigned short segnum;
 
-	skb2 = q->next;
-	list = (struct sk_buff *)q;
-	while(list != skb2) {
+	skb_queue_walk_safe(q, skb2, n) {
 		struct dn_skb_cb *cb2 = DN_SKB_CB(skb2);
 
 		if (dn_before_or_equal(cb2->segnum, acknum))
@@ -400,8 +398,6 @@
 
 		/* printk(KERN_DEBUG "ack: %s %04x %04x\n", ack ? "ACK" : "SKIP", (int)cb2->segnum, (int)acknum); */
 
-		skb2 = skb2->next;
-
 		if (ack == NULL)
 			continue;
 
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
index 6f479fa..8121bf0 100644
--- a/net/econet/af_econet.c
+++ b/net/econet/af_econet.c
@@ -901,15 +901,10 @@
 	struct ec_cb *eb;
 
 	spin_lock_irqsave(&aun_queue_lock, flags);
-	skb = skb_peek(&aun_queue);
-	while (skb && skb != (struct sk_buff *)&aun_queue)
-	{
-		struct sk_buff *newskb = skb->next;
+	skb_queue_walk(&aun_queue, skb) {
 		eb = (struct ec_cb *)&skb->cb;
 		if (eb->seq == seq)
 			goto foundit;
-
-		skb = newskb;
 	}
 	spin_unlock_irqrestore(&aun_queue_lock, flags);
 	printk(KERN_DEBUG "AUN: unknown sequence %ld\n", seq);
@@ -982,23 +977,18 @@
 
 static void ab_cleanup(unsigned long h)
 {
-	struct sk_buff *skb;
+	struct sk_buff *skb, *n;
 	unsigned long flags;
 
 	spin_lock_irqsave(&aun_queue_lock, flags);
-	skb = skb_peek(&aun_queue);
-	while (skb && skb != (struct sk_buff *)&aun_queue)
-	{
-		struct sk_buff *newskb = skb->next;
+	skb_queue_walk_safe(&aun_queue, skb, n) {
 		struct ec_cb *eb = (struct ec_cb *)&skb->cb;
-		if ((jiffies - eb->start) > eb->timeout)
-		{
+		if ((jiffies - eb->start) > eb->timeout) {
 			tx_result(skb->sk, eb->cookie,
 				  ECTYPE_TRANSMIT_NOT_PRESENT);
 			skb_unlink(skb, &aun_queue);
 			kfree_skb(skb);
 		}
-		skb = newskb;
 	}
 	spin_unlock_irqrestore(&aun_queue_lock, flags);
 
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index 280352a..5a883af 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -337,11 +337,6 @@
 void ether_setup(struct net_device *dev)
 {
 	dev->header_ops		= &eth_header_ops;
-#ifdef CONFIG_COMPAT_NET_DEV_OPS
-	dev->change_mtu		= eth_change_mtu;
-	dev->set_mac_address 	= eth_mac_addr;
-	dev->validate_addr	= eth_validate_addr;
-#endif
 	dev->type		= ARPHRD_ETHER;
 	dev->hard_header_len 	= ETH_HLEN;
 	dev->mtu		= ETH_DATA_LEN;
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index 9d26a3d..5b919f7 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -408,7 +408,7 @@
 
 config INET_LRO
 	bool "Large Receive Offload (ipv4/tcp)"
-
+	default y
 	---help---
 	  Support for Large Receive Offload (ipv4/tcp).
 
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 1706896..5abee4c 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1246,13 +1246,20 @@
 	struct sk_buff **pp = NULL;
 	struct sk_buff *p;
 	struct iphdr *iph;
+	unsigned int hlen;
+	unsigned int off;
+	unsigned int id;
 	int flush = 1;
 	int proto;
-	int id;
 
-	iph = skb_gro_header(skb, sizeof(*iph));
-	if (unlikely(!iph))
-		goto out;
+	off = skb_gro_offset(skb);
+	hlen = off + sizeof(*iph);
+	iph = skb_gro_header_fast(skb, off);
+	if (skb_gro_header_hard(skb, hlen)) {
+		iph = skb_gro_header_slow(skb, hlen, off);
+		if (unlikely(!iph))
+			goto out;
+	}
 
 	proto = iph->protocol & (MAX_INET_PROTOS - 1);
 
@@ -1267,9 +1274,9 @@
 	if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
 		goto out_unlock;
 
-	flush = ntohs(iph->tot_len) != skb_gro_len(skb) ||
-		iph->frag_off != htons(IP_DF);
-	id = ntohs(iph->id);
+	id = ntohl(*(u32 *)&iph->id);
+	flush = (u16)((ntohl(*(u32 *)iph) ^ skb_gro_len(skb)) | (id ^ IP_DF));
+	id >>= 16;
 
 	for (p = *head; p; p = p->next) {
 		struct iphdr *iph2;
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 9070d11..538d2a9 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -986,9 +986,12 @@
 static struct node *trie_rebalance(struct trie *t, struct tnode *tn)
 {
 	int wasfull;
-	t_key cindex, key = tn->key;
+	t_key cindex, key;
 	struct tnode *tp;
 
+	preempt_disable();
+	key = tn->key;
+
 	while (tn != NULL && (tp = node_parent((struct node *)tn)) != NULL) {
 		cindex = tkey_extract_bits(key, tp->pos, tp->bits);
 		wasfull = tnode_full(tp, tnode_get_child(tp, cindex));
@@ -1007,6 +1010,7 @@
 	if (IS_TNODE(tn))
 		tn = (struct tnode *)resize(t, (struct tnode *)tn);
 
+	preempt_enable();
 	return (struct node *)tn;
 }
 
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index c4c60e9..28205e5 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -784,8 +784,8 @@
 {
 	static unsigned int rover;
 	unsigned int i = rover, goal;
-	struct rtable *rth, **rthp;
-	unsigned long length = 0, samples = 0;
+	struct rtable *rth, *aux, **rthp;
+	unsigned long samples = 0;
 	unsigned long sum = 0, sum2 = 0;
 	u64 mult;
 
@@ -795,9 +795,9 @@
 	goal = (unsigned int)mult;
 	if (goal > rt_hash_mask)
 		goal = rt_hash_mask + 1;
-	length = 0;
 	for (; goal > 0; goal--) {
 		unsigned long tmo = ip_rt_gc_timeout;
+		unsigned long length;
 
 		i = (i + 1) & rt_hash_mask;
 		rthp = &rt_hash_table[i].chain;
@@ -809,8 +809,10 @@
 
 		if (*rthp == NULL)
 			continue;
+		length = 0;
 		spin_lock_bh(rt_hash_lock_addr(i));
 		while ((rth = *rthp) != NULL) {
+			prefetch(rth->u.dst.rt_next);
 			if (rt_is_expired(rth)) {
 				*rthp = rth->u.dst.rt_next;
 				rt_free(rth);
@@ -819,33 +821,30 @@
 			if (rth->u.dst.expires) {
 				/* Entry is expired even if it is in use */
 				if (time_before_eq(jiffies, rth->u.dst.expires)) {
+nofree:
 					tmo >>= 1;
 					rthp = &rth->u.dst.rt_next;
 					/*
-					 * Only bump our length if the hash
-					 * inputs on entries n and n+1 are not
-					 * the same, we only count entries on
+					 * We only count entries on
 					 * a chain with equal hash inputs once
 					 * so that entries for different QOS
 					 * levels, and other non-hash input
 					 * attributes don't unfairly skew
 					 * the length computation
 					 */
-					if ((*rthp == NULL) ||
-					    !compare_hash_inputs(&(*rthp)->fl,
-								 &rth->fl))
-						length += ONE;
+					for (aux = rt_hash_table[i].chain;;) {
+						if (aux == rth) {
+							length += ONE;
+							break;
+						}
+						if (compare_hash_inputs(&aux->fl, &rth->fl))
+							break;
+						aux = aux->u.dst.rt_next;
+					}
 					continue;
 				}
-			} else if (!rt_may_expire(rth, tmo, ip_rt_gc_timeout)) {
-				tmo >>= 1;
-				rthp = &rth->u.dst.rt_next;
-				if ((*rthp == NULL) ||
-				    !compare_hash_inputs(&(*rthp)->fl,
-							 &rth->fl))
-					length += ONE;
-				continue;
-			}
+			} else if (!rt_may_expire(rth, tmo, ip_rt_gc_timeout))
+				goto nofree;
 
 			/* Cleanup aged off entries. */
 			*rthp = rth->u.dst.rt_next;
@@ -1068,7 +1067,6 @@
 static int rt_intern_hash(unsigned hash, struct rtable *rt, struct rtable **rp)
 {
 	struct rtable	*rth, **rthp;
-	struct rtable	*rthi;
 	unsigned long	now;
 	struct rtable *cand, **candp;
 	u32 		min_score;
@@ -1088,7 +1086,6 @@
 	}
 
 	rthp = &rt_hash_table[hash].chain;
-	rthi = NULL;
 
 	spin_lock_bh(rt_hash_lock_addr(hash));
 	while ((rth = *rthp) != NULL) {
@@ -1134,17 +1131,6 @@
 		chain_length++;
 
 		rthp = &rth->u.dst.rt_next;
-
-		/*
-		 * check to see if the next entry in the chain
-		 * contains the same hash input values as rt.  If it does
-		 * This is where we will insert into the list, instead of
-		 * at the head.  This groups entries that differ by aspects not
-		 * relvant to the hash function together, which we use to adjust
-		 * our chain length
-		 */
-		if (*rthp && compare_hash_inputs(&(*rthp)->fl, &rt->fl))
-			rthi = rth;
 	}
 
 	if (cand) {
@@ -1205,10 +1191,7 @@
 		}
 	}
 
-	if (rthi)
-		rt->u.dst.rt_next = rthi->u.dst.rt_next;
-	else
-		rt->u.dst.rt_next = rt_hash_table[hash].chain;
+	rt->u.dst.rt_next = rt_hash_table[hash].chain;
 
 #if RT_CACHE_DEBUG >= 2
 	if (rt->u.dst.rt_next) {
@@ -1224,10 +1207,7 @@
 	 * previous writes to rt are comitted to memory
 	 * before making rt visible to other CPUS.
 	 */
-	if (rthi)
-		rcu_assign_pointer(rthi->u.dst.rt_next, rt);
-	else
-		rcu_assign_pointer(rt_hash_table[hash].chain, rt);
+	rcu_assign_pointer(rt_hash_table[hash].chain, rt);
 
 	spin_unlock_bh(rt_hash_lock_addr(hash));
 	*rp = rt;
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 7a0f0b2..17b89c5 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -439,12 +439,14 @@
 			 !tp->urg_data ||
 			 before(tp->urg_seq, tp->copied_seq) ||
 			 !before(tp->urg_seq, tp->rcv_nxt)) {
+			struct sk_buff *skb;
+
 			answ = tp->rcv_nxt - tp->copied_seq;
 
 			/* Subtract 1, if FIN is in queue. */
-			if (answ && !skb_queue_empty(&sk->sk_receive_queue))
-				answ -=
-		       tcp_hdr((struct sk_buff *)sk->sk_receive_queue.prev)->fin;
+			skb = skb_peek_tail(&sk->sk_receive_queue);
+			if (answ && skb)
+				answ -= tcp_hdr(skb)->fin;
 		} else
 			answ = tp->urg_seq - tp->copied_seq;
 		release_sock(sk);
@@ -1382,11 +1384,7 @@
 
 		/* Next get a buffer. */
 
-		skb = skb_peek(&sk->sk_receive_queue);
-		do {
-			if (!skb)
-				break;
-
+		skb_queue_walk(&sk->sk_receive_queue, skb) {
 			/* Now that we have two receive queues this
 			 * shouldn't happen.
 			 */
@@ -1403,8 +1401,7 @@
 			if (tcp_hdr(skb)->fin)
 				goto found_fin_ok;
 			WARN_ON(!(flags & MSG_PEEK));
-			skb = skb->next;
-		} while (skb != (struct sk_buff *)&sk->sk_receive_queue);
+		}
 
 		/* Well, if we have backlog, try to process it now yet. */
 
@@ -2518,20 +2515,30 @@
 	unsigned int thlen;
 	unsigned int flags;
 	unsigned int mss = 1;
+	unsigned int hlen;
+	unsigned int off;
 	int flush = 1;
 	int i;
 
-	th = skb_gro_header(skb, sizeof(*th));
-	if (unlikely(!th))
-		goto out;
+	off = skb_gro_offset(skb);
+	hlen = off + sizeof(*th);
+	th = skb_gro_header_fast(skb, off);
+	if (skb_gro_header_hard(skb, hlen)) {
+		th = skb_gro_header_slow(skb, hlen, off);
+		if (unlikely(!th))
+			goto out;
+	}
 
 	thlen = th->doff * 4;
 	if (thlen < sizeof(*th))
 		goto out;
 
-	th = skb_gro_header(skb, thlen);
-	if (unlikely(!th))
-		goto out;
+	hlen = off + thlen;
+	if (skb_gro_header_hard(skb, hlen)) {
+		th = skb_gro_header_slow(skb, hlen, off);
+		if (unlikely(!th))
+			goto out;
+	}
 
 	skb_gro_pull(skb, thlen);
 
@@ -2544,7 +2551,7 @@
 
 		th2 = tcp_hdr(p);
 
-		if ((th->source ^ th2->source) | (th->dest ^ th2->dest)) {
+		if (*(u32 *)&th->source ^ *(u32 *)&th2->source) {
 			NAPI_GRO_CB(p)->same_flow = 0;
 			continue;
 		}
@@ -2559,14 +2566,14 @@
 	flush |= flags & TCP_FLAG_CWR;
 	flush |= (flags ^ tcp_flag_word(th2)) &
 		  ~(TCP_FLAG_CWR | TCP_FLAG_FIN | TCP_FLAG_PSH);
-	flush |= (th->ack_seq ^ th2->ack_seq) | (th->window ^ th2->window);
-	for (i = sizeof(*th); !flush && i < thlen; i += 4)
+	flush |= th->ack_seq ^ th2->ack_seq;
+	for (i = sizeof(*th); i < thlen; i += 4)
 		flush |= *(u32 *)((u8 *)th + i) ^
 			 *(u32 *)((u8 *)th2 + i);
 
 	mss = skb_shinfo(p)->gso_size;
 
-	flush |= (len > mss) | !len;
+	flush |= (len - 1) >= mss;
 	flush |= (ntohl(th2->seq) + skb_gro_len(p)) ^ ntohl(th->seq);
 
 	if (flush || skb_gro_receive(head, skb)) {
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index eeb8a92..ba34a23 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4426,7 +4426,7 @@
 		}
 		__skb_queue_head(&tp->out_of_order_queue, skb);
 	} else {
-		struct sk_buff *skb1 = tp->out_of_order_queue.prev;
+		struct sk_buff *skb1 = skb_peek_tail(&tp->out_of_order_queue);
 		u32 seq = TCP_SKB_CB(skb)->seq;
 		u32 end_seq = TCP_SKB_CB(skb)->end_seq;
 
@@ -4443,15 +4443,18 @@
 		}
 
 		/* Find place to insert this segment. */
-		do {
+		while (1) {
 			if (!after(TCP_SKB_CB(skb1)->seq, seq))
 				break;
-		} while ((skb1 = skb1->prev) !=
-			 (struct sk_buff *)&tp->out_of_order_queue);
+			if (skb_queue_is_first(&tp->out_of_order_queue, skb1)) {
+				skb1 = NULL;
+				break;
+			}
+			skb1 = skb_queue_prev(&tp->out_of_order_queue, skb1);
+		}
 
 		/* Do skb overlap to previous one? */
-		if (skb1 != (struct sk_buff *)&tp->out_of_order_queue &&
-		    before(seq, TCP_SKB_CB(skb1)->end_seq)) {
+		if (skb1 && before(seq, TCP_SKB_CB(skb1)->end_seq)) {
 			if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq)) {
 				/* All the bits are present. Drop. */
 				__kfree_skb(skb);
@@ -4463,24 +4466,41 @@
 				tcp_dsack_set(sk, seq,
 					      TCP_SKB_CB(skb1)->end_seq);
 			} else {
-				skb1 = skb1->prev;
+				if (skb_queue_is_first(&tp->out_of_order_queue,
+						       skb1))
+					skb1 = NULL;
+				else
+					skb1 = skb_queue_prev(
+						&tp->out_of_order_queue,
+						skb1);
 			}
 		}
-		__skb_queue_after(&tp->out_of_order_queue, skb1, skb);
+		if (!skb1)
+			__skb_queue_head(&tp->out_of_order_queue, skb);
+		else
+			__skb_queue_after(&tp->out_of_order_queue, skb1, skb);
 
 		/* And clean segments covered by new one as whole. */
-		while ((skb1 = skb->next) !=
-		       (struct sk_buff *)&tp->out_of_order_queue &&
-		       after(end_seq, TCP_SKB_CB(skb1)->seq)) {
-			if (before(end_seq, TCP_SKB_CB(skb1)->end_seq)) {
+		if (skb1 && !skb_queue_is_last(&tp->out_of_order_queue, skb1)) {
+			struct sk_buff *n;
+
+			skb1 = skb_queue_next(&tp->out_of_order_queue, skb1);
+			skb_queue_walk_from_safe(&tp->out_of_order_queue,
+						 skb1, n) {
+				if (!after(end_seq, TCP_SKB_CB(skb1)->seq))
+					break;
+				if (before(end_seq,
+					   TCP_SKB_CB(skb1)->end_seq)) {
+					tcp_dsack_extend(sk,
+							 TCP_SKB_CB(skb1)->seq,
+							 end_seq);
+					break;
+				}
+				__skb_unlink(skb1, &tp->out_of_order_queue);
 				tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq,
-						 end_seq);
-				break;
+						 TCP_SKB_CB(skb1)->end_seq);
+				__kfree_skb(skb1);
 			}
-			__skb_unlink(skb1, &tp->out_of_order_queue);
-			tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq,
-					 TCP_SKB_CB(skb1)->end_seq);
-			__kfree_skb(skb1);
 		}
 
 add_sack:
@@ -4492,7 +4512,10 @@
 static struct sk_buff *tcp_collapse_one(struct sock *sk, struct sk_buff *skb,
 					struct sk_buff_head *list)
 {
-	struct sk_buff *next = skb->next;
+	struct sk_buff *next = NULL;
+
+	if (!skb_queue_is_last(list, skb))
+		next = skb_queue_next(list, skb);
 
 	__skb_unlink(skb, list);
 	__kfree_skb(skb);
@@ -4503,6 +4526,9 @@
 
 /* Collapse contiguous sequence of skbs head..tail with
  * sequence numbers start..end.
+ *
+ * If tail is NULL, this means until the end of the list.
+ *
  * Segments with FIN/SYN are not collapsed (only because this
  * simplifies code)
  */
@@ -4511,15 +4537,23 @@
 	     struct sk_buff *head, struct sk_buff *tail,
 	     u32 start, u32 end)
 {
-	struct sk_buff *skb;
+	struct sk_buff *skb, *n;
+	bool end_of_skbs;
 
 	/* First, check that queue is collapsible and find
 	 * the point where collapsing can be useful. */
-	for (skb = head; skb != tail;) {
+	skb = head;
+restart:
+	end_of_skbs = true;
+	skb_queue_walk_from_safe(list, skb, n) {
+		if (skb == tail)
+			break;
 		/* No new bits? It is possible on ofo queue. */
 		if (!before(start, TCP_SKB_CB(skb)->end_seq)) {
 			skb = tcp_collapse_one(sk, skb, list);
-			continue;
+			if (!skb)
+				break;
+			goto restart;
 		}
 
 		/* The first skb to collapse is:
@@ -4529,16 +4563,24 @@
 		 */
 		if (!tcp_hdr(skb)->syn && !tcp_hdr(skb)->fin &&
 		    (tcp_win_from_space(skb->truesize) > skb->len ||
-		     before(TCP_SKB_CB(skb)->seq, start) ||
-		     (skb->next != tail &&
-		      TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb->next)->seq)))
+		     before(TCP_SKB_CB(skb)->seq, start))) {
+			end_of_skbs = false;
 			break;
+		}
+
+		if (!skb_queue_is_last(list, skb)) {
+			struct sk_buff *next = skb_queue_next(list, skb);
+			if (next != tail &&
+			    TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(next)->seq) {
+				end_of_skbs = false;
+				break;
+			}
+		}
 
 		/* Decided to skip this, advance start seq. */
 		start = TCP_SKB_CB(skb)->end_seq;
-		skb = skb->next;
 	}
-	if (skb == tail || tcp_hdr(skb)->syn || tcp_hdr(skb)->fin)
+	if (end_of_skbs || tcp_hdr(skb)->syn || tcp_hdr(skb)->fin)
 		return;
 
 	while (before(start, end)) {
@@ -4583,7 +4625,8 @@
 			}
 			if (!before(start, TCP_SKB_CB(skb)->end_seq)) {
 				skb = tcp_collapse_one(sk, skb, list);
-				if (skb == tail ||
+				if (!skb ||
+				    skb == tail ||
 				    tcp_hdr(skb)->syn ||
 				    tcp_hdr(skb)->fin)
 					return;
@@ -4610,17 +4653,21 @@
 	head = skb;
 
 	for (;;) {
-		skb = skb->next;
+		struct sk_buff *next = NULL;
+
+		if (!skb_queue_is_last(&tp->out_of_order_queue, skb))
+			next = skb_queue_next(&tp->out_of_order_queue, skb);
+		skb = next;
 
 		/* Segment is terminated when we see gap or when
 		 * we are at the end of all the queue. */
-		if (skb == (struct sk_buff *)&tp->out_of_order_queue ||
+		if (!skb ||
 		    after(TCP_SKB_CB(skb)->seq, end) ||
 		    before(TCP_SKB_CB(skb)->end_seq, start)) {
 			tcp_collapse(sk, &tp->out_of_order_queue,
 				     head, skb, start, end);
 			head = skb;
-			if (skb == (struct sk_buff *)&tp->out_of_order_queue)
+			if (!skb)
 				break;
 			/* Start new segment */
 			start = TCP_SKB_CB(skb)->seq;
@@ -4681,10 +4728,11 @@
 		tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4U * tp->advmss);
 
 	tcp_collapse_ofo_queue(sk);
-	tcp_collapse(sk, &sk->sk_receive_queue,
-		     sk->sk_receive_queue.next,
-		     (struct sk_buff *)&sk->sk_receive_queue,
-		     tp->copied_seq, tp->rcv_nxt);
+	if (!skb_queue_empty(&sk->sk_receive_queue))
+		tcp_collapse(sk, &sk->sk_receive_queue,
+			     skb_peek(&sk->sk_receive_queue),
+			     NULL,
+			     tp->copied_seq, tp->rcv_nxt);
 	sk_mem_reclaim(sk);
 
 	if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf)
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 61f5538..b6215be 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -817,13 +817,20 @@
 	struct sk_buff *p;
 	struct ipv6hdr *iph;
 	unsigned int nlen;
+	unsigned int hlen;
+	unsigned int off;
 	int flush = 1;
 	int proto;
 	__wsum csum;
 
-	iph = skb_gro_header(skb, sizeof(*iph));
-	if (unlikely(!iph))
-		goto out;
+	off = skb_gro_offset(skb);
+	hlen = off + sizeof(*iph);
+	iph = skb_gro_header_fast(skb, off);
+	if (skb_gro_header_hard(skb, hlen)) {
+		iph = skb_gro_header_slow(skb, hlen, off);
+		if (unlikely(!iph))
+			goto out;
+	}
 
 	skb_gro_pull(skb, sizeof(*iph));
 	skb_set_transport_header(skb, skb_gro_offset(skb));
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 1394ddb..032a5ec 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -137,6 +137,7 @@
 		}
 	},
 	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
+	.rt6i_protocol  = RTPROT_KERNEL,
 	.rt6i_metric	= ~(u32) 0,
 	.rt6i_ref	= ATOMIC_INIT(1),
 };
@@ -159,6 +160,7 @@
 		}
 	},
 	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
+	.rt6i_protocol  = RTPROT_KERNEL,
 	.rt6i_metric	= ~(u32) 0,
 	.rt6i_ref	= ATOMIC_INIT(1),
 };
@@ -176,6 +178,7 @@
 		}
 	},
 	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
+	.rt6i_protocol  = RTPROT_KERNEL,
 	.rt6i_metric	= ~(u32) 0,
 	.rt6i_ref	= ATOMIC_INIT(1),
 };
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index d9dd94b..ea37741 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -941,7 +941,8 @@
 	return 0;
 }
 
-struct sk_buff **tcp6_gro_receive(struct sk_buff **head, struct sk_buff *skb)
+static struct sk_buff **tcp6_gro_receive(struct sk_buff **head,
+					 struct sk_buff *skb)
 {
 	struct ipv6hdr *iph = skb_gro_network_header(skb);
 
@@ -961,9 +962,8 @@
 
 	return tcp_gro_receive(head, skb);
 }
-EXPORT_SYMBOL(tcp6_gro_receive);
 
-int tcp6_gro_complete(struct sk_buff *skb)
+static int tcp6_gro_complete(struct sk_buff *skb)
 {
 	struct ipv6hdr *iph = ipv6_hdr(skb);
 	struct tcphdr *th = tcp_hdr(skb);
@@ -974,7 +974,6 @@
 
 	return tcp_gro_complete(skb);
 }
-EXPORT_SYMBOL(tcp6_gro_complete);
 
 static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
 				 u32 ts, struct tcp_md5sig_key *key, int rst)
diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c
index 2562ebc..7af2e74 100644
--- a/net/irda/irlap_frame.c
+++ b/net/irda/irlap_frame.c
@@ -982,17 +982,12 @@
 {
 	struct sk_buff *tx_skb;
 	struct sk_buff *skb;
-	int count;
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
-	/* Initialize variables */
-	count = skb_queue_len(&self->wx_list);
-
 	/*  Resend unacknowledged frame(s) */
-	skb = skb_peek(&self->wx_list);
-	while (skb != NULL) {
+	skb_queue_walk(&self->wx_list, skb) {
 		irlap_wait_min_turn_around(self, &self->qos_tx);
 
 		/* We copy the skb to be retransmitted since we will have to
@@ -1011,21 +1006,12 @@
 		/*
 		 *  Set poll bit on the last frame retransmitted
 		 */
-		if (count-- == 1)
+		if (skb_queue_is_last(&self->wx_list, skb))
 			tx_skb->data[1] |= PF_BIT; /* Set p/f bit */
 		else
 			tx_skb->data[1] &= ~PF_BIT; /* Clear p/f bit */
 
 		irlap_send_i_frame(self, tx_skb, command);
-
-		/*
-		 *  If our skb is the last buffer in the list, then
-		 *  we are finished, if not, move to the next sk-buffer
-		 */
-		if (skb == skb_peek_tail(&self->wx_list))
-			skb = NULL;
-		else
-			skb = skb->next;
 	}
 #if 0 /* Not yet */
 	/*
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c
index 3477624..c6bab39 100644
--- a/net/llc/llc_conn.c
+++ b/net/llc/llc_conn.c
@@ -79,10 +79,6 @@
 
 	if (unlikely(!ev->ind_prim && !ev->cfm_prim)) {
 		/* indicate or confirm not required */
-		/* XXX this is not very pretty, perhaps we should store
-		 * XXX indicate/confirm-needed state in the llc_conn_state_ev
-		 * XXX control block of the SKB instead? -DaveM
-		 */
 		if (!skb->next)
 			goto out_kfree_skb;
 		goto out_skb_put;
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index e7682fe..11c7231 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -52,14 +52,6 @@
 
 DEBUGFS_READONLY_FILE(frequency, 20, "%d",
 		      local->hw.conf.channel->center_freq);
-DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d",
-		      local->hw.wiphy->rts_threshold);
-DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d",
-		      local->hw.wiphy->frag_threshold);
-DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d",
-		      local->hw.wiphy->retry_short);
-DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d",
-		      local->hw.wiphy->retry_long);
 DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d",
 		      local->total_ps_buffered);
 DEBUGFS_READONLY_FILE(wep_iv, 20, "%#08x",
@@ -303,10 +295,6 @@
 	local->debugfs.keys = debugfs_create_dir("keys", phyd);
 
 	DEBUGFS_ADD(frequency);
-	DEBUGFS_ADD(rts_threshold);
-	DEBUGFS_ADD(fragmentation_threshold);
-	DEBUGFS_ADD(short_retry_limit);
-	DEBUGFS_ADD(long_retry_limit);
 	DEBUGFS_ADD(total_ps_buffered);
 	DEBUGFS_ADD(wep_iv);
 	DEBUGFS_ADD(tsf);
@@ -359,10 +347,6 @@
 void debugfs_hw_del(struct ieee80211_local *local)
 {
 	DEBUGFS_DEL(frequency);
-	DEBUGFS_DEL(rts_threshold);
-	DEBUGFS_DEL(fragmentation_threshold);
-	DEBUGFS_DEL(short_retry_limit);
-	DEBUGFS_DEL(long_retry_limit);
 	DEBUGFS_DEL(total_ps_buffered);
 	DEBUGFS_DEL(wep_iv);
 	DEBUGFS_DEL(tsf);
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index c236079..0b30277 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -535,9 +535,9 @@
 		bssid = ifibss->bssid;
 	bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, bssid,
 				       ifibss->ssid, ifibss->ssid_len,
-				       capability,
 				       WLAN_CAPABILITY_IBSS |
-				       WLAN_CAPABILITY_PRIVACY);
+				       WLAN_CAPABILITY_PRIVACY,
+				       capability);
 
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
 	if (bss)
@@ -737,6 +737,9 @@
 	struct ieee80211_if_ibss *ifibss;
 	struct sk_buff *skb;
 
+	if (WARN_ON(local->suspended))
+		return;
+
 	if (!netif_running(sdata->dev))
 		return;
 
@@ -773,10 +776,36 @@
 	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
 	struct ieee80211_local *local = sdata->local;
 
+	if (local->quiescing) {
+		ifibss->timer_running = true;
+		return;
+	}
+
 	set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request);
 	queue_work(local->hw.workqueue, &ifibss->work);
 }
 
+#ifdef CONFIG_PM
+void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+
+	cancel_work_sync(&ifibss->work);
+	if (del_timer_sync(&ifibss->timer))
+		ifibss->timer_running = true;
+}
+
+void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+
+	if (ifibss->timer_running) {
+		add_timer(&ifibss->timer);
+		ifibss->timer_running = false;
+	}
+}
+#endif
+
 void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 9d15147..c088c46 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -293,6 +293,7 @@
 	int auth_tries; /* retries for auth req */
 	int assoc_tries; /* retries for assoc req */
 
+	unsigned long timers_running; /* used for quiesce/restart */
 	bool powersave; /* powersave requested for this iface */
 
 	unsigned long request;
@@ -333,6 +334,9 @@
 
 	unsigned long request;
 	unsigned long last_scan_completed;
+
+	bool timer_running;
+
 	bool fixed_bssid;
 	bool fixed_channel;
 
@@ -358,6 +362,8 @@
 	struct timer_list mesh_path_timer;
 	struct sk_buff_head skb_queue;
 
+	unsigned long timers_running;
+
 	bool housekeeping;
 
 	u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN];
@@ -609,6 +615,21 @@
 	unsigned int filter_flags; /* FIF_* */
 	struct iw_statistics wstats;
 	bool tim_in_locked_section; /* see ieee80211_beacon_get() */
+
+	/*
+	 * suspended is true if we finished all the suspend _and_ we have
+	 * not yet come up from resume. This is to be used by mac80211
+	 * to ensure driver sanity during suspend and mac80211's own
+	 * sanity. It can eventually be used for WoW as well.
+	 */
+	bool suspended;
+
+	/*
+	 * quiescing is true during the suspend process _only_ to
+	 * ease timer cancelling etc.
+	 */
+	bool quiescing;
+
 	int tx_headroom; /* required headroom for hardware/radiotap */
 
 	/* Tasklet and skb queue to process calls from IRQ mode. All frames
@@ -758,10 +779,6 @@
 		struct dentry *rcdir;
 		struct dentry *rcname;
 		struct dentry *frequency;
-		struct dentry *rts_threshold;
-		struct dentry *fragmentation_threshold;
-		struct dentry *short_retry_limit;
-		struct dentry *long_retry_limit;
 		struct dentry *total_ps_buffered;
 		struct dentry *wep_iv;
 		struct dentry *tsf;
@@ -938,6 +955,11 @@
 void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency);
 int ieee80211_max_network_latency(struct notifier_block *nb,
 				  unsigned long data, void *dummy);
+void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
+				      struct ieee80211_channel_sw_ie *sw_elem,
+				      struct ieee80211_bss *bss);
+void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata);
+void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);
 
 /* IBSS code */
 void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local);
@@ -950,6 +972,8 @@
 int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
 			struct cfg80211_ibss_params *params);
 int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata);
+void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata);
+void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata);
 
 /* scan/BSS handling */
 void ieee80211_scan_work(struct work_struct *work);
@@ -960,6 +984,7 @@
 int ieee80211_scan_results(struct ieee80211_local *local,
 			   struct iw_request_info *info,
 			   char *buf, size_t len);
+void ieee80211_scan_cancel(struct ieee80211_local *local);
 ieee80211_rx_result
 ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata,
 		  struct sk_buff *skb,
@@ -1035,14 +1060,6 @@
 void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
 				       struct ieee80211_mgmt *mgmt,
 				       size_t len);
-void ieee80211_chswitch_timer(unsigned long data);
-void ieee80211_chswitch_work(struct work_struct *work);
-void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata,
-				  struct ieee80211_channel_sw_ie *sw_elem,
-				  struct ieee80211_bss *bss);
-void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
-				 u16 capab_info, u8 *pwr_constr_elem,
-				 u8 pwr_constr_elem_len);
 
 /* Suspend/resume and hw reconfiguration */
 int ieee80211_reconfig(struct ieee80211_local *local);
@@ -1068,8 +1085,6 @@
 
 /* utility functions/constants */
 extern void *mac80211_wiphy_privid; /* for wiphy privid */
-extern const unsigned char rfc1042_header[6];
-extern const unsigned char bridge_tunnel_header[6];
 u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
 			enum nl80211_iftype type);
 int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 827ea8e..ce26756 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -320,7 +320,7 @@
 	case ALG_TKIP:
 		key->conf.iv_len = TKIP_IV_LEN;
 		key->conf.icv_len = TKIP_ICV_LEN;
-		if (seq && seq_len == 6) {
+		if (seq) {
 			for (i = 0; i < NUM_RX_DATA_QUEUES; i++) {
 				key->u.tkip.rx[i].iv32 =
 					get_unaligned_le32(&seq[2]);
@@ -332,7 +332,7 @@
 	case ALG_CCMP:
 		key->conf.iv_len = CCMP_HDR_LEN;
 		key->conf.icv_len = CCMP_MIC_LEN;
-		if (seq && seq_len == CCMP_PN_LEN) {
+		if (seq) {
 			for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
 				for (j = 0; j < CCMP_PN_LEN; j++)
 					key->u.ccmp.rx_pn[i][j] =
@@ -342,7 +342,7 @@
 	case ALG_AES_CMAC:
 		key->conf.iv_len = 0;
 		key->conf.icv_len = sizeof(struct ieee80211_mmie);
-		if (seq && seq_len == 6)
+		if (seq)
 			for (j = 0; j < 6; j++)
 				key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1];
 		break;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 76df5ea..e37770c 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -219,18 +219,26 @@
 				      u32 changed)
 {
 	struct ieee80211_local *local = sdata->local;
+	static const u8 zero[ETH_ALEN] = { 0 };
 
 	if (!changed)
 		return;
 
-	if (sdata->vif.type == NL80211_IFTYPE_STATION)
-		sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid;
-	else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
+	if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+		/*
+		 * While not associated, claim a BSSID of all-zeroes
+		 * so that drivers don't do any weird things with the
+		 * BSSID at that time.
+		 */
+		if (sdata->vif.bss_conf.assoc)
+			sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid;
+		else
+			sdata->vif.bss_conf.bssid = zero;
+	} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
 		sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid;
 	else if (sdata->vif.type == NL80211_IFTYPE_AP)
 		sdata->vif.bss_conf.bssid = sdata->dev->dev_addr;
 	else if (ieee80211_vif_is_mesh(&sdata->vif)) {
-		static const u8 zero[ETH_ALEN] = { 0 };
 		sdata->vif.bss_conf.bssid = zero;
 	} else {
 		WARN_ON(1);
@@ -727,9 +735,7 @@
 	 * +-------------------------+
 	 *
 	 */
-	priv_size = ((sizeof(struct ieee80211_local) +
-		      NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST) +
-		    priv_data_len;
+	priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len;
 
 	wiphy = wiphy_new(&mac80211_config_ops, priv_size);
 
@@ -746,9 +752,7 @@
 
 	local->hw.wiphy = wiphy;
 
-	local->hw.priv = (char *)local +
-			 ((sizeof(struct ieee80211_local) +
-			   NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
+	local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN);
 
 	BUG_ON(!ops->tx);
 	BUG_ON(!ops->start);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 9000b01..fc712e6 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -21,6 +21,9 @@
 #define CAPAB_OFFSET 17
 #define ACCEPT_PLINKS 0x80
 
+#define TMR_RUNNING_HK	0
+#define TMR_RUNNING_MP	1
+
 int mesh_allocated;
 static struct kmem_cache *rm_cache;
 
@@ -45,6 +48,12 @@
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 
 	ifmsh->housekeeping = true;
+
+	if (local->quiescing) {
+		set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
+		return;
+	}
+
 	queue_work(local->hw.workqueue, &ifmsh->work);
 }
 
@@ -343,6 +352,11 @@
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 	struct ieee80211_local *local = sdata->local;
 
+	if (local->quiescing) {
+		set_bit(TMR_RUNNING_MP, &ifmsh->timers_running);
+		return;
+	}
+
 	queue_work(local->hw.workqueue, &ifmsh->work);
 }
 
@@ -424,6 +438,32 @@
 		  round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
 }
 
+#ifdef CONFIG_PM
+void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+
+	/* might restart the timer but that doesn't matter */
+	cancel_work_sync(&ifmsh->work);
+
+	/* use atomic bitops in case both timers fire at the same time */
+
+	if (del_timer_sync(&ifmsh->housekeeping_timer))
+		set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
+	if (del_timer_sync(&ifmsh->mesh_path_timer))
+		set_bit(TMR_RUNNING_MP, &ifmsh->timers_running);
+}
+
+void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+
+	if (test_and_clear_bit(TMR_RUNNING_HK, &ifmsh->timers_running))
+		add_timer(&ifmsh->housekeeping_timer);
+	if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running))
+		add_timer(&ifmsh->mesh_path_timer);
+}
+#endif
 
 void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
 {
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index d891d7d..c7d7281 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -191,12 +191,8 @@
 #define PLINK_CATEGORY		30
 #define MESH_PATH_SEL_CATEGORY	32
 
-/* Mesh Header Flags */
-#define IEEE80211S_FLAGS_AE	0x3
-
 /* Public interfaces */
 /* Various */
-int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr);
 int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
 		struct ieee80211_sub_if_data *sdata);
 int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr,
@@ -267,6 +263,8 @@
 void mesh_path_flush_by_nexthop(struct sta_info *sta);
 void mesh_path_discard_frame(struct sk_buff *skb,
 		struct ieee80211_sub_if_data *sdata);
+void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata);
+void mesh_path_restart(struct ieee80211_sub_if_data *sdata);
 
 #ifdef CONFIG_MAC80211_MESH
 extern int mesh_allocated;
@@ -294,10 +292,20 @@
 
 void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local);
 
+void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata);
+void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata);
+void mesh_plink_quiesce(struct sta_info *sta);
+void mesh_plink_restart(struct sta_info *sta);
 #else
 #define mesh_allocated	0
 static inline void
 ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {}
+static inline void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata)
+{}
+static inline void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata)
+{}
+static inline void mesh_plink_quiesce(struct sta_info *sta) {}
+static inline void mesh_plink_restart(struct sta_info *sta) {}
 #endif
 
 #endif /* IEEE80211S_H */
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 60b35ac..003cb47 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -836,8 +836,14 @@
 	mpath = rcu_dereference(mpath);
 	if (!mpath)
 		goto endmpathtimer;
-	spin_lock_bh(&mpath->state_lock);
 	sdata = mpath->sdata;
+
+	if (sdata->local->quiescing) {
+		rcu_read_unlock();
+		return;
+	}
+
+	spin_lock_bh(&mpath->state_lock);
 	if (mpath->flags & MESH_PATH_RESOLVED ||
 			(!(mpath->flags & MESH_PATH_RESOLVING)))
 		mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED);
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index a8bbdec..cb14253 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -266,6 +266,11 @@
 	 */
 	sta = (struct sta_info *) data;
 
+	if (sta->sdata->local->quiescing) {
+		sta->plink_timer_was_running = true;
+		return;
+	}
+
 	spin_lock_bh(&sta->lock);
 	if (sta->ignore_plink_timer) {
 		sta->ignore_plink_timer = false;
@@ -322,6 +327,22 @@
 	}
 }
 
+#ifdef CONFIG_PM
+void mesh_plink_quiesce(struct sta_info *sta)
+{
+	if (del_timer_sync(&sta->plink_timer))
+		sta->plink_timer_was_running = true;
+}
+
+void mesh_plink_restart(struct sta_info *sta)
+{
+	if (sta->plink_timer_was_running) {
+		add_timer(&sta->plink_timer);
+		sta->plink_timer_was_running = false;
+	}
+}
+#endif
+
 static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
 {
 	sta->plink_timer.expires = jiffies + (HZ * timeout / 1000);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index ae03068..509469c 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -33,10 +33,13 @@
 #define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
 #define IEEE80211_ASSOC_MAX_TRIES 3
 #define IEEE80211_MONITORING_INTERVAL (2 * HZ)
-#define IEEE80211_PROBE_WAIT (HZ / 20)
+#define IEEE80211_PROBE_WAIT (HZ / 5)
 #define IEEE80211_PROBE_IDLE_TIME (60 * HZ)
 #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ)
 
+#define TMR_RUNNING_TIMER	0
+#define TMR_RUNNING_CHANSW	1
+
 /* utils */
 static int ecw2cw(int ecw)
 {
@@ -121,10 +124,14 @@
 		    (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
 			switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
 			case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
-				channel_type = NL80211_CHAN_HT40PLUS;
+				if (!(local->hw.conf.channel->flags &
+				    IEEE80211_CHAN_NO_HT40PLUS))
+					channel_type = NL80211_CHAN_HT40PLUS;
 				break;
 			case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
-				channel_type = NL80211_CHAN_HT40MINUS;
+				if (!(local->hw.conf.channel->flags &
+				    IEEE80211_CHAN_NO_HT40MINUS))
+					channel_type = NL80211_CHAN_HT40MINUS;
 				break;
 			}
 		}
@@ -349,13 +356,13 @@
 
 		switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
 		case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
-			if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) {
+			if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
 				cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 				cap &= ~IEEE80211_HT_CAP_SGI_40;
 			}
 			break;
 		case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
-			if (flags & IEEE80211_CHAN_NO_FAT_BELOW) {
+			if (flags & IEEE80211_CHAN_NO_HT40MINUS) {
 				cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 				cap &= ~IEEE80211_HT_CAP_SGI_40;
 			}
@@ -482,6 +489,108 @@
 	ieee80211_tx_skb(sdata, skb, 0);
 }
 
+/* spectrum management related things */
+static void ieee80211_chswitch_work(struct work_struct *work)
+{
+	struct ieee80211_sub_if_data *sdata =
+		container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
+	struct ieee80211_bss *bss;
+	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+	if (!netif_running(sdata->dev))
+		return;
+
+	bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid,
+				   sdata->local->hw.conf.channel->center_freq,
+				   ifmgd->ssid, ifmgd->ssid_len);
+	if (!bss)
+		goto exit;
+
+	sdata->local->oper_channel = sdata->local->csa_channel;
+	/* XXX: shouldn't really modify cfg80211-owned data! */
+	if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL))
+		bss->cbss.channel = sdata->local->oper_channel;
+
+	ieee80211_rx_bss_put(sdata->local, bss);
+exit:
+	ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
+	ieee80211_wake_queues_by_reason(&sdata->local->hw,
+					IEEE80211_QUEUE_STOP_REASON_CSA);
+}
+
+static void ieee80211_chswitch_timer(unsigned long data)
+{
+	struct ieee80211_sub_if_data *sdata =
+		(struct ieee80211_sub_if_data *) data;
+	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+	if (sdata->local->quiescing) {
+		set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running);
+		return;
+	}
+
+	queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work);
+}
+
+void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
+				      struct ieee80211_channel_sw_ie *sw_elem,
+				      struct ieee80211_bss *bss)
+{
+	struct ieee80211_channel *new_ch;
+	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+	int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num);
+
+	if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATED)
+		return;
+
+	if (sdata->local->sw_scanning || sdata->local->hw_scanning)
+		return;
+
+	/* Disregard subsequent beacons if we are already running a timer
+	   processing a CSA */
+
+	if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED)
+		return;
+
+	new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
+	if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED)
+		return;
+
+	sdata->local->csa_channel = new_ch;
+
+	if (sw_elem->count <= 1) {
+		queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work);
+	} else {
+		ieee80211_stop_queues_by_reason(&sdata->local->hw,
+					IEEE80211_QUEUE_STOP_REASON_CSA);
+		ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
+		mod_timer(&ifmgd->chswitch_timer,
+			  jiffies +
+			  msecs_to_jiffies(sw_elem->count *
+					   bss->cbss.beacon_interval));
+	}
+}
+
+static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
+					u16 capab_info, u8 *pwr_constr_elem,
+					u8 pwr_constr_elem_len)
+{
+	struct ieee80211_conf *conf = &sdata->local->hw.conf;
+
+	if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT))
+		return;
+
+	/* Power constraint IE length should be 1 octet */
+	if (pwr_constr_elem_len != 1)
+		return;
+
+	if ((*pwr_constr_elem <= conf->channel->max_power) &&
+	    (*pwr_constr_elem != sdata->local->power_constr_level)) {
+		sdata->local->power_constr_level = *pwr_constr_elem;
+		ieee80211_hw_config(sdata->local, 0);
+	}
+}
+
 /* powersave */
 static void ieee80211_enable_ps(struct ieee80211_local *local,
 				struct ieee80211_sub_if_data *sdata)
@@ -613,6 +722,9 @@
 {
 	struct ieee80211_local *local = (void *) data;
 
+	if (local->quiescing)
+		return;
+
 	queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work);
 }
 
@@ -865,6 +977,10 @@
 	 * changed or not.
 	 */
 	bss_info_changed |= BSS_CHANGED_BASIC_RATES;
+
+	/* And the BSSID changed - we're associated now */
+	bss_info_changed |= BSS_CHANGED_BSSID;
+
 	ieee80211_bss_info_change_notify(sdata, bss_info_changed);
 
 	/* will be same as sdata */
@@ -1064,6 +1180,9 @@
 	}
 
 	ieee80211_hw_config(local, config_changed);
+
+	/* And the BSSID changed -- not very interesting here */
+	changed |= BSS_CHANGED_BSSID;
 	ieee80211_bss_info_change_notify(sdata, changed);
 
 	rcu_read_lock();
@@ -1270,8 +1389,8 @@
 		ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
 		ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
 					 ifmgd->ssid_len, NULL, 0);
+		mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT);
 		goto unlock;
-
 	}
 
 	if (time_after(jiffies, sta->last_rx + IEEE80211_PROBE_IDLE_TIME)) {
@@ -1280,15 +1399,16 @@
 					 ifmgd->ssid_len, NULL, 0);
 	}
 
+	if (!disassoc)
+		mod_timer(&ifmgd->timer,
+			  jiffies + IEEE80211_MONITORING_INTERVAL);
+
  unlock:
 	rcu_read_unlock();
 
 	if (disassoc)
 		ieee80211_set_disassoc(sdata, true, true,
 					WLAN_REASON_PREV_AUTH_NOT_VALID);
-	else
-		mod_timer(&ifmgd->timer, jiffies +
-				      IEEE80211_MONITORING_INTERVAL);
 }
 
 
@@ -1732,7 +1852,7 @@
 	    (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN) == 0)) {
 		struct ieee80211_channel_sw_ie *sw_elem =
 			(struct ieee80211_channel_sw_ie *)elems->ch_switch_elem;
-		ieee80211_process_chanswitch(sdata, sw_elem, bss);
+		ieee80211_sta_process_chanswitch(sdata, sw_elem, bss);
 	}
 
 	ieee80211_rx_bss_put(local, bss);
@@ -1820,6 +1940,16 @@
 	    memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0)
 		return;
 
+	if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+		if (net_ratelimit()) {
+			printk(KERN_DEBUG "%s: cancelling probereq poll due "
+			       "to a received beacon\n", sdata->dev->name);
+		}
+#endif
+		ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
+	}
+
 	ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
 	ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable,
 					  len - baselen, &elems,
@@ -1829,16 +1959,13 @@
 		directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len,
 						   ifmgd->aid);
 
-	ncrc = crc32_be(ncrc, (void *)&directed_tim, sizeof(directed_tim));
+	if (ncrc != ifmgd->beacon_crc) {
+		ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems,
+				      true);
 
-	if (ncrc == ifmgd->beacon_crc)
-		return;
-	ifmgd->beacon_crc = ncrc;
-
-	ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true);
-
-	ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param,
-				 elems.wmm_param_len);
+		ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param,
+					 elems.wmm_param_len);
+	}
 
 	if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) {
 		if (directed_tim) {
@@ -1863,6 +1990,10 @@
 		}
 	}
 
+	if (ncrc == ifmgd->beacon_crc)
+		return;
+	ifmgd->beacon_crc = ncrc;
+
 	if (elems.erp_info && elems.erp_info_len >= 1) {
 		erp_valid = true;
 		erp_value = elems.erp_info[0];
@@ -1997,6 +2128,11 @@
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_local *local = sdata->local;
 
+	if (local->quiescing) {
+		set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
+		return;
+	}
+
 	set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request);
 	queue_work(local->hw.workqueue, &ifmgd->work);
 }
@@ -2129,6 +2265,17 @@
 
 	if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
 		return;
+
+	/*
+	 * Nothing should have been stuffed into the workqueue during
+	 * the suspend->resume cycle. If this WARN is seen then there
+	 * is a bug with either the driver suspend or something in
+	 * mac80211 stuffing into the workqueue which we haven't yet
+	 * cleared during mac80211's suspend cycle.
+	 */
+	if (WARN_ON(local->suspended))
+		return;
+
 	ifmgd = &sdata->u.mgd;
 
 	while ((skb = skb_dequeue(&ifmgd->skb_queue)))
@@ -2196,6 +2343,38 @@
 	}
 }
 
+#ifdef CONFIG_PM
+void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+	/*
+	 * we need to use atomic bitops for the running bits
+	 * only because both timers might fire at the same
+	 * time -- the code here is properly synchronised.
+	 */
+
+	cancel_work_sync(&ifmgd->work);
+	cancel_work_sync(&ifmgd->beacon_loss_work);
+	if (del_timer_sync(&ifmgd->timer))
+		set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
+
+	cancel_work_sync(&ifmgd->chswitch_work);
+	if (del_timer_sync(&ifmgd->chswitch_timer))
+		set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running);
+}
+
+void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+	if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running))
+		add_timer(&ifmgd->timer);
+	if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running))
+		add_timer(&ifmgd->chswitch_timer);
+}
+#endif
+
 /* interface setup */
 void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
 {
@@ -2310,9 +2489,6 @@
 		ifmgd->flags &= ~IEEE80211_STA_BSSID_SET;
 	}
 
-	if (netif_running(sdata->dev))
-		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
-
 	return ieee80211_sta_commit(sdata);
 }
 
@@ -2321,6 +2497,13 @@
 {
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
+	if (len == 0 && ifmgd->extra_ie_len == 0)
+		return -EALREADY;
+
+	if (len == ifmgd->extra_ie_len && ifmgd->extra_ie &&
+	    memcmp(ifmgd->extra_ie, ie, len) == 0)
+		return -EALREADY;
+
 	kfree(ifmgd->extra_ie);
 	if (len == 0) {
 		ifmgd->extra_ie = NULL;
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index 9d3d89a..7a549f9 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -2,6 +2,7 @@
 #include <net/rtnetlink.h>
 
 #include "ieee80211_i.h"
+#include "mesh.h"
 #include "driver-ops.h"
 #include "led.h"
 
@@ -13,11 +14,30 @@
 	struct sta_info *sta;
 	unsigned long flags;
 
+	ieee80211_scan_cancel(local);
+
 	ieee80211_stop_queues_by_reason(hw,
 			IEEE80211_QUEUE_STOP_REASON_SUSPEND);
 
+	/* flush out all packets */
+	synchronize_net();
+
+	local->quiescing = true;
+	/* make quiescing visible to timers everywhere */
+	mb();
+
 	flush_workqueue(local->hw.workqueue);
 
+	/* Don't try to run timers while suspended. */
+	del_timer_sync(&local->sta_cleanup);
+
+	 /*
+	 * Note that this particular timer doesn't need to be
+	 * restarted at resume.
+	 */
+	cancel_work_sync(&local->dynamic_ps_enable_work);
+	del_timer_sync(&local->dynamic_ps_timer);
+
 	/* disable keys */
 	list_for_each_entry(sdata, &local->interfaces, list)
 		ieee80211_disable_keys(sdata);
@@ -35,10 +55,20 @@
 
 	rcu_read_unlock();
 
+	/* flush again, in case driver queued work */
+	flush_workqueue(local->hw.workqueue);
+
+	/* stop hardware - this must stop RX */
+	if (local->open_count) {
+		ieee80211_led_radio(local, false);
+		drv_stop(local);
+	}
+
 	/* remove STAs */
-	if (local->ops->sta_notify) {
-		spin_lock_irqsave(&local->sta_lock, flags);
-		list_for_each_entry(sta, &local->sta_list, list) {
+	spin_lock_irqsave(&local->sta_lock, flags);
+	list_for_each_entry(sta, &local->sta_list, list) {
+		if (local->ops->sta_notify) {
+			sdata = sta->sdata;
 			if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
 				sdata = container_of(sdata->bss,
 					     struct ieee80211_sub_if_data,
@@ -47,29 +77,43 @@
 			drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE,
 				       &sta->sta);
 		}
-		spin_unlock_irqrestore(&local->sta_lock, flags);
+
+		mesh_plink_quiesce(sta);
 	}
+	spin_unlock_irqrestore(&local->sta_lock, flags);
 
 	/* remove all interfaces */
 	list_for_each_entry(sdata, &local->interfaces, list) {
-		if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
-		    sdata->vif.type != NL80211_IFTYPE_MONITOR &&
-		    netif_running(sdata->dev)) {
-			conf.vif = &sdata->vif;
-			conf.type = sdata->vif.type;
-			conf.mac_addr = sdata->dev->dev_addr;
-			drv_remove_interface(local, &conf);
+		switch(sdata->vif.type) {
+		case NL80211_IFTYPE_STATION:
+			ieee80211_sta_quiesce(sdata);
+			break;
+		case NL80211_IFTYPE_ADHOC:
+			ieee80211_ibss_quiesce(sdata);
+			break;
+		case NL80211_IFTYPE_MESH_POINT:
+			ieee80211_mesh_quiesce(sdata);
+			break;
+		case NL80211_IFTYPE_AP_VLAN:
+		case NL80211_IFTYPE_MONITOR:
+			/* don't tell driver about this */
+			continue;
+		default:
+			break;
 		}
+
+		if (!netif_running(sdata->dev))
+			continue;
+
+		conf.vif = &sdata->vif;
+		conf.type = sdata->vif.type;
+		conf.mac_addr = sdata->dev->dev_addr;
+		drv_remove_interface(local, &conf);
 	}
 
-	/* flush again, in case driver queued work */
-	flush_workqueue(local->hw.workqueue);
+	local->suspended = true;
+	local->quiescing = false;
 
-	/* stop hardware */
-	if (local->open_count) {
-		ieee80211_led_radio(local, false);
-		drv_stop(local);
-	}
 	return 0;
 }
 
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index f962bd1..6a9b8e6 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1247,93 +1247,12 @@
 }
 
 static int
-ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
+__ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
 {
 	struct net_device *dev = rx->dev;
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
-	u16 hdrlen, ethertype;
-	u8 *payload;
-	u8 dst[ETH_ALEN];
-	u8 src[ETH_ALEN] __aligned(2);
-	struct sk_buff *skb = rx->skb;
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
-		return -1;
-
-	hdrlen = ieee80211_hdrlen(hdr->frame_control);
-
-	/* convert IEEE 802.11 header + possible LLC headers into Ethernet
-	 * header
-	 * IEEE 802.11 address fields:
-	 * ToDS FromDS Addr1 Addr2 Addr3 Addr4
-	 *   0     0   DA    SA    BSSID n/a
-	 *   0     1   DA    BSSID SA    n/a
-	 *   1     0   BSSID SA    DA    n/a
-	 *   1     1   RA    TA    DA    SA
-	 */
-	memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN);
-	memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN);
-
-	switch (hdr->frame_control &
-		cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
-	case cpu_to_le16(IEEE80211_FCTL_TODS):
-		if (unlikely(sdata->vif.type != NL80211_IFTYPE_AP &&
-			     sdata->vif.type != NL80211_IFTYPE_AP_VLAN))
-			return -1;
-		break;
-	case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
-		if (unlikely(sdata->vif.type != NL80211_IFTYPE_WDS &&
-			     sdata->vif.type != NL80211_IFTYPE_MESH_POINT))
-			return -1;
-		if (ieee80211_vif_is_mesh(&sdata->vif)) {
-			struct ieee80211s_hdr *meshdr = (struct ieee80211s_hdr *)
-				(skb->data + hdrlen);
-			hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
-			if (meshdr->flags & MESH_FLAGS_AE_A5_A6) {
-				memcpy(dst, meshdr->eaddr1, ETH_ALEN);
-				memcpy(src, meshdr->eaddr2, ETH_ALEN);
-			}
-		}
-		break;
-	case cpu_to_le16(IEEE80211_FCTL_FROMDS):
-		if (sdata->vif.type != NL80211_IFTYPE_STATION ||
-		    (is_multicast_ether_addr(dst) &&
-		     !compare_ether_addr(src, dev->dev_addr)))
-			return -1;
-		break;
-	case cpu_to_le16(0):
-		if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
-			return -1;
-		break;
-	}
-
-	if (unlikely(skb->len - hdrlen < 8))
-		return -1;
-
-	payload = skb->data + hdrlen;
-	ethertype = (payload[6] << 8) | payload[7];
-
-	if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
-		    ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
-		   compare_ether_addr(payload, bridge_tunnel_header) == 0)) {
-		/* remove RFC1042 or Bridge-Tunnel encapsulation and
-		 * replace EtherType */
-		skb_pull(skb, hdrlen + 6);
-		memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
-		memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
-	} else {
-		struct ethhdr *ehdr;
-		__be16 len;
-
-		skb_pull(skb, hdrlen);
-		len = htons(skb->len);
-		ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
-		memcpy(ehdr->h_dest, dst, ETH_ALEN);
-		memcpy(ehdr->h_source, src, ETH_ALEN);
-		ehdr->h_proto = len;
-	}
-	return 0;
+	return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type);
 }
 
 /*
@@ -1472,7 +1391,7 @@
 	if (!(rx->flags & IEEE80211_RX_AMSDU))
 		return RX_CONTINUE;
 
-	err = ieee80211_data_to_8023(rx);
+	err = __ieee80211_data_to_8023(rx);
 	if (unlikely(err))
 		return RX_DROP_UNUSABLE;
 
@@ -1658,7 +1577,7 @@
 	if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
 		return RX_DROP_MONITOR;
 
-	err = ieee80211_data_to_8023(rx);
+	err = __ieee80211_data_to_8023(rx);
 	if (unlikely(err))
 		return RX_DROP_UNUSABLE;
 
@@ -1846,6 +1765,9 @@
 				   sizeof(mgmt->u.action.u.chan_switch)))
 				return RX_DROP_MONITOR;
 
+			if (sdata->vif.type != NL80211_IFTYPE_STATION)
+				return RX_DROP_MONITOR;
+
 			if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN))
 				return RX_DROP_MONITOR;
 
@@ -1856,7 +1778,7 @@
 			if (!bss)
 				return RX_DROP_MONITOR;
 
-			ieee80211_process_chanswitch(sdata,
+			ieee80211_sta_process_chanswitch(sdata,
 				     &mgmt->u.action.u.chan_switch.sw_elem, bss);
 			ieee80211_rx_bss_put(local, bss);
 			break;
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index e65d74b..2a8d09a 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -631,3 +631,21 @@
 	mutex_unlock(&local->scan_mtx);
 	return ret;
 }
+
+void ieee80211_scan_cancel(struct ieee80211_local *local)
+{
+	bool swscan;
+
+	cancel_delayed_work_sync(&local->scan_work);
+
+	/*
+	 * Only call this function when a scan can't be
+	 * queued -- mostly at suspend under RTNL.
+	 */
+	mutex_lock(&local->scan_mtx);
+	swscan = local->sw_scanning;
+	mutex_unlock(&local->scan_mtx);
+
+	if (swscan)
+		ieee80211_scan_completed(&local->hw, true);
+}
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index 48bf78e..6895303 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -84,104 +84,3 @@
 			mgmt->sa, mgmt->bssid,
 			mgmt->u.action.u.measurement.dialog_token);
 }
-
-void ieee80211_chswitch_work(struct work_struct *work)
-{
-	struct ieee80211_sub_if_data *sdata =
-		container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
-	struct ieee80211_bss *bss;
-	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-
-	if (!netif_running(sdata->dev))
-		return;
-
-	bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid,
-				   sdata->local->hw.conf.channel->center_freq,
-				   ifmgd->ssid, ifmgd->ssid_len);
-	if (!bss)
-		goto exit;
-
-	sdata->local->oper_channel = sdata->local->csa_channel;
-	/* XXX: shouldn't really modify cfg80211-owned data! */
-	if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL))
-		bss->cbss.channel = sdata->local->oper_channel;
-
-	ieee80211_rx_bss_put(sdata->local, bss);
-exit:
-	ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
-	ieee80211_wake_queues_by_reason(&sdata->local->hw,
-					IEEE80211_QUEUE_STOP_REASON_CSA);
-}
-
-void ieee80211_chswitch_timer(unsigned long data)
-{
-	struct ieee80211_sub_if_data *sdata =
-		(struct ieee80211_sub_if_data *) data;
-	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-
-	queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work);
-}
-
-void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata,
-				  struct ieee80211_channel_sw_ie *sw_elem,
-				  struct ieee80211_bss *bss)
-{
-	struct ieee80211_channel *new_ch;
-	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num);
-
-	/* FIXME: Handle ADHOC later */
-	if (sdata->vif.type != NL80211_IFTYPE_STATION)
-		return;
-
-	if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATED)
-		return;
-
-	if (sdata->local->sw_scanning || sdata->local->hw_scanning)
-		return;
-
-	/* Disregard subsequent beacons if we are already running a timer
-	   processing a CSA */
-
-	if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED)
-		return;
-
-	new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
-	if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED)
-		return;
-
-	sdata->local->csa_channel = new_ch;
-
-	if (sw_elem->count <= 1) {
-		queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work);
-	} else {
-		ieee80211_stop_queues_by_reason(&sdata->local->hw,
-						IEEE80211_QUEUE_STOP_REASON_CSA);
-		ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
-		mod_timer(&ifmgd->chswitch_timer,
-			  jiffies +
-			  msecs_to_jiffies(sw_elem->count *
-					   bss->cbss.beacon_interval));
-	}
-}
-
-void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
-				 u16 capab_info, u8 *pwr_constr_elem,
-				 u8 pwr_constr_elem_len)
-{
-	struct ieee80211_conf *conf = &sdata->local->hw.conf;
-
-	if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT))
-		return;
-
-	/* Power constraint IE length should be 1 octet */
-	if (pwr_constr_elem_len != 1)
-		return;
-
-	if ((*pwr_constr_elem <= conf->channel->max_power) &&
-	    (*pwr_constr_elem != sdata->local->power_constr_level)) {
-		sdata->local->power_constr_level = *pwr_constr_elem;
-		ieee80211_hw_config(sdata->local, 0);
-	}
-}
-
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index a98ea27..d5611d8 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -293,6 +293,9 @@
 	skb_queue_head_init(&sta->ps_tx_buf);
 	skb_queue_head_init(&sta->tx_filtered);
 
+	for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
+		sta->last_seq_ctrl[i] = cpu_to_le16(USHORT_MAX);
+
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
 	printk(KERN_DEBUG "%s: Allocated STA %pM\n",
 	       wiphy_name(local->hw.wiphy), sta->sta.addr);
@@ -608,6 +611,9 @@
 		sta_info_cleanup_expire_buffered(local, sta);
 	rcu_read_unlock();
 
+	if (local->quiescing)
+		return;
+
 	local->sta_cleanup.expires =
 		round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
 	add_timer(&local->sta_cleanup);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 164b16c..49a1a1f 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -216,6 +216,7 @@
  * @plink_state: peer link state
  * @plink_timeout: timeout of peer link
  * @plink_timer: peer link watch timer
+ * @plink_timer_was_running: used by suspend/resume to restore timers
  * @debugfs: debug filesystem info
  * @sta: station information we share with the driver
  */
@@ -293,6 +294,7 @@
 	__le16 reason;
 	u8 plink_retries;
 	bool ignore_plink_timer;
+	bool plink_timer_was_running;
 	enum plink_state plink_state;
 	u32 plink_timeout;
 	struct timer_list plink_timer;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 8f68bf9..a910148 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -872,6 +872,8 @@
 
 	do {
 		hdr = (void *) skb->data;
+		if (unlikely(ieee80211_is_pspoll(hdr->frame_control)))
+			break; /* must not overwrite AID */
 		next_len = skb->next ? skb->next->len : 0;
 		group_addr = is_multicast_ether_addr(hdr->addr1);
 
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 0689a8f..949d857 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -35,15 +35,6 @@
 /* privid for wiphys to determine whether they belong to us or not */
 void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
 
-/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
-/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
-const unsigned char rfc1042_header[] __aligned(2) =
-	{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
-
-/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
-const unsigned char bridge_tunnel_header[] __aligned(2) =
-	{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
-
 struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy)
 {
 	struct ieee80211_local *local;
@@ -103,70 +94,6 @@
 	return NULL;
 }
 
-unsigned int ieee80211_hdrlen(__le16 fc)
-{
-	unsigned int hdrlen = 24;
-
-	if (ieee80211_is_data(fc)) {
-		if (ieee80211_has_a4(fc))
-			hdrlen = 30;
-		if (ieee80211_is_data_qos(fc))
-			hdrlen += IEEE80211_QOS_CTL_LEN;
-		goto out;
-	}
-
-	if (ieee80211_is_ctl(fc)) {
-		/*
-		 * ACK and CTS are 10 bytes, all others 16. To see how
-		 * to get this condition consider
-		 *   subtype mask:   0b0000000011110000 (0x00F0)
-		 *   ACK subtype:    0b0000000011010000 (0x00D0)
-		 *   CTS subtype:    0b0000000011000000 (0x00C0)
-		 *   bits that matter:         ^^^      (0x00E0)
-		 *   value of those: 0b0000000011000000 (0x00C0)
-		 */
-		if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0))
-			hdrlen = 10;
-		else
-			hdrlen = 16;
-	}
-out:
-	return hdrlen;
-}
-EXPORT_SYMBOL(ieee80211_hdrlen);
-
-unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
-{
-	const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *)skb->data;
-	unsigned int hdrlen;
-
-	if (unlikely(skb->len < 10))
-		return 0;
-	hdrlen = ieee80211_hdrlen(hdr->frame_control);
-	if (unlikely(hdrlen > skb->len))
-		return 0;
-	return hdrlen;
-}
-EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
-
-int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
-{
-	int ae = meshhdr->flags & IEEE80211S_FLAGS_AE;
-	/* 7.1.3.5a.2 */
-	switch (ae) {
-	case 0:
-		return 6;
-	case 1:
-		return 12;
-	case 2:
-		return 18;
-	case 3:
-		return 24;
-	default:
-		return 6;
-	}
-}
-
 void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx)
 {
 	struct sk_buff *skb = tx->skb;
@@ -1034,6 +961,13 @@
 	struct sta_info *sta;
 	unsigned long flags;
 	int res;
+	bool from_suspend = local->suspended;
+
+	/*
+	 * We're going to start the hardware, at that point
+	 * we are no longer suspended and can RX frames.
+	 */
+	local->suspended = false;
 
 	/* restart hardware */
 	if (local->open_count) {
@@ -1058,6 +992,7 @@
 	if (local->ops->sta_notify) {
 		spin_lock_irqsave(&local->sta_lock, flags);
 		list_for_each_entry(sta, &local->sta_list, list) {
+			sdata = sta->sdata;
 			if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
 				sdata = container_of(sdata->bss,
 					     struct ieee80211_sub_if_data,
@@ -1128,5 +1063,40 @@
 	ieee80211_wake_queues_by_reason(hw,
 			IEEE80211_QUEUE_STOP_REASON_SUSPEND);
 
+	/*
+	 * If this is for hw restart things are still running.
+	 * We may want to change that later, however.
+	 */
+	if (!from_suspend)
+		return 0;
+
+#ifdef CONFIG_PM
+	local->suspended = false;
+
+	list_for_each_entry(sdata, &local->interfaces, list) {
+		switch(sdata->vif.type) {
+		case NL80211_IFTYPE_STATION:
+			ieee80211_sta_restart(sdata);
+			break;
+		case NL80211_IFTYPE_ADHOC:
+			ieee80211_ibss_restart(sdata);
+			break;
+		case NL80211_IFTYPE_MESH_POINT:
+			ieee80211_mesh_restart(sdata);
+			break;
+		default:
+			break;
+		}
+	}
+
+	add_timer(&local->sta_cleanup);
+
+	spin_lock_irqsave(&local->sta_lock, flags);
+	list_for_each_entry(sta, &local->sta_list, list)
+		mesh_plink_restart(sta);
+	spin_unlock_irqrestore(&local->sta_lock, flags);
+#else
+	WARN_ON(1);
+#endif
 	return 0;
 }
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index c143947..a01154e 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -37,12 +37,13 @@
 
 	if (sdata->vif.type == NL80211_IFTYPE_STATION) {
 		int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length);
-		if (ret)
+		if (ret && ret != -EALREADY)
 			return ret;
 		sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
 		sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
 		sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
-		ieee80211_sta_req_auth(sdata);
+		if (ret != -EALREADY)
+			ieee80211_sta_req_auth(sdata);
 		return 0;
 	}
 
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 45b74f3..694343b 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -23,34 +23,6 @@
  */
 const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 };
 
-static const char llc_ip_hdr[8] = {0xAA, 0xAA, 0x3, 0, 0, 0, 0x08, 0};
-
-/* Given a data frame determine the 802.1p/1d tag to use.  */
-static unsigned int classify_1d(struct sk_buff *skb)
-{
-	unsigned int dscp;
-
-	/* skb->priority values from 256->263 are magic values to
-	 * directly indicate a specific 802.1d priority.  This is used
-	 * to allow 802.1d priority to be passed directly in from VLAN
-	 * tags, etc.
-	 */
-	if (skb->priority >= 256 && skb->priority <= 263)
-		return skb->priority - 256;
-
-	switch (skb->protocol) {
-	case htons(ETH_P_IP):
-		dscp = ip_hdr(skb)->tos & 0xfc;
-		break;
-
-	default:
-		return 0;
-	}
-
-	return dscp >> 5;
-}
-
-
 static int wme_downgrade_ac(struct sk_buff *skb)
 {
 	switch (skb->priority) {
@@ -94,7 +66,7 @@
 
 	/* use the data classifier to determine what 802.1d tag the
 	 * data frame has */
-	skb->priority = classify_1d(skb);
+	skb->priority = cfg80211_classify8021d(skb);
 
 	/* in case we are a client verify acm is not set for this ac */
 	while (unlikely(local->wmm_acm & BIT(skb->priority))) {
diff --git a/net/rxrpc/ar-connection.c b/net/rxrpc/ar-connection.c
index 0f1218b..67e38a0 100644
--- a/net/rxrpc/ar-connection.c
+++ b/net/rxrpc/ar-connection.c
@@ -343,9 +343,9 @@
 		/* not yet present - create a candidate for a new connection
 		 * and then redo the check */
 		conn = rxrpc_alloc_connection(gfp);
-		if (IS_ERR(conn)) {
-			_leave(" = %ld", PTR_ERR(conn));
-			return PTR_ERR(conn);
+		if (!conn) {
+			_leave(" = -ENOMEM");
+			return -ENOMEM;
 		}
 
 		conn->trans = trans;
@@ -508,9 +508,9 @@
 		/* not yet present - create a candidate for a new connection and then
 		 * redo the check */
 		candidate = rxrpc_alloc_connection(gfp);
-		if (IS_ERR(candidate)) {
-			_leave(" = %ld", PTR_ERR(candidate));
-			return PTR_ERR(candidate);
+		if (!candidate) {
+			_leave(" = -ENOMEM");
+			return -ENOMEM;
 		}
 
 		candidate->trans = trans;
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index 428a5ef..a886496 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -308,6 +308,7 @@
 				if (!netif_tx_queue_stopped(slave_txq) &&
 				    !netif_tx_queue_frozen(slave_txq) &&
 				    slave_ops->ndo_start_xmit(skb, slave) == 0) {
+					txq_trans_update(slave_txq);
 					__netif_tx_unlock(slave_txq);
 					master->slaves = NEXT_SLAVE(q);
 					netif_wake_queue(dev);
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 3c3bc9e..4500549 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -10,6 +10,14 @@
 
 	  If unsure, say N.
 
+config CFG80211_DEBUGFS
+	bool "cfg80211 DebugFS entries"
+	depends on CFG80211 && DEBUG_FS
+	---help---
+	  You can enable this if you want to debugfs entries for cfg80211.
+
+	  If unsure, say N.
+
 config WIRELESS_OLD_REGULATORY
 	bool "Old wireless static regulatory definitions"
 	default n
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index 14ea01c..f78c483 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -6,6 +6,7 @@
 obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o
 
 cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o
+cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
 cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o
 
 ccflags-y += -D__CHECK_ENDIAN__
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 47c20eb..a5dbea1 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -17,6 +17,7 @@
 #include "nl80211.h"
 #include "core.h"
 #include "sysfs.h"
+#include "debugfs.h"
 
 /* name for sysfs, %d is appended */
 #define PHY_NAME "phy"
@@ -228,7 +229,7 @@
 
 /* exported functions */
 
-struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
+struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
 {
 	static int wiphy_counter;
 
@@ -375,6 +376,8 @@
 		nl80211_send_reg_change_event(&request);
 	}
 
+	cfg80211_debugfs_drv_add(drv);
+
 	res = 0;
 out_unlock:
 	mutex_unlock(&cfg80211_mutex);
@@ -405,6 +408,8 @@
 	/* unlock again before freeing */
 	mutex_unlock(&drv->mtx);
 
+	cfg80211_debugfs_drv_del(drv);
+
 	/* If this device got a regulatory hint tell core its
 	 * free to listen now to a new shiny device regulatory hint */
 	reg_device_remove(wiphy);
diff --git a/net/wireless/core.h b/net/wireless/core.h
index f14b6c5..ab512bc 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -10,12 +10,13 @@
 #include <linux/netdevice.h>
 #include <linux/kref.h>
 #include <linux/rbtree.h>
+#include <linux/debugfs.h>
 #include <net/genetlink.h>
 #include <net/cfg80211.h>
 #include "reg.h"
 
 struct cfg80211_registered_device {
-	struct cfg80211_ops *ops;
+	const struct cfg80211_ops *ops;
 	struct list_head list;
 	/* we hold this mutex during any call so that
 	 * we cannot do multiple calls at once, and also
@@ -50,6 +51,17 @@
 	struct cfg80211_scan_request *scan_req; /* protected by RTNL */
 	unsigned long suspend_at;
 
+#ifdef CONFIG_CFG80211_DEBUGFS
+	/* Debugfs entries */
+	struct wiphy_debugfsdentries {
+		struct dentry *rts_threshold;
+		struct dentry *fragmentation_threshold;
+		struct dentry *short_retry_limit;
+		struct dentry *long_retry_limit;
+		struct dentry *ht40allow_map;
+	} debugfs;
+#endif
+
 	/* must be last because of the way we do wiphy_priv(),
 	 * and it should at least be aligned to NETDEV_ALIGN */
 	struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN)));
diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c
new file mode 100644
index 0000000..679ddfc
--- /dev/null
+++ b/net/wireless/debugfs.c
@@ -0,0 +1,131 @@
+/*
+ * cfg80211 debugfs
+ *
+ * Copyright 2009	Luis R. Rodriguez <lrodriguez@atheros.com>
+ * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "core.h"
+#include "debugfs.h"
+
+static int cfg80211_open_file_generic(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...)		\
+static ssize_t name## _read(struct file *file, char __user *userbuf,	\
+			    size_t count, loff_t *ppos)			\
+{									\
+	struct wiphy *wiphy= file->private_data;		\
+	char buf[buflen];						\
+	int res;							\
+									\
+	res = scnprintf(buf, buflen, fmt "\n", ##value);		\
+	return simple_read_from_buffer(userbuf, count, ppos, buf, res);	\
+}									\
+									\
+static const struct file_operations name## _ops = {			\
+	.read = name## _read,						\
+	.open = cfg80211_open_file_generic,				\
+};
+
+DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d",
+		      wiphy->rts_threshold)
+DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d",
+		      wiphy->frag_threshold);
+DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d",
+		      wiphy->retry_short)
+DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d",
+		      wiphy->retry_long);
+
+static int ht_print_chan(struct ieee80211_channel *chan,
+			 char *buf, int buf_size, int offset)
+{
+	if (WARN_ON(offset > buf_size))
+		return 0;
+
+	if (chan->flags & IEEE80211_CHAN_DISABLED)
+		return snprintf(buf + offset,
+				buf_size - offset,
+				"%d Disabled\n",
+				chan->center_freq);
+
+	return snprintf(buf + offset,
+			buf_size - offset,
+			"%d HT40 %c%c\n",
+			chan->center_freq,
+			(chan->flags & IEEE80211_CHAN_NO_HT40MINUS) ? ' ' : '-',
+			(chan->flags & IEEE80211_CHAN_NO_HT40PLUS)  ? ' ' : '+');
+}
+
+static ssize_t ht40allow_map_read(struct file *file,
+				  char __user *user_buf,
+				  size_t count, loff_t *ppos)
+{
+	struct wiphy *wiphy = file->private_data;
+	char *buf;
+	unsigned int offset = 0, buf_size = PAGE_SIZE, i, r;
+	enum ieee80211_band band;
+	struct ieee80211_supported_band *sband;
+
+	buf = kzalloc(buf_size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	mutex_lock(&cfg80211_mutex);
+
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+		sband = wiphy->bands[band];
+		if (!sband)
+			continue;
+		for (i = 0; i < sband->n_channels; i++)
+			offset += ht_print_chan(&sband->channels[i],
+						buf, buf_size, offset);
+	}
+
+	mutex_unlock(&cfg80211_mutex);
+
+	r = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
+
+	kfree(buf);
+
+	return r;
+}
+
+static const struct file_operations ht40allow_map_ops = {
+	.read = ht40allow_map_read,
+	.open = cfg80211_open_file_generic,
+};
+
+#define DEBUGFS_ADD(name)						\
+	drv->debugfs.name = debugfs_create_file(#name, S_IRUGO, phyd,	\
+						  &drv->wiphy, &name## _ops);
+#define DEBUGFS_DEL(name)						\
+	debugfs_remove(drv->debugfs.name);				\
+	drv->debugfs.name = NULL;
+
+void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv)
+{
+	struct dentry *phyd = drv->wiphy.debugfsdir;
+
+	DEBUGFS_ADD(rts_threshold);
+	DEBUGFS_ADD(fragmentation_threshold);
+	DEBUGFS_ADD(short_retry_limit);
+	DEBUGFS_ADD(long_retry_limit);
+	DEBUGFS_ADD(ht40allow_map);
+}
+
+void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv)
+{
+	DEBUGFS_DEL(rts_threshold);
+	DEBUGFS_DEL(fragmentation_threshold);
+	DEBUGFS_DEL(short_retry_limit);
+	DEBUGFS_DEL(long_retry_limit);
+	DEBUGFS_DEL(ht40allow_map);
+}
diff --git a/net/wireless/debugfs.h b/net/wireless/debugfs.h
new file mode 100644
index 0000000..c226983
--- /dev/null
+++ b/net/wireless/debugfs.h
@@ -0,0 +1,14 @@
+#ifndef __CFG80211_DEBUGFS_H
+#define __CFG80211_DEBUGFS_H
+
+#ifdef CONFIG_CFG80211_DEBUGFS
+void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv);
+void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv);
+#else
+static inline
+void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv) {}
+static inline
+void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv) {}
+#endif
+
+#endif /* __CFG80211_DEBUGFS_H */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index a3a152f..4b4d3c8 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -57,7 +57,7 @@
 static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
 	[NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
 	[NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
-				      .len = BUS_ID_SIZE-1 },
+				      .len = 20-1 },
 	[NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
 	[NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
 	[NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 },
@@ -77,6 +77,7 @@
 	[NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
 	[NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
 	[NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
+	[NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
 
 	[NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
 	[NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
@@ -492,7 +493,7 @@
 		enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
 		struct ieee80211_channel *chan;
 		struct ieee80211_sta_ht_cap *ht_cap;
-		u32 freq, sec_freq;
+		u32 freq;
 
 		if (!rdev->ops->set_channel) {
 			result = -EOPNOTSUPP;
@@ -518,33 +519,28 @@
 		if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
 			goto bad_res;
 
-		if (channel_type == NL80211_CHAN_HT40MINUS)
-			sec_freq = freq - 20;
-		else if (channel_type == NL80211_CHAN_HT40PLUS)
-			sec_freq = freq + 20;
-		else
-			sec_freq = 0;
+		if (channel_type == NL80211_CHAN_HT40MINUS &&
+		    (chan->flags & IEEE80211_CHAN_NO_HT40MINUS))
+			goto bad_res;
+		else if (channel_type == NL80211_CHAN_HT40PLUS &&
+			 (chan->flags & IEEE80211_CHAN_NO_HT40PLUS))
+			goto bad_res;
+
+		/*
+		 * At this point we know if that if HT40 was requested
+		 * we are allowed to use it and the extension channel
+		 * exists.
+		 */
 
 		ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap;
 
-		/* no HT capabilities */
-		if (channel_type != NL80211_CHAN_NO_HT &&
-		    !ht_cap->ht_supported)
-			goto bad_res;
-
-		if (sec_freq) {
-			struct ieee80211_channel *schan;
-
-			/* no 40 MHz capabilities */
+		/* no HT capabilities or intolerant */
+		if (channel_type != NL80211_CHAN_NO_HT) {
+			if (!ht_cap->ht_supported)
+				goto bad_res;
 			if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
 			    (ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT))
 				goto bad_res;
-
-			schan = ieee80211_get_channel(&rdev->wiphy, sec_freq);
-
-			/* Secondary channel not allowed */
-			if (!schan || schan->flags & IEEE80211_CHAN_DISABLED)
-				goto bad_res;
 		}
 
 		result = rdev->ops->set_channel(&rdev->wiphy, chan,
@@ -2571,18 +2567,24 @@
 			rem_reg_rules) {
 		num_rules++;
 		if (num_rules > NL80211_MAX_SUPP_REG_RULES)
-			goto bad_reg;
+			return -EINVAL;
 	}
 
-	if (!reg_is_valid_request(alpha2))
-		return -EINVAL;
+	mutex_lock(&cfg80211_mutex);
+
+	if (!reg_is_valid_request(alpha2)) {
+		r = -EINVAL;
+		goto bad_reg;
+	}
 
 	size_of_regd = sizeof(struct ieee80211_regdomain) +
 		(num_rules * sizeof(struct ieee80211_reg_rule));
 
 	rd = kzalloc(size_of_regd, GFP_KERNEL);
-	if (!rd)
-		return -ENOMEM;
+	if (!rd) {
+		r = -ENOMEM;
+		goto bad_reg;
+	}
 
 	rd->n_reg_rules = num_rules;
 	rd->alpha2[0] = alpha2[0];
@@ -2599,20 +2601,24 @@
 
 		rule_idx++;
 
-		if (rule_idx > NL80211_MAX_SUPP_REG_RULES)
+		if (rule_idx > NL80211_MAX_SUPP_REG_RULES) {
+			r = -EINVAL;
 			goto bad_reg;
+		}
 	}
 
 	BUG_ON(rule_idx != num_rules);
 
-	mutex_lock(&cfg80211_mutex);
 	r = set_regdom(rd);
+
 	mutex_unlock(&cfg80211_mutex);
+
 	return r;
 
  bad_reg:
+	mutex_unlock(&cfg80211_mutex);
 	kfree(rd);
-	return -EINVAL;
+	return r;
 }
 
 static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 537af62..f87ac1d 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -48,12 +48,6 @@
 /* To trigger userspace events */
 static struct platform_device *reg_pdev;
 
-/* Keep the ordering from large to small */
-static u32 supported_bandwidths[] = {
-	MHZ_TO_KHZ(40),
-	MHZ_TO_KHZ(20),
-};
-
 /*
  * Central wireless core regulatory domains, we only need two,
  * the current one and a world regulatory domain in case we have no
@@ -388,6 +382,8 @@
 /* Used by nl80211 before kmalloc'ing our regulatory domain */
 bool reg_is_valid_request(const char *alpha2)
 {
+	assert_cfg80211_lock();
+
 	if (!last_request)
 		return false;
 
@@ -435,19 +431,20 @@
 	return true;
 }
 
-/* Returns value in KHz */
-static u32 freq_max_bandwidth(const struct ieee80211_freq_range *freq_range,
-	u32 freq)
+static bool reg_does_bw_fit(const struct ieee80211_freq_range *freq_range,
+			    u32 center_freq_khz,
+			    u32 bw_khz)
 {
-	unsigned int i;
-	for (i = 0; i < ARRAY_SIZE(supported_bandwidths); i++) {
-		u32 start_freq_khz = freq - supported_bandwidths[i]/2;
-		u32 end_freq_khz = freq + supported_bandwidths[i]/2;
-		if (start_freq_khz >= freq_range->start_freq_khz &&
-			end_freq_khz <= freq_range->end_freq_khz)
-			return supported_bandwidths[i];
-	}
-	return 0;
+	u32 start_freq_khz, end_freq_khz;
+
+	start_freq_khz = center_freq_khz - (bw_khz/2);
+	end_freq_khz = center_freq_khz + (bw_khz/2);
+
+	if (start_freq_khz >= freq_range->start_freq_khz &&
+	    end_freq_khz <= freq_range->end_freq_khz)
+		return true;
+
+	return false;
 }
 
 /**
@@ -847,14 +844,17 @@
 
 static int freq_reg_info_regd(struct wiphy *wiphy,
 			      u32 center_freq,
-			      u32 *bandwidth,
+			      u32 desired_bw_khz,
 			      const struct ieee80211_reg_rule **reg_rule,
 			      const struct ieee80211_regdomain *custom_regd)
 {
 	int i;
 	bool band_rule_found = false;
 	const struct ieee80211_regdomain *regd;
-	u32 max_bandwidth = 0;
+	bool bw_fits = false;
+
+	if (!desired_bw_khz)
+		desired_bw_khz = MHZ_TO_KHZ(20);
 
 	regd = custom_regd ? custom_regd : cfg80211_regdomain;
 
@@ -887,38 +887,54 @@
 		if (!band_rule_found)
 			band_rule_found = freq_in_rule_band(fr, center_freq);
 
-		max_bandwidth = freq_max_bandwidth(fr, center_freq);
+		bw_fits = reg_does_bw_fit(fr,
+					  center_freq,
+					  desired_bw_khz);
 
-		if (max_bandwidth && *bandwidth <= max_bandwidth) {
+		if (band_rule_found && bw_fits) {
 			*reg_rule = rr;
-			*bandwidth = max_bandwidth;
-			break;
+			return 0;
 		}
 	}
 
 	if (!band_rule_found)
 		return -ERANGE;
 
-	return !max_bandwidth;
+	return -EINVAL;
 }
 EXPORT_SYMBOL(freq_reg_info);
 
-int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth,
-			 const struct ieee80211_reg_rule **reg_rule)
+int freq_reg_info(struct wiphy *wiphy,
+		  u32 center_freq,
+		  u32 desired_bw_khz,
+		  const struct ieee80211_reg_rule **reg_rule)
 {
 	assert_cfg80211_lock();
-	return freq_reg_info_regd(wiphy, center_freq,
-		bandwidth, reg_rule, NULL);
+	return freq_reg_info_regd(wiphy,
+				  center_freq,
+				  desired_bw_khz,
+				  reg_rule,
+				  NULL);
 }
 
+/*
+ * Note that right now we assume the desired channel bandwidth
+ * is always 20 MHz for each individual channel (HT40 uses 20 MHz
+ * per channel, the primary and the extension channel). To support
+ * smaller custom bandwidths such as 5 MHz or 10 MHz we'll need a
+ * new ieee80211_channel.target_bw and re run the regulatory check
+ * on the wiphy with the target_bw specified. Then we can simply use
+ * that below for the desired_bw_khz below.
+ */
 static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
 			   unsigned int chan_idx)
 {
 	int r;
-	u32 flags;
-	u32 max_bandwidth = 0;
+	u32 flags, bw_flags = 0;
+	u32 desired_bw_khz = MHZ_TO_KHZ(20);
 	const struct ieee80211_reg_rule *reg_rule = NULL;
 	const struct ieee80211_power_rule *power_rule = NULL;
+	const struct ieee80211_freq_range *freq_range = NULL;
 	struct ieee80211_supported_band *sband;
 	struct ieee80211_channel *chan;
 	struct wiphy *request_wiphy = NULL;
@@ -933,8 +949,10 @@
 
 	flags = chan->orig_flags;
 
-	r = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq),
-		&max_bandwidth, &reg_rule);
+	r = freq_reg_info(wiphy,
+			  MHZ_TO_KHZ(chan->center_freq),
+			  desired_bw_khz,
+			  &reg_rule);
 
 	if (r) {
 		/*
@@ -977,6 +995,10 @@
 	}
 
 	power_rule = &reg_rule->power_rule;
+	freq_range = &reg_rule->freq_range;
+
+	if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40))
+		bw_flags = IEEE80211_CHAN_NO_HT40;
 
 	if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
 	    request_wiphy && request_wiphy == wiphy &&
@@ -987,19 +1009,19 @@
 		 * settings
 		 */
 		chan->flags = chan->orig_flags =
-			map_regdom_flags(reg_rule->flags);
+			map_regdom_flags(reg_rule->flags) | bw_flags;
 		chan->max_antenna_gain = chan->orig_mag =
 			(int) MBI_TO_DBI(power_rule->max_antenna_gain);
-		chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth);
+		chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz);
 		chan->max_power = chan->orig_mpwr =
 			(int) MBM_TO_DBM(power_rule->max_eirp);
 		return;
 	}
 
-	chan->flags = flags | map_regdom_flags(reg_rule->flags);
+	chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags);
 	chan->max_antenna_gain = min(chan->orig_mag,
 		(int) MBI_TO_DBI(power_rule->max_antenna_gain));
-	chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth);
+	chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz);
 	if (chan->orig_mpwr)
 		chan->max_power = min(chan->orig_mpwr,
 			(int) MBM_TO_DBM(power_rule->max_eirp));
@@ -1156,6 +1178,93 @@
 	wiphy_update_beacon_reg(wiphy);
 }
 
+static bool is_ht40_not_allowed(struct ieee80211_channel *chan)
+{
+	if (!chan)
+		return true;
+	if (chan->flags & IEEE80211_CHAN_DISABLED)
+		return true;
+	/* This would happen when regulatory rules disallow HT40 completely */
+	if (IEEE80211_CHAN_NO_HT40 == (chan->flags & (IEEE80211_CHAN_NO_HT40)))
+		return true;
+	return false;
+}
+
+static void reg_process_ht_flags_channel(struct wiphy *wiphy,
+					 enum ieee80211_band band,
+					 unsigned int chan_idx)
+{
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_channel *channel;
+	struct ieee80211_channel *channel_before = NULL, *channel_after = NULL;
+	unsigned int i;
+
+	assert_cfg80211_lock();
+
+	sband = wiphy->bands[band];
+	BUG_ON(chan_idx >= sband->n_channels);
+	channel = &sband->channels[chan_idx];
+
+	if (is_ht40_not_allowed(channel)) {
+		channel->flags |= IEEE80211_CHAN_NO_HT40;
+		return;
+	}
+
+	/*
+	 * We need to ensure the extension channels exist to
+	 * be able to use HT40- or HT40+, this finds them (or not)
+	 */
+	for (i = 0; i < sband->n_channels; i++) {
+		struct ieee80211_channel *c = &sband->channels[i];
+		if (c->center_freq == (channel->center_freq - 20))
+			channel_before = c;
+		if (c->center_freq == (channel->center_freq + 20))
+			channel_after = c;
+	}
+
+	/*
+	 * Please note that this assumes target bandwidth is 20 MHz,
+	 * if that ever changes we also need to change the below logic
+	 * to include that as well.
+	 */
+	if (is_ht40_not_allowed(channel_before))
+		channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
+	else
+		channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
+
+	if (is_ht40_not_allowed(channel_after))
+		channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
+	else
+		channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
+}
+
+static void reg_process_ht_flags_band(struct wiphy *wiphy,
+				      enum ieee80211_band band)
+{
+	unsigned int i;
+	struct ieee80211_supported_band *sband;
+
+	BUG_ON(!wiphy->bands[band]);
+	sband = wiphy->bands[band];
+
+	for (i = 0; i < sband->n_channels; i++)
+		reg_process_ht_flags_channel(wiphy, band, i);
+}
+
+static void reg_process_ht_flags(struct wiphy *wiphy)
+{
+	enum ieee80211_band band;
+
+	if (!wiphy)
+		return;
+
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+		if (wiphy->bands[band])
+			reg_process_ht_flags_band(wiphy, band);
+	}
+
+}
+
 void wiphy_update_regulatory(struct wiphy *wiphy,
 			     enum nl80211_reg_initiator initiator)
 {
@@ -1169,6 +1278,7 @@
 	}
 out:
 	reg_process_beacons(wiphy);
+	reg_process_ht_flags(wiphy);
 	if (wiphy->reg_notifier)
 		wiphy->reg_notifier(wiphy, last_request);
 }
@@ -1179,9 +1289,11 @@
 				  const struct ieee80211_regdomain *regd)
 {
 	int r;
-	u32 max_bandwidth = 0;
+	u32 desired_bw_khz = MHZ_TO_KHZ(20);
+	u32 bw_flags = 0;
 	const struct ieee80211_reg_rule *reg_rule = NULL;
 	const struct ieee80211_power_rule *power_rule = NULL;
+	const struct ieee80211_freq_range *freq_range = NULL;
 	struct ieee80211_supported_band *sband;
 	struct ieee80211_channel *chan;
 
@@ -1191,8 +1303,11 @@
 	BUG_ON(chan_idx >= sband->n_channels);
 	chan = &sband->channels[chan_idx];
 
-	r = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq),
-		&max_bandwidth, &reg_rule, regd);
+	r = freq_reg_info_regd(wiphy,
+			       MHZ_TO_KHZ(chan->center_freq),
+			       desired_bw_khz,
+			       &reg_rule,
+			       regd);
 
 	if (r) {
 		chan->flags = IEEE80211_CHAN_DISABLED;
@@ -1200,10 +1315,14 @@
 	}
 
 	power_rule = &reg_rule->power_rule;
+	freq_range = &reg_rule->freq_range;
 
-	chan->flags |= map_regdom_flags(reg_rule->flags);
+	if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40))
+		bw_flags = IEEE80211_CHAN_NO_HT40;
+
+	chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags;
 	chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain);
-	chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth);
+	chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz);
 	chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp);
 }
 
@@ -1225,13 +1344,22 @@
 				   const struct ieee80211_regdomain *regd)
 {
 	enum ieee80211_band band;
+	unsigned int bands_set = 0;
 
 	mutex_lock(&cfg80211_mutex);
 	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
-		if (wiphy->bands[band])
-			handle_band_custom(wiphy, band, regd);
+		if (!wiphy->bands[band])
+			continue;
+		handle_band_custom(wiphy, band, regd);
+		bands_set++;
 	}
 	mutex_unlock(&cfg80211_mutex);
+
+	/*
+	 * no point in calling this if it won't have any effect
+	 * on your device's supportd bands.
+	 */
+	WARN_ON(!bands_set);
 }
 EXPORT_SYMBOL(wiphy_apply_custom_regulatory);
 
@@ -1552,6 +1680,13 @@
 
 	queue_regulatory_request(request);
 
+	/*
+	 * This ensures last_request is populated once modules
+	 * come swinging in and calling regulatory hints and
+	 * wiphy_apply_custom_regulatory().
+	 */
+	flush_scheduled_work();
+
 	return 0;
 }
 
diff --git a/net/wireless/util.c b/net/wireless/util.c
index beb226e..d072bff 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -4,7 +4,9 @@
  * Copyright 2007-2009	Johannes Berg <johannes@sipsolutions.net>
  */
 #include <linux/bitops.h>
+#include <linux/etherdevice.h>
 #include <net/cfg80211.h>
+#include <net/ip.h>
 #include "core.h"
 
 struct ieee80211_rate *
@@ -181,5 +183,323 @@
 		return -EINVAL;
 	}
 
+	if (params->seq) {
+		switch (params->cipher) {
+		case WLAN_CIPHER_SUITE_WEP40:
+		case WLAN_CIPHER_SUITE_WEP104:
+			/* These ciphers do not use key sequence */
+			return -EINVAL;
+		case WLAN_CIPHER_SUITE_TKIP:
+		case WLAN_CIPHER_SUITE_CCMP:
+		case WLAN_CIPHER_SUITE_AES_CMAC:
+			if (params->seq_len != 6)
+				return -EINVAL;
+			break;
+		}
+	}
+
 	return 0;
 }
+
+/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
+/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
+const unsigned char rfc1042_header[] __aligned(2) =
+	{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+EXPORT_SYMBOL(rfc1042_header);
+
+/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
+const unsigned char bridge_tunnel_header[] __aligned(2) =
+	{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
+EXPORT_SYMBOL(bridge_tunnel_header);
+
+unsigned int ieee80211_hdrlen(__le16 fc)
+{
+	unsigned int hdrlen = 24;
+
+	if (ieee80211_is_data(fc)) {
+		if (ieee80211_has_a4(fc))
+			hdrlen = 30;
+		if (ieee80211_is_data_qos(fc))
+			hdrlen += IEEE80211_QOS_CTL_LEN;
+		goto out;
+	}
+
+	if (ieee80211_is_ctl(fc)) {
+		/*
+		 * ACK and CTS are 10 bytes, all others 16. To see how
+		 * to get this condition consider
+		 *   subtype mask:   0b0000000011110000 (0x00F0)
+		 *   ACK subtype:    0b0000000011010000 (0x00D0)
+		 *   CTS subtype:    0b0000000011000000 (0x00C0)
+		 *   bits that matter:         ^^^      (0x00E0)
+		 *   value of those: 0b0000000011000000 (0x00C0)
+		 */
+		if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0))
+			hdrlen = 10;
+		else
+			hdrlen = 16;
+	}
+out:
+	return hdrlen;
+}
+EXPORT_SYMBOL(ieee80211_hdrlen);
+
+unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
+{
+	const struct ieee80211_hdr *hdr =
+			(const struct ieee80211_hdr *)skb->data;
+	unsigned int hdrlen;
+
+	if (unlikely(skb->len < 10))
+		return 0;
+	hdrlen = ieee80211_hdrlen(hdr->frame_control);
+	if (unlikely(hdrlen > skb->len))
+		return 0;
+	return hdrlen;
+}
+EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
+
+int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
+{
+	int ae = meshhdr->flags & MESH_FLAGS_AE;
+	/* 7.1.3.5a.2 */
+	switch (ae) {
+	case 0:
+		return 6;
+	case 1:
+		return 12;
+	case 2:
+		return 18;
+	case 3:
+		return 24;
+	default:
+		return 6;
+	}
+}
+
+int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
+			   enum nl80211_iftype iftype)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	u16 hdrlen, ethertype;
+	u8 *payload;
+	u8 dst[ETH_ALEN];
+	u8 src[ETH_ALEN] __aligned(2);
+
+	if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
+		return -1;
+
+	hdrlen = ieee80211_hdrlen(hdr->frame_control);
+
+	/* convert IEEE 802.11 header + possible LLC headers into Ethernet
+	 * header
+	 * IEEE 802.11 address fields:
+	 * ToDS FromDS Addr1 Addr2 Addr3 Addr4
+	 *   0     0   DA    SA    BSSID n/a
+	 *   0     1   DA    BSSID SA    n/a
+	 *   1     0   BSSID SA    DA    n/a
+	 *   1     1   RA    TA    DA    SA
+	 */
+	memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN);
+	memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN);
+
+	switch (hdr->frame_control &
+		cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
+	case cpu_to_le16(IEEE80211_FCTL_TODS):
+		if (unlikely(iftype != NL80211_IFTYPE_AP &&
+			     iftype != NL80211_IFTYPE_AP_VLAN))
+			return -1;
+		break;
+	case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
+		if (unlikely(iftype != NL80211_IFTYPE_WDS &&
+			     iftype != NL80211_IFTYPE_MESH_POINT))
+			return -1;
+		if (iftype == NL80211_IFTYPE_MESH_POINT) {
+			struct ieee80211s_hdr *meshdr =
+				(struct ieee80211s_hdr *) (skb->data + hdrlen);
+			hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
+			if (meshdr->flags & MESH_FLAGS_AE_A5_A6) {
+				memcpy(dst, meshdr->eaddr1, ETH_ALEN);
+				memcpy(src, meshdr->eaddr2, ETH_ALEN);
+			}
+		}
+		break;
+	case cpu_to_le16(IEEE80211_FCTL_FROMDS):
+		if (iftype != NL80211_IFTYPE_STATION ||
+		    (is_multicast_ether_addr(dst) &&
+		     !compare_ether_addr(src, addr)))
+			return -1;
+		break;
+	case cpu_to_le16(0):
+		if (iftype != NL80211_IFTYPE_ADHOC)
+			return -1;
+		break;
+	}
+
+	if (unlikely(skb->len - hdrlen < 8))
+		return -1;
+
+	payload = skb->data + hdrlen;
+	ethertype = (payload[6] << 8) | payload[7];
+
+	if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
+		    ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
+		   compare_ether_addr(payload, bridge_tunnel_header) == 0)) {
+		/* remove RFC1042 or Bridge-Tunnel encapsulation and
+		 * replace EtherType */
+		skb_pull(skb, hdrlen + 6);
+		memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
+		memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
+	} else {
+		struct ethhdr *ehdr;
+		__be16 len;
+
+		skb_pull(skb, hdrlen);
+		len = htons(skb->len);
+		ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
+		memcpy(ehdr->h_dest, dst, ETH_ALEN);
+		memcpy(ehdr->h_source, src, ETH_ALEN);
+		ehdr->h_proto = len;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(ieee80211_data_to_8023);
+
+int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr,
+			     enum nl80211_iftype iftype, u8 *bssid, bool qos)
+{
+	struct ieee80211_hdr hdr;
+	u16 hdrlen, ethertype;
+	__le16 fc;
+	const u8 *encaps_data;
+	int encaps_len, skip_header_bytes;
+	int nh_pos, h_pos;
+	int head_need;
+
+	if (unlikely(skb->len < ETH_HLEN))
+		return -EINVAL;
+
+	nh_pos = skb_network_header(skb) - skb->data;
+	h_pos = skb_transport_header(skb) - skb->data;
+
+	/* convert Ethernet header to proper 802.11 header (based on
+	 * operation mode) */
+	ethertype = (skb->data[12] << 8) | skb->data[13];
+	fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
+
+	switch (iftype) {
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_AP_VLAN:
+		fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
+		/* DA BSSID SA */
+		memcpy(hdr.addr1, skb->data, ETH_ALEN);
+		memcpy(hdr.addr2, addr, ETH_ALEN);
+		memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
+		hdrlen = 24;
+		break;
+	case NL80211_IFTYPE_STATION:
+		fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
+		/* BSSID SA DA */
+		memcpy(hdr.addr1, bssid, ETH_ALEN);
+		memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
+		memcpy(hdr.addr3, skb->data, ETH_ALEN);
+		hdrlen = 24;
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		/* DA SA BSSID */
+		memcpy(hdr.addr1, skb->data, ETH_ALEN);
+		memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
+		memcpy(hdr.addr3, bssid, ETH_ALEN);
+		hdrlen = 24;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	if (qos) {
+		fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
+		hdrlen += 2;
+	}
+
+	hdr.frame_control = fc;
+	hdr.duration_id = 0;
+	hdr.seq_ctrl = 0;
+
+	skip_header_bytes = ETH_HLEN;
+	if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) {
+		encaps_data = bridge_tunnel_header;
+		encaps_len = sizeof(bridge_tunnel_header);
+		skip_header_bytes -= 2;
+	} else if (ethertype > 0x600) {
+		encaps_data = rfc1042_header;
+		encaps_len = sizeof(rfc1042_header);
+		skip_header_bytes -= 2;
+	} else {
+		encaps_data = NULL;
+		encaps_len = 0;
+	}
+
+	skb_pull(skb, skip_header_bytes);
+	nh_pos -= skip_header_bytes;
+	h_pos -= skip_header_bytes;
+
+	head_need = hdrlen + encaps_len - skb_headroom(skb);
+
+	if (head_need > 0 || skb_cloned(skb)) {
+		head_need = max(head_need, 0);
+		if (head_need)
+			skb_orphan(skb);
+
+		if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) {
+			printk(KERN_ERR "failed to reallocate Tx buffer\n");
+			return -ENOMEM;
+		}
+		skb->truesize += head_need;
+	}
+
+	if (encaps_data) {
+		memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
+		nh_pos += encaps_len;
+		h_pos += encaps_len;
+	}
+
+	memcpy(skb_push(skb, hdrlen), &hdr, hdrlen);
+
+	nh_pos += hdrlen;
+	h_pos += hdrlen;
+
+	/* Update skb pointers to various headers since this modified frame
+	 * is going to go through Linux networking code that may potentially
+	 * need things like pointer to IP header. */
+	skb_set_mac_header(skb, 0);
+	skb_set_network_header(skb, nh_pos);
+	skb_set_transport_header(skb, h_pos);
+
+	return 0;
+}
+EXPORT_SYMBOL(ieee80211_data_from_8023);
+
+/* Given a data frame determine the 802.1p/1d tag to use. */
+unsigned int cfg80211_classify8021d(struct sk_buff *skb)
+{
+	unsigned int dscp;
+
+	/* skb->priority values from 256->263 are magic values to
+	 * directly indicate a specific 802.1d priority.  This is used
+	 * to allow 802.1d priority to be passed directly in from VLAN
+	 * tags, etc.
+	 */
+	if (skb->priority >= 256 && skb->priority <= 263)
+		return skb->priority - 256;
+
+	switch (skb->protocol) {
+	case htons(ETH_P_IP):
+		dscp = ip_hdr(skb)->tos & 0xfc;
+		break;
+	default:
+		return 0;
+	}
+
+	return dscp >> 5;
+}
+EXPORT_SYMBOL(cfg80211_classify8021d);
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index f98090b..711e00a 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -504,6 +504,13 @@
 			else if (idx == wdev->wext.default_mgmt_key)
 				wdev->wext.default_mgmt_key = -1;
 		}
+		/*
+		 * Applications using wireless extensions expect to be
+		 * able to delete keys that don't exist, so allow that.
+		 */
+		if (err == -ENOENT)
+			return 0;
+
 		return err;
 	} else {
 		if (addr)
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index d3bbef7..252c201 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -636,8 +636,10 @@
 /*
  * Print info for /proc/net/wireless (print all entries)
  */
-static int wireless_seq_show(struct seq_file *seq, void *v)
+static int wireless_dev_seq_show(struct seq_file *seq, void *v)
 {
+	might_sleep();
+
 	if (v == SEQ_START_TOKEN)
 		seq_printf(seq, "Inter-| sta-|   Quality        |   Discarded "
 				"packets               | Missed | WE\n"
@@ -651,21 +653,41 @@
 
 static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos)
 {
+	struct net *net = seq_file_net(seq);
+	loff_t off;
+	struct net_device *dev;
+
 	rtnl_lock();
-	return dev_seq_start(seq, pos);
+	if (!*pos)
+		return SEQ_START_TOKEN;
+
+	off = 1;
+	for_each_netdev(net, dev)
+		if (off++ == *pos)
+			return dev;
+	return NULL;
+}
+
+static void *wireless_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct net *net = seq_file_net(seq);
+
+	++*pos;
+
+	return v == SEQ_START_TOKEN ?
+		first_net_device(net) : next_net_device(v);
 }
 
 static void wireless_dev_seq_stop(struct seq_file *seq, void *v)
 {
-	dev_seq_stop(seq, v);
 	rtnl_unlock();
 }
 
 static const struct seq_operations wireless_seq_ops = {
 	.start = wireless_dev_seq_start,
-	.next  = dev_seq_next,
+	.next  = wireless_dev_seq_next,
 	.stop  = wireless_dev_seq_stop,
-	.show  = wireless_seq_show,
+	.show  = wireless_dev_seq_show,
 };
 
 static int seq_open_wireless(struct inode *inode, struct file *file)
@@ -798,6 +820,13 @@
 			err = -EFAULT;
 			goto out;
 		}
+
+		if (cmd == SIOCSIWENCODEEXT) {
+			struct iw_encode_ext *ee = (void *) extra;
+
+			if (iwp->length < sizeof(*ee) + ee->key_len)
+				return -EFAULT;
+		}
 	}
 
 	err = handler(dev, info, (union iwreq_data *) iwp, extra);